ln-service 53.5.0 → 53.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -24,62 +24,66 @@ test(`Get node`, async ({end, equal, strictSame}) => {
24
24
 
25
25
  const [{generate, id, lnd}, target, remote] = nodes;
26
26
 
27
- const controlToTarget = await setupChannel({generate, lnd, to: target});
27
+ try {
28
+ const controlToTarget = await setupChannel({generate, lnd, to: target});
28
29
 
29
- const targetToRemote = await setupChannel({
30
- generate: target.generate,
31
- lnd: target.lnd,
32
- to: remote,
33
- });
30
+ const targetToRemote = await setupChannel({
31
+ generate: target.generate,
32
+ lnd: target.lnd,
33
+ to: remote,
34
+ });
34
35
 
35
- await updateRoutingFees({
36
- lnd,
37
- base_fee_tokens: baseFee,
38
- cltv_delta: cltvDelta,
39
- fee_rate: feeRate,
40
- transaction_id: controlToTarget.transaction_id,
41
- transaction_vout: controlToTarget.transaction_vout,
42
- });
36
+ await updateRoutingFees({
37
+ lnd,
38
+ base_fee_tokens: baseFee,
39
+ cltv_delta: cltvDelta,
40
+ fee_rate: feeRate,
41
+ transaction_id: controlToTarget.transaction_id,
42
+ transaction_vout: controlToTarget.transaction_vout,
43
+ });
43
44
 
44
- await addPeer({lnd, public_key: remote.id, socket: remote.socket});
45
+ await addPeer({lnd, public_key: remote.id, socket: remote.socket});
45
46
 
46
- await delay(3000);
47
+ await delay(3000);
47
48
 
48
- const node = await getNode({lnd, public_key: id});
49
+ const node = await getNode({lnd, public_key: id});
49
50
 
50
- {
51
- const {channels} = await getNode({
52
- lnd,
53
- is_omitting_channels: true,
54
- public_key: id,
55
- });
51
+ {
52
+ const {channels} = await getNode({
53
+ lnd,
54
+ is_omitting_channels: true,
55
+ public_key: id,
56
+ });
56
57
 
57
- equal(channels.length, [].length, 'Channels are omitted')
58
- }
59
-
60
- if (!!node.channels.length) {
61
- const [{policies}] = node.channels;
58
+ equal(channels.length, [].length, 'Channels are omitted')
59
+ }
62
60
 
63
- const policy = policies.find(n => n.public_key === id);
61
+ if (!!node.channels.length) {
62
+ const [{policies}] = node.channels;
64
63
 
65
- equal(BigInt(policy.base_fee_mtokens), BigInt(baseFee)*mtokPerTok, 'Base');
66
- equal(policy.cltv_delta, cltvDelta, 'Got expected cltv delta');
67
- equal(policy.fee_rate, feeRate, 'Got expected fee rate');
68
- equal(policy.is_disabled, false, 'Channel is not disabled');
69
- equal(policy.max_htlc_mtokens, '990000000', 'Max HTLC mtokens returned');
70
- equal(policy.min_htlc_mtokens, '1000', 'Min HTLC mtokens returned');
71
- }
64
+ const policy = policies.find(n => n.public_key === id);
72
65
 
73
- const [socket] = node.sockets;
66
+ equal(BigInt(policy.base_fee_mtokens), BigInt(baseFee)*mtokPerTok, 'bf');
67
+ equal(policy.cltv_delta, cltvDelta, 'Got expected cltv delta');
68
+ equal(policy.fee_rate, feeRate, 'Got expected fee rate');
69
+ equal(policy.is_disabled, false, 'Channel is not disabled');
70
+ equal(policy.max_htlc_mtokens, '990000000', 'Max HTLC mtokens returned');
71
+ equal(policy.min_htlc_mtokens, '1000', 'Min HTLC mtokens returned');
72
+ }
74
73
 
75
- equal(node.alias, id.slice(0, defaultAliasLength), 'Alias');
76
- equal(node.color, '#3399ff', 'Color');
77
- equal(node.sockets.length, 1, 'Socket');
78
- equal(!!socket.socket, true, 'Ip, port');
79
- equal(socket.type, 'tcp', 'Socket type');
80
- equal(node.updated_at.length, 24, 'Update date');
74
+ const [socket] = node.sockets;
81
75
 
82
- await kill({});
76
+ equal(node.alias, id.slice(0, defaultAliasLength), 'Alias');
77
+ equal(node.color, '#3399ff', 'Color');
78
+ equal(node.sockets.length, 1, 'Socket');
79
+ equal(!!socket.socket, true, 'Ip, port');
80
+ equal(socket.type, 'tcp', 'Socket type');
81
+ equal(node.updated_at.length, 24, 'Update date');
82
+ } catch (err) {
83
+ strictSame(err, null, 'Expected no error');
84
+ } finally {
85
+ await kill({});
86
+ }
83
87
 
84
88
  return end();
85
89
  });
@@ -177,7 +177,14 @@ test(`Get pending channels`, async ({end, equal}) => {
177
177
  equal(forceClose.partner_public_key, target.id, 'pk');
178
178
  equal(forceClose.received, 0, 'No receive amount');
179
179
  equal(forceClose.recovered_tokens, undefined, 'No recovered amount');
180
- equal(forceClose.remote_balance, 0, 'No remote balance');
180
+
181
+ // LND 0.14.1 and below do not support remote balance info
182
+ if (!!forceClose.remote_balance) {
183
+ equal(forceClose.remote_balance, giftTokens, 'Got gift remote balance');
184
+ } else {
185
+ equal(forceClose.remote_balance, 0, 'No remote balance');
186
+ }
187
+
181
188
  equal(forceClose.sent, 0, 'No sent amount');
182
189
  equal(!!forceClose.timelock_blocks, true, 'Timelock blocks set');
183
190
  equal(forceClose.timelock_expiration, startHeight + 265, 'Funds timelock');
@@ -1,11 +1,14 @@
1
+ const asyncRetry = require('async/retry');
1
2
  const {spawnLightningCluster} = require('ln-docker-daemons');
2
3
  const {test} = require('@alexbosworth/tap');
3
4
 
4
5
  const {getWalletInfo} = require('./../../');
5
6
 
6
7
  const initHeight = 1;
8
+ const interval = 10;
7
9
  const pubKeyHexLength = Buffer.alloc(33).toString('hex').length;
8
10
  const regtestChainId = '06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f';
11
+ const times = 1000;
9
12
  const walletInfoType = 'wallet';
10
13
 
11
14
  // Getting the wallet info should return info about the wallet
@@ -16,6 +19,14 @@ test(`Get wallet info`, async ({end, equal, strictSame}) => {
16
19
 
17
20
  const result = await getWalletInfo({lnd});
18
21
 
22
+ await asyncRetry({interval, times}, async () => {
23
+ if (result.current_block_height === initHeight) {
24
+ return;
25
+ }
26
+
27
+ throw new Error('ExpectedBlockHeightAtInitHeight');
28
+ });
29
+
19
30
  equal(result.active_channels_count, 0, 'Expected channels count');
20
31
  equal(!!result.alias, true, 'Expected alias');
21
32
  strictSame(result.chains, [regtestChainId], 'Got chains');
@@ -16,7 +16,7 @@ const defaultFee = 1e3;
16
16
  const giveTokens = 1e5;
17
17
  const interval = 100;
18
18
  const size = 2;
19
- const times = 20;
19
+ const times = 200;
20
20
 
21
21
  // Subscribing to channels should trigger channel events
22
22
  test('Subscribe to channels', async ({end, equal, fail}) => {
@@ -16,98 +16,104 @@ test(`Subscribe to peer messages`, async ({end, equal, strictSame}) => {
16
16
 
17
17
  const [{lnd}, target, remote] = nodes;
18
18
 
19
- await addPeer({
20
- lnd,
21
- public_key: target.id,
22
- socket: target.socket,
23
- });
24
-
25
- await addPeer({
26
- lnd: target.lnd,
27
- public_key: remote.id,
28
- socket: remote.socket,
29
- });
30
-
31
19
  try {
32
- await sendMessageToPeer({
20
+ await addPeer({
33
21
  lnd,
34
- message: Buffer.from('message').toString('hex'),
35
22
  public_key: target.id,
23
+ socket: target.socket,
24
+ });
25
+
26
+ await addPeer({
27
+ lnd: target.lnd,
28
+ public_key: remote.id,
29
+ socket: remote.socket,
36
30
  });
37
- } catch (err) {
38
- const [code] = err;
39
31
 
40
- // Send message to peer is not supported on LND 0.13.4 or lower
41
- if (code === 501) {
42
- await kill({});
32
+ try {
33
+ await sendMessageToPeer({
34
+ lnd,
35
+ message: Buffer.from('message').toString('hex'),
36
+ public_key: target.id,
37
+ });
38
+ } catch (err) {
39
+ const [code] = err;
43
40
 
44
- return end();
41
+ // Send message to peer is not supported on LND 0.13.4 or lower
42
+ if (code === 501) {
43
+ await kill({});
44
+
45
+ return end();
46
+ }
45
47
  }
46
- }
47
48
 
48
- const messages = [];
49
- const targetSub = subscribeToPeerMessages({lnd: target.lnd});
50
- const remoteSub = subscribeToPeerMessages({lnd: remote.lnd});
51
- const targetMessages = [];
49
+ const messages = [];
50
+ const targetSub = subscribeToPeerMessages({lnd: target.lnd});
51
+ const remoteSub = subscribeToPeerMessages({lnd: remote.lnd});
52
+ const targetMessages = [];
52
53
 
53
- remoteSub.on('message_received', message => messages.push(message));
54
+ remoteSub.on('message_received', message => messages.push(message));
54
55
 
55
- targetSub.on('message_received', async ({message, type}) => {
56
- targetMessages.push(message);
56
+ targetSub.on('message_received', async ({message, type}) => {
57
+ targetMessages.push(message);
57
58
 
58
- if (type !== 40805) {
59
- return;
60
- }
59
+ if (type !== 40805) {
60
+ return;
61
+ }
62
+
63
+ // Wait for message to appear
64
+ return await asyncRetry({interval, times}, async () => {
65
+ // Relay message from control to remote
66
+ await sendMessageToPeer({
67
+ message,
68
+ type,
69
+ lnd: target.lnd,
70
+ public_key: remote.id,
71
+ });
72
+
73
+ if (!messages.length) {
74
+ throw new Error('ExpectedMessage');
75
+ }
76
+ });
77
+ });
61
78
 
62
79
  // Wait for message to appear
63
- return await asyncRetry({interval, times}, async () => {
64
- // Relay message from control to remote
80
+ await asyncRetry({interval, times}, async () => {
81
+ // Control send a message to target peer
65
82
  await sendMessageToPeer({
66
- message,
67
- type,
68
- lnd: target.lnd,
69
- public_key: remote.id,
83
+ lnd,
84
+ message: Buffer.from('message to remote').toString('hex'),
85
+ public_key: target.id,
86
+ type: 40805,
70
87
  });
71
88
 
72
- if (!messages.length) {
73
- throw new Error('ExpectedMessage');
89
+ if (!targetMessages.length) {
90
+ throw new Error('ExpectedTargetMessageReceived');
74
91
  }
75
92
  });
76
- });
77
93
 
78
- // Wait for message to appear
79
- await asyncRetry({interval, times}, async () => {
80
- // Control send a message to target peer
81
- await sendMessageToPeer({
82
- lnd,
83
- message: Buffer.from('message to remote').toString('hex'),
84
- public_key: target.id,
85
- type: 40805,
94
+ // Wait for message to appear
95
+ await asyncRetry({interval, times}, async () => {
96
+ if (!messages.length) {
97
+ throw new Error('ExpectedMessage');
98
+ }
86
99
  });
87
100
 
88
- if (!targetMessages.length) {
89
- throw new Error('ExpectedTargetMessageReceived');
90
- }
91
- });
92
-
93
- // Wait for message to appear
94
- await asyncRetry({interval, times}, async () => {
95
- if (!messages.length) {
96
- throw new Error('ExpectedMessage');
97
- }
98
- });
99
-
100
- strictSame(
101
- messages,
102
- [{
103
- message: Buffer.from('message to remote').toString('hex'),
104
- public_key: target.id,
105
- type: 40805,
106
- }],
107
- 'Message successfully relayed through target'
108
- );
109
-
110
- await kill({});
101
+ const [message] = messages;
102
+
103
+ strictSame(
104
+ message,
105
+ {
106
+ message: Buffer.from('message to remote').toString('hex'),
107
+ public_key: target.id,
108
+ type: 40805,
109
+ },
110
+ 'Message successfully relayed through target'
111
+ );
112
+ } catch (err) {
113
+ equal(err, null, 'Expected no error');
114
+ } finally {
115
+ await kill({});
116
+ }
111
117
 
112
118
  return end();
113
119
  });
@@ -26,66 +26,70 @@ test('Get forwarding reputations', async ({end, equal}) => {
26
26
 
27
27
  const [{generate, id, lnd}, target, remote] = cluster.nodes;
28
28
 
29
- await generate({count: 400});
30
-
31
- // Create a channel from the control to the target node
32
- await setupChannel({
33
- generate,
34
- lnd,
35
- capacity: channelCapacityTokens * 2,
36
- to: target,
37
- });
38
-
39
- const targetToRemoteChan = await setupChannel({
40
- generate: target.generate,
41
- give: Math.round(channelCapacityTokens / 2),
42
- lnd: target.lnd,
43
- to: remote,
44
- });
45
-
46
- await asyncRetry({interval, times}, async () => {
47
- await addPeer({lnd, public_key: remote.id, socket: remote.socket});
48
-
49
- const {channels} = await getChannels({lnd: remote.lnd});
50
-
51
- await waitForRoute({lnd, tokens, destination: remote.id});
52
-
53
- try {
54
- const res = await probeForRoute({
55
- lnd,
56
- tokens,
57
- destination: remote.id,
58
- is_ignoring_past_failures: true,
59
- });
60
- } catch (err) {
61
- equal(err, null, 'Expected no error probing');
62
- }
63
-
64
- const {nodes} = await getForwardingReputations({lnd});
65
-
66
- const [node] = nodes;
67
-
68
- if (!node) {
69
- throw new Error('ExpectedForwardingNode');
70
- }
71
-
72
- equal(!!node.public_key, true, 'Temp fail node added');
73
-
74
- const [peer] = node.peers;
75
-
76
- if (!peer) {
77
- throw new Error('ExpectedNodePeer');
78
- }
79
-
80
- if (!peer.last_failed_forward_at) {
81
- throw new Error('ExpectedLastFailTimeReturned');
82
- }
83
-
84
- equal(!!peer.last_failed_forward_at, true, 'Last fail time returned');
85
- equal(!!peer.to_public_key, true, 'Got peer pub key');
86
- });
87
-
88
- await cluster.kill({});
29
+ await generate({count: 100});
30
+
31
+ try {
32
+ // Create a channel from the control to the target node
33
+ await setupChannel({
34
+ generate,
35
+ lnd,
36
+ capacity: channelCapacityTokens * 2,
37
+ to: target,
38
+ });
39
+
40
+ const targetToRemoteChan = await setupChannel({
41
+ generate: target.generate,
42
+ give: Math.round(channelCapacityTokens / 2),
43
+ lnd: target.lnd,
44
+ to: remote,
45
+ });
46
+
47
+ await asyncRetry({interval, times}, async () => {
48
+ await addPeer({lnd, public_key: remote.id, socket: remote.socket});
49
+
50
+ const {channels} = await getChannels({lnd: remote.lnd});
51
+
52
+ await waitForRoute({lnd, tokens, destination: remote.id});
53
+
54
+ try {
55
+ const res = await probeForRoute({
56
+ lnd,
57
+ tokens,
58
+ destination: remote.id,
59
+ is_ignoring_past_failures: true,
60
+ });
61
+ } catch (err) {
62
+ equal(err, null, 'Expected no error probing');
63
+ }
64
+
65
+ const {nodes} = await getForwardingReputations({lnd});
66
+
67
+ const [node] = nodes;
68
+
69
+ if (!node) {
70
+ throw new Error('ExpectedForwardingNode');
71
+ }
72
+
73
+ equal(!!node.public_key, true, 'Temp fail node added');
74
+
75
+ const [peer] = node.peers;
76
+
77
+ if (!peer) {
78
+ throw new Error('ExpectedNodePeer');
79
+ }
80
+
81
+ if (!peer.last_failed_forward_at) {
82
+ throw new Error('ExpectedLastFailTimeReturned');
83
+ }
84
+
85
+ equal(!!peer.last_failed_forward_at, true, 'Last fail time returned');
86
+ equal(!!peer.to_public_key, true, 'Got peer pub key');
87
+ });
88
+ } catch (err) {
89
+ equal(err, null, 'Expected no error');
90
+ } finally {
91
+ await cluster.kill({});
92
+ }
89
93
 
90
94
  return end();
91
95
  });
@@ -17,41 +17,45 @@ test('Get route confidence', async ({end, equal}) => {
17
17
 
18
18
  const [{generate, lnd}, target, remote] = nodes;
19
19
 
20
- // Create a channel from the control to the target node
21
- await setupChannel({
22
- generate,
23
- lnd,
24
- capacity: channelCapacityTokens * 2,
25
- to: target,
26
- });
27
-
28
- // Create a too-small channel from target to remote
29
- await setupChannel({
30
- generate: target.generate,
31
- give: Math.round(channelCapacityTokens / 2),
32
- lnd: target.lnd,
33
- to: remote,
34
- });
35
-
36
- await addPeer({lnd, public_key: remote.id, socket: remote.socket});
37
-
38
- const destination = remote.id;
39
-
40
- // Allow time for graph sync to complete
41
- const {routes} = await waitForRoute({destination, lnd, tokens});
42
-
43
- // Run into a failure to inform future pathfinding
44
20
  try {
45
- await probeForRoute({destination, lnd, tokens});
46
- } catch (err) {}
47
-
48
- const [{hops}] = routes;
49
-
50
- const {confidence} = await getRouteConfidence({lnd, hops});
51
-
52
- equal((confidence / 1e6) < 0.1, true, 'Due to fail, odds of success = low');
53
-
54
- await kill({});
21
+ // Create a channel from the control to the target node
22
+ await setupChannel({
23
+ generate,
24
+ lnd,
25
+ capacity: channelCapacityTokens * 2,
26
+ to: target,
27
+ });
28
+
29
+ // Create a too-small channel from target to remote
30
+ await setupChannel({
31
+ generate: target.generate,
32
+ give: Math.round(channelCapacityTokens / 2),
33
+ lnd: target.lnd,
34
+ to: remote,
35
+ });
36
+
37
+ await addPeer({lnd, public_key: remote.id, socket: remote.socket});
38
+
39
+ const destination = remote.id;
40
+
41
+ // Allow time for graph sync to complete
42
+ const {routes} = await waitForRoute({destination, lnd, tokens});
43
+
44
+ // Run into a failure to inform future pathfinding
45
+ try {
46
+ await probeForRoute({destination, lnd, tokens});
47
+ } catch (err) {}
48
+
49
+ const [{hops}] = routes;
50
+
51
+ const {confidence} = await getRouteConfidence({lnd, hops});
52
+
53
+ equal((confidence / 1e6) < 0.1, true, 'Due to fail, odds of success low');
54
+ } catch (err) {
55
+ equal(err, null, 'Expected no error');
56
+ } finally {
57
+ await kill({});
58
+ }
55
59
 
56
60
  return end();
57
61
  });
@@ -8,6 +8,7 @@ const {addPeer} = require('./../../');
8
8
  const {createInvoice} = require('./../../');
9
9
  const {decodePaymentRequest} = require('./../../');
10
10
  const {getInvoice} = require('./../../');
11
+ const {getNetworkGraph} = require('./../../');
11
12
  const {getRouteThroughHops} = require('./../../');
12
13
  const {getRouteToDestination} = require('./../../');
13
14
  const {getWalletInfo} = require('./../../');
@@ -17,8 +18,10 @@ const {setupChannel} = require('./../macros');
17
18
  const {waitForRoute} = require('./../macros');
18
19
 
19
20
  const confirmationCount = 6;
21
+ const interval = 10;
20
22
  const messages = [{type: '1000000', value: '01'}];
21
23
  const size = 3;
24
+ const times = 1000;
22
25
  const tokens = 100;
23
26
 
24
27
  // Getting a route through hops should result in a route through specified hops
@@ -40,7 +43,7 @@ test(`Get route through hops`, async ({end, equal, strictSame}) => {
40
43
 
41
44
  await target.generate({count: confirmationCount});
42
45
 
43
- await asyncRetry({interval: 10, times: 1000}, async () => {
46
+ await asyncRetry({interval, times}, async () => {
44
47
  const wallet = await getWalletInfo({lnd: remote.lnd});
45
48
 
46
49
  await addPeer({lnd, public_key: remote.id, socket: remote.socket});
@@ -59,11 +62,25 @@ test(`Get route through hops`, async ({end, equal, strictSame}) => {
59
62
 
60
63
  await waitForRoute({lnd, destination: remote.id, tokens: invoice.tokens});
61
64
 
62
- const {route} = await getRouteToDestination({
63
- lnd,
64
- cltv_delta: decodedRequest.cltv_delta,
65
- destination: decodedRequest.destination,
66
- tokens: invoice.tokens,
65
+ const {route} = await asyncRetry({interval, times}, async () => {
66
+ return await getRouteToDestination({
67
+ lnd,
68
+ cltv_delta: decodedRequest.cltv_delta,
69
+ destination: decodedRequest.destination,
70
+ tokens: invoice.tokens,
71
+ });
72
+ });
73
+
74
+ await asyncRetry({interval, times}, async () => {
75
+ const {nodes} = await getNetworkGraph({lnd});
76
+
77
+ const limitedFeatures = nodes.find(node => {
78
+ return !node.features.find(n => n.bit === 14);
79
+ });
80
+
81
+ if (!!limitedFeatures) {
82
+ throw new Error('NetworkGraphSyncIncomplete');
83
+ }
67
84
  });
68
85
 
69
86
  const res = await getRouteThroughHops({
@@ -18,6 +18,7 @@ const {openChannel} = require('./../../');
18
18
  const {payViaRoutes} = require('./../../');
19
19
  const {routeFromChannels} = require('./../../');
20
20
  const {setupChannel} = require('./../macros');
21
+ const {subscribeToForwardRequests} = require('./../../');
21
22
  const {waitForChannel} = require('./../macros');
22
23
  const {waitForPendingChannel} = require('./../macros');
23
24
  const {waitForRoute} = require('./../macros');
@@ -27,6 +28,7 @@ const confirmationCount = 6;
27
28
  const defaultFee = 1e3;
28
29
  const defaultVout = 0;
29
30
  const interval = 10;
31
+ const intermediateRecord = {type: '65536', value: '5678'};
30
32
  const mtokPadding = '000';
31
33
  const regtestChain = '0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206';
32
34
  const reserveRatio = 0.99;
@@ -39,7 +41,7 @@ const tokens = 100;
39
41
  const txIdHexLength = 32 * 2;
40
42
 
41
43
  // Paying via routes should successfully pay via routes
42
- test(`Pay via routes`, async ({end, equal}) => {
44
+ test(`Pay via routes`, async ({end, equal, strictSame}) => {
43
45
  const {kill, nodes} = await spawnLightningCluster({size});
44
46
 
45
47
  const [{generate, lnd}, target, remote] = nodes;
@@ -170,10 +172,26 @@ test(`Pay via routes`, async ({end, equal}) => {
170
172
  equal(lowFeeErrMessage, 'FeeInsufficient', 'Low fee returns low fee msg');
171
173
  }
172
174
 
175
+ const [hopToTarget] = route.hops;
176
+
177
+ hopToTarget.messages = [intermediateRecord];
178
+
173
179
  route.messages = [{type: tlvType, value: tlvValue}];
174
180
 
181
+ const sub = subscribeToForwardRequests({lnd: target.lnd});
182
+
183
+ const forwardMessages = [];
184
+
185
+ sub.on('forward_request', request => {
186
+ request.messages.forEach(message => forwardMessages.push(message));
187
+
188
+ return request.accept();
189
+ });
190
+
175
191
  const payment = await payViaRoutes({id, lnd, routes: [route]});
176
192
 
193
+ strictSame(forwardMessages, [intermediateRecord], 'Got intermediate record');
194
+
177
195
  equal(payment.confirmed_at > start, true, 'Paid has confirm date');
178
196
 
179
197
  const paidInvoice = await getInvoice({id, lnd: remote.lnd});