UNPKG

ln-service

Version:

Interaction helper for your Lightning Network daemon

154 lines (124 loc) 4.4 kB
const {deepStrictEqual} = require('node:assert').strict; const {strictEqual} = require('node:assert').strict; const test = require('node:test'); const asyncRetry = require('async/retry'); const {setupChannel} = require('ln-docker-daemons'); const {spawnLightningCluster} = require('ln-docker-daemons'); const {cancelHodlInvoice} = require('./../../'); const {createInvoice} = require('./../../'); const {decodePaymentRequest} = require('./../../'); const {getInvoice} = require('./../../'); const {getRouteToDestination} = require('./../../'); const {parsePaymentRequest} = require('./../../'); const {payViaRoutes} = require('./../../'); const all = promise => Promise.all(promise); const interval = 10; const {isArray} = Array; const message = {type: '85805', value: '01'}; const size = 3; const times = 3000; const tokens = 1000; // Getting a route to a destination should return a route to the destination test(`Get a route to a destination`, async () => { await asyncRetry({}, async () => { const {kill, nodes} = await spawnLightningCluster({size}); const [control, target, remote] = nodes; await control.generate({count: 200}); await setupChannel({ generate: control.generate, lnd: control.lnd, to: target, }); await setupChannel({ generate: target.generate, give_tokens: 1e5, is_private: true, lnd: target.lnd, to: remote, }); const invoice = await asyncRetry({interval, times}, async () => { const invoice = await createInvoice({ tokens, is_including_private_channels: true, lnd: remote.lnd, }); const {routes} = parsePaymentRequest({request: invoice.request}); // Wait for private routes to get picked up if (!routes) { await cancelHodlInvoice({id: invoice.id, lnd: remote.lnd}); throw new Error('ExpectedRouteForInvoice'); } return invoice; }); const parsed = parsePaymentRequest({request: invoice.request}); await asyncRetry({interval, times}, async () => { const {route} = await getRouteToDestination({ destination: parsed.destination, features: parsed.features, lnd: control.lnd, payment: parsed.payment, routes: parsed.routes, mtokens: parsed.mtokens, total_mtokens: parsed.mtokens, }); const paid = await payViaRoutes({ id: parsed.id, lnd: control.lnd, routes: [route], }); strictEqual(invoice.secret, paid.secret, 'Paid multi-hop private route'); }); const inv = await createInvoice({tokens, lnd: target.lnd}); const invDetails = await decodePaymentRequest({ lnd: control.lnd, request: inv.request, }); const controlToTarget = await getRouteToDestination({ destination: target.id, features: invDetails.features, lnd: control.lnd, messages: [message], payment: invDetails.payment, tokens: invDetails.tokens / [control, remote].length, total_mtokens: invDetails.mtokens, }); const remoteToTarget = await getRouteToDestination({ destination: target.id, features: invDetails.features, lnd: remote.lnd, messages: [message], payment: invDetails.payment, tokens: invDetails.tokens / [control, remote].length, total_mtokens: invDetails.mtokens, }); try { const [controlPay, remotePay] = await all([ payViaRoutes({ id: invDetails.id, lnd: control.lnd, routes: [controlToTarget.route], }), payViaRoutes({ id: invDetails.id, lnd: remote.lnd, routes: [remoteToTarget.route], }), ]); strictEqual(controlPay.secret, inv.secret, 'Control paid for secret'); strictEqual(remotePay.secret, inv.secret, 'Remote paid for secret'); const {payments} = await getInvoice({ id: invDetails.id, lnd: target.lnd, }); const [payment1, payment2] = payments; const [message1] = payment1.messages; const [message2] = payment2.messages; deepStrictEqual(message1, message, 'Target received message'); deepStrictEqual(message2, message, 'Target received both messages'); } catch (err) { strictEqual(err, null, 'Unexpected error paying invoice'); } await kill({}); }); return; });