UNPKG

paid-services

Version:
244 lines (193 loc) 6.76 kB
const {addPeer} = require('ln-service'); const {address} = require('bitcoinjs-lib'); const asyncAuto = require('async/auto'); const asyncMap = require('async/map'); const asyncRetry = require('async/retry'); const {broadcastChainTransaction} = require('ln-service'); const {closeChannel} = require('ln-service'); const {createChainAddress} = require('ln-service'); const {getChainTransactions} = require('ln-service'); const {getChannel} = require('ln-service'); const {getChannels} = require('ln-service'); const {getNetwork} = require('ln-sync'); const {networks} = require('bitcoinjs-lib'); const {openChannel} = require('ln-service'); const {spawnLightningCluster} = require('ln-docker-daemons'); const {test} = require('@alexbosworth/tap'); const {Transaction} = require('bitcoinjs-lib'); const {changeChannelCapacity} = require('./../../capacity'); const {getCapacityChangeRequests} = require('./../../capacity'); const bufferAsHex = buffer => buffer.toString('hex'); const capacity = 1e6; const {fromHex} = Transaction; const id = Buffer.alloc(32).toString('hex'); const interval = 10; const logger = {error: () => {}, info: () => {}}; const maturity = 100; const size = 3; const slow = 3000; const splitCapacity = 200000; const sumOf = arr => arr.reduce((sum, n) => sum + n, 0); const times = 2000; const {toOutputScript} = address; const weightAsVBytes = n => Math.ceil(n / 4); // A capacity replacement proposal should be counter signed and accepted test(`Decrease capacity replacement`, async ({end, equal, strictSame}) => { const {kill, nodes} = await spawnLightningCluster({size}); const [control, target, remote] = nodes; const {generate, lnd} = control; const network = networks[(await getNetwork({lnd})).bitcoinjs]; // Make some funds await generate({count: maturity}); // Add remote as a peer await addPeer({lnd, public_key: remote.id, socket: remote.socket}); try { // Open up a new channel const channelOpen = await asyncRetry({interval, times}, async () => { return await openChannel({ lnd, local_tokens: capacity, partner_public_key: target.id, partner_socket: target.socket, }); }); // Wait for the channel to be active const channel = await asyncRetry({interval, times}, async () => { const [channel] = (await getChannels({lnd, is_active: true})).channels; if (!channel) { await generate({}); throw new Error('ExpectedChannelActivation'); } const {policies} = await getChannel({lnd, id: channel.id}); const noPolicy = policies.find(n => !n.cltv_delta); if (!!channel && !noPolicy) { return channel; } await generate({}); throw new Error('ExpectedChannelActivation'); }); await asyncAuto({ // Propose the channel propose: async () => { await changeChannelCapacity({ lnd, logger, ask: (args, cbk) => { if (args.name === 'add') { return cbk({add: false}); } if (args.name === 'amount') { return cbk({amount: splitCapacity}); } if (args.name === 'decrease') { return cbk({decrease: 'open_channel'}); } if (args.name === 'direction') { return cbk({direction: 'decrease'}); } if (args.name === 'internal') { return cbk({internal: true}); } if (args.name === 'key') { return cbk({key: remote.id}); } if (args.name === 'ok') { return cbk({ok: true}); } if (args.name === 'proceed') { return cbk({proceed: true}); } if (args.name === 'rate') { return cbk({rate: args.default}); } if (args.name === 'spend') { return cbk({spend: false}); } if (args.name === 'query') { return cbk({query: target.id}); } if (args.name === 'type') { return cbk({type: 'Private'}); } throw new Error('UnexpectedQueryNameForProposingSide'); }, nodes: [], }); }, // Wait to see the inbound proposal waitForProposal: async () => { await asyncRetry({interval, times}, async () => { const {requests} = await getCapacityChangeRequests({ lnd: target.lnd, }); if (!requests.length) { throw new Error('FailedToFindChangeRequest'); } }); }, // Accept the channel accept: ['waitForProposal', async ({}) => { await changeChannelCapacity({ logger, ask: (args, cbk) => { if (args.name === 'accept') { return cbk({accept: true}); } if (args.name === 'ok') { return cbk({ok: true}); } throw new Error('UnexpectedQueryNameForAcceptingSide'); }, lnd: target.lnd, nodes: [], }); }], // Generate to confirm the change generate: ['waitForProposal', async ({}) => { // Wait for the new channel to be active const recreated = await asyncRetry({ times, interval: slow, }, async () => { const {channels} = await getChannels({lnd, is_active: true}); const [channel] = channels .filter(n => n.is_private) .filter(n => n.capacity < capacity); await generate({}); if (!channel) { throw new Error('ExpectedChannelActivation'); } const channelWithRemote = channels.find(channel => { return channel.partner_public_key === remote.id; }); equal(channelWithRemote.capacity, splitCapacity, 'Remote created'); { const {policies} = await getChannel({lnd, id: channel.id}); const noPolicy = policies.find(n => !n.cltv_delta); if (!!noPolicy) { throw new Error('ExpectedChannelPolicy'); } }; { const {policies} = await getChannel({ id: channel.id, lnd: target.lnd, }); const noPolicy = policies.find(n => !n.cltv_delta); if (!!noPolicy) { throw new Error('ExpectedChannelPolicy'); } }; return; }); return; }], }); } catch (err) { strictSame(err, null, 'Expected no failure'); } finally { await kill({}); } return end(); });