UNPKG

ln-service

Version:

Interaction helper for your Lightning Network daemon

226 lines (175 loc) 6.87 kB
const {deepEqual} = require('node:assert').strict; const {equal} = require('node:assert').strict; const {once} = require('node:events'); const {rejects} = require('node:assert').strict; const test = require('node:test'); const {setupChannel} = require('ln-docker-daemons'); const {spawnLightningCluster} = require('ln-docker-daemons'); const {addPeer} = require('./../../'); const {createInvoice} = require('./../../'); const {deleteForwardingReputations} = require('./../../'); const {getHeight} = require('./../../'); const {getInvoice} = require('./../../'); const {getPayment} = require('./../../'); const {payViaPaymentRequest} = require('./../../'); const {subscribeToForwardRequests} = require('./../../'); const {subscribeToPayViaRequest} = require('./../../'); const waitForRoute = require('./../macros/wait_for_route'); const size = 3; const tokens = 100; // Subscribing to forward requests should intercept forwards test(`Subscribe to requests`, async () => { const {kill, nodes} = await spawnLightningCluster({size}); const [{generate, lnd}, target, remote] = nodes; const channel = await setupChannel({generate, lnd, to: target}); await remote.generate({count: 100}); const remoteChan = await setupChannel({ lnd: target.lnd, generate: target.generate, to: remote, }); await addPeer({lnd, public_key: remote.id, socket: remote.socket}); const {routes} = await waitForRoute({lnd, tokens, destination: remote.id}); let height; const [route] = routes; { const invoice = await createInvoice({tokens, lnd: remote.lnd}); const sub = subscribeToForwardRequests({lnd: target.lnd}); sub.on('forward_request', async forward => await forward.reject()); await rejects( payViaPaymentRequest({lnd, request: invoice.request}), [503, 'PaymentPathfindingFailedToFindPossibleRoute'], 'Forward is rejected interactively' ); sub.removeAllListeners(); await deleteForwardingReputations({lnd}); const sub2 = subscribeToForwardRequests({lnd: target.lnd}); sub2.on('forward_request', forward => forward.reject()); const failures = []; const paying = []; const pay = subscribeToPayViaRequest({lnd, request: invoice.request}); height = (await getHeight({lnd})).current_block_height; pay.on('paying', pending => paying.push(pending)); pay.on('routing_failure', failure => failures.push(failure)); await once(pay, 'failed'); equal(failures.length, 1, 'Got a failure'); const [failed] = failures; delete failed.channel; deepEqual( failed, { index: 1, mtokens: '101000', public_key: target.id, reason: 'TemporaryChannelFailure', route: { fee: 1, fee_mtokens: '1000', hops: [ { channel: channel.id, fee: 1, fee_mtokens: '1000', forward: 100, forward_mtokens: '100000', public_key: target.id, timeout: height + 43, }, { channel: remoteChan.id, fee: 0, fee_mtokens: '0', forward: 100, forward_mtokens: '100000', public_key: remote.id, timeout: height + 43, }, ], mtokens: '101000', payment: invoice.payment, timeout: height + 40 + 43, tokens: 101, total_mtokens: '100000', }, }, 'Failure is emitted' ); sub2.removeAllListeners(); } await deleteForwardingReputations({lnd}); { const invoice = await createInvoice({tokens, lnd: remote.lnd}); const sub = subscribeToForwardRequests({lnd: target.lnd}); sub.once('forward_request', async forward => { const {pending} = await getPayment({lnd, id: invoice.id}); equal(pending.destination, remote.id, 'Pending remote'); equal(!!pending.created_at, true, 'Has creation date'); equal(pending.id, invoice.id, 'Payment id is present'); equal(pending.mtokens, invoice.mtokens, 'Pending payment mtokens'); equal(pending.paths.length, 1, 'Path is present'); const [path] = pending.paths; deepEqual( path, { fee: 1, fee_mtokens: '1000', hops: [ { channel: forward.in_channel, fee: 1, fee_mtokens: '1000', forward: 100, forward_mtokens: '100000', public_key: target.id, timeout: height + 43, }, { channel: forward.out_channel, fee: 0, fee_mtokens: '0', forward: 100, forward_mtokens: '100000', public_key: remote.id, timeout: height + 43, }, ], mtokens: '101000', payment: invoice.payment, timeout: height + 40 + 43, tokens: 101, total_mtokens: '100000', }, 'Paths are present' ); equal(pending.request, invoice.request, 'Pending pay of request'); equal(pending.timeout, height + 40 + 43, 'Pending timeout'); equal(pending.tokens, invoice.tokens, 'Pending pay of invoice tokens'); const info = await getHeight({lnd: target.lnd}); equal(forward.cltv_delta, 40, 'Forward has CLTV delta'); equal(forward.fee, 1, 'Forward has a routing fee'); equal(forward.fee_mtokens, '1000', 'Forward has precise routing fee'); equal(forward.hash, invoice.id, 'Forward has payment hash'); equal(forward.in_channel, channel.id, 'Forward has inbound channel') equal(forward.in_payment, 2, 'Forward has payment index'); equal(forward.messages.length, [].length, 'Forward has no messages'); equal(forward.mtokens, invoice.mtokens, 'Forward has tokens out'); equal(forward.out_channel, remoteChan.id, 'Forward has outbound chan'); equal(forward.timeout, info.current_block_height + 83, 'Has timeout'); equal(forward.tokens, invoice.tokens, 'Forward has invoiced tokens'); return await forward.accept(); }); await payViaPaymentRequest({lnd, request: invoice.request}); } { const invoice = await createInvoice({tokens, lnd: remote.lnd}); const {secret} = invoice; const sub = subscribeToForwardRequests({lnd: target.lnd}); sub.on('forward_request', async ({settle}) => await settle({secret})); const paid = await payViaPaymentRequest({lnd, request: invoice.request}); equal(paid.secret, invoice.secret, 'The sender gets the preimage'); const inv = await getInvoice({id: invoice.id, lnd: remote.lnd}); equal(inv.is_confirmed, false, 'Receiver does not get the payment'); } await kill({}); return; });