ln-service
Version:
Interaction helper for your Lightning Network daemon
177 lines (130 loc) • 5.25 kB
JavaScript
const {deepEqual} = require('node:assert').strict;
const {equal} = require('node:assert').strict;
const {exit} = require('node:process');
const test = require('node:test');
const asyncRetry = require('async/retry');
const {setupChannel} = require('ln-docker-daemons');
const {spawnLightningCluster} = require('ln-docker-daemons');
const {addPeer} = require('./../../');
const {closeChannel} = require('./../../');
const {getChannel} = require('./../../');
const {subscribeToGraph} = require('./../../');
const capacity = 1e6;
const delay = ms => new Promise(resolve => setTimeout(resolve, ms));
const increaseDelay = n => n * 1000;
const interval = 10;
const size = 2;
const times = 1000;
// Subscribing to graph should trigger graph events
test('Subscribe to channels', async t => {
const attempts = [];
t.after(() => exit());
await asyncRetry({interval, times}, async () => {
const {kill, nodes} = await spawnLightningCluster({size});
const [control, target] = nodes;
const {generate, lnd} = control;
const channelClosed = [];
const channelUpdated = [];
const nodeUpdated = [];
const {socket} = target;
attempts.push(socket);
await delay(increaseDelay(attempts.length));
const sub = subscribeToGraph({lnd});
sub.on('channel_closed', update => channelClosed.push(update));
sub.on('channel_updated', update => channelUpdated.push(update));
sub.on('node_updated', update => nodeUpdated.push(update));
sub.on('err', err => {});
try {
const channel = await setupChannel({
capacity,
generate,
lnd,
to: target,
});
const {id} = channel;
const channelPolicies = await getChannel({id, lnd});
await asyncRetry({interval, times}, async () => {
await addPeer({lnd, public_key: target.id, socket: target.socket});
if (!channelUpdated.length) {
throw new Error('ExpectedChannelUpdated');
}
if (nodeUpdated.length !== [control, target].length) {
throw new Error('ExpectedNodesUpdated');
}
return;
});
await closeChannel({id, lnd})
await asyncRetry({interval, times}, async () => {
await generate({});
if (!channelClosed.length) {
throw new Error('ExpectedChannelClosed');
}
return;
});
const [channelClose] = channelClosed;
equal(channelClose.capacity, capacity, 'Got closed channel capacity');
equal(!!channelClose.close_height, true, 'Got closed channel height');
equal(channelClose.id, id, 'Got closed channel id');
equal(channelClose.transaction_id, channel.transaction_id, 'Got close');
equal(channelClose.transaction_vout, channel.transaction_vout, 'Vout');
equal(!!channelClose.updated_at, true, 'Got close updated at');
const expectedUpdates = channelPolicies.policies.map(policy => {
const peer = channelPolicies.policies
.find(n => n.public_key !== policy.public_key);
return {
capacity,
id,
base_fee_mtokens: policy.base_fee_mtokens,
cltv_delta: policy.cltv_delta,
fee_rate: policy.fee_rate,
is_disabled: policy.is_disabled,
inbound_base_discount_mtokens: policy.inbound_base_discount_mtokens,
inbound_rate_discount: policy.inbound_rate_discount,
max_htlc_mtokens: policy.max_htlc_mtokens,
min_htlc_mtokens: policy.min_htlc_mtokens,
public_keys: [policy.public_key, peer.public_key],
transaction_id: channel.transaction_id,
transaction_vout: channel.transaction_vout,
};
});
expectedUpdates.forEach(update => {
const [key1, key2] = update.public_keys;
const gotUpdate = channelUpdated.find(chan => {
const [k1, k2] = chan.public_keys;
return key1 === k1 && key2 === k2;
});
equal(!!gotUpdate.updated_at, true, 'Got updated at policy date');
delete gotUpdate.updated_at;
deepEqual(gotUpdate, update, 'Got expected channel announcement');
return;
});
const gotControl = nodeUpdated.find(n => n.public_key === control.id);
const expectedControl = {
alias: control.id.substring(0, 20),
color: '#3399ff',
public_key: control.id,
sockets: gotControl.sockets,
};
const gotTarget = nodeUpdated.find(n => n.public_key === target.id);
const expectedTarget = {
alias: target.id.substring(0, 20),
color: '#3399ff',
public_key: target.id,
sockets: gotTarget.sockets,
};
equal(!!gotControl.features, true, 'Got control features');
equal(!!gotControl.updated_at, true, 'Got control updated at');
delete gotControl.features;
delete gotControl.updated_at;
delete gotTarget.features;
delete gotTarget.updated_at;
equal(!!gotTarget, true, 'Got target updated at');
deepEqual(gotControl, expectedControl, 'Got control node announcement');
deepEqual(gotTarget, expectedTarget, 'Got target node announcement');
await kill({});
} catch (err) {
await kill({});
throw err;
}
});
});