ln-service 53.6.0 → 53.7.3

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +11 -3
  3. package/index.js +2 -2
  4. package/package.json +5 -4
  5. package/test/integration/test_add_peer.js +26 -20
  6. package/test/integration/test_delete_pending_channel.js +5 -2
  7. package/test/integration/test_get_closed_channels.js +0 -2
  8. package/test/integration/test_get_failed_payments.js +123 -119
  9. package/test/integration/test_get_invoice.js +0 -1
  10. package/test/integration/test_get_node.js +65 -49
  11. package/test/integration/test_get_peers.js +32 -21
  12. package/test/integration/test_get_pending_force.js +1 -1
  13. package/test/integration/test_get_wallet_info.js +35 -18
  14. package/test/integration/test_open_channels.js +22 -15
  15. package/test/integration/test_pay.js +0 -1
  16. package/test/integration/test_pay_private_invoice.js +0 -1
  17. package/test/integration/test_propose_channel.js +438 -421
  18. package/test/integration/test_remove_peer.js +13 -9
  19. package/test/integration/test_send_message_to_peer.js +39 -28
  20. package/test/integration/test_subscribe_to_channels.js +1 -2
  21. package/test/integration/test_subscribe_to_invoices.js +80 -78
  22. package/test/integration/test_subscribe_to_peer_messages.js +81 -73
  23. package/test/integration/test_subscribe_to_peers.js +23 -19
  24. package/test/invoicesrpc-integration/test_get_sweep_transactions.js +0 -2
  25. package/test/invoicesrpc-integration/test_subscribe_cancel_invoice.js +0 -1
  26. package/test/macros/wait_for_channel.js +1 -1
  27. package/test/routerrpc-integration/test_delete_forwarding_reputations.js +61 -27
  28. package/test/routerrpc-integration/test_get_forwarding_reputations.js +74 -42
  29. package/test/routerrpc-integration/test_get_route_confidence.js +38 -34
  30. package/test/routerrpc-integration/test_get_route_through_hops.js +45 -17
  31. package/test/routerrpc-integration/test_multipath_payment.js +0 -1
  32. package/test/routerrpc-integration/test_pay_via_payment_details.js +118 -111
  33. package/test/routerrpc-integration/test_pay_via_payment_request.js +92 -80
  34. package/test/routerrpc-integration/test_pay_via_routes.js +19 -1
  35. package/test/routerrpc-integration/test_probe_for_route.js +78 -74
  36. package/test/routerrpc-integration/test_subscribe_to_forward_requests.js +2 -3
  37. package/test/routerrpc-integration/test_subscribe_to_forwards.js +518 -505
  38. package/test/routerrpc-integration/test_subscribe_to_past_payments.js +0 -3
  39. package/test/tower_clientrpc-integration/test_get_connected_watchtowers.js +0 -3
  40. package/test/walletrpc-integration/test_fund_psbt.js +113 -1
  41. package/test/walletrpc-integration/test_partially_sign_psbt.js +12 -5
  42. package/test/walletrpc-integration/test_sign_psbt.js +4 -1
@@ -1,3 +1,4 @@
1
+ const asyncRetry = require('async/retry');
1
2
  const {spawnLightningCluster} = require('ln-docker-daemons');
2
3
  const {test} = require('@alexbosworth/tap');
3
4
 
@@ -5,12 +6,17 @@ const {addPeer} = require('./../../');
5
6
  const {createInvoice} = require('./../../');
6
7
  const {deleteForwardingReputations} = require('./../../');
7
8
  const {getForwardingReputations} = require('./../../');
9
+ const {getNetworkGraph} = require('./../../');
8
10
  const {payViaPaymentRequest} = require('./../../');
9
11
  const {probeForRoute} = require('./../../');
10
12
  const {setupChannel} = require('./../macros');
11
13
  const {waitForRoute} = require('./../macros');
12
14
 
15
+ const flatten = arr => [].concat(...arr);
16
+ const interval = 10;
13
17
  const size = 3;
18
+ const times = 1000;
19
+ const tlvOnionBit = 14;
14
20
  const tokens = 1e6 / 2;
15
21
 
16
22
  // Deleting forwarding reputations should eliminate forwarding reputations
@@ -19,45 +25,73 @@ test('Delete forwarding reputations', async ({end, equal}) => {
19
25
 
20
26
  const [{generate, lnd}, target, remote] = nodes;
21
27
 
22
- const controlToTargetChan = await setupChannel({generate, lnd, to: target});
28
+ try {
29
+ const controlToTargetChan = await setupChannel({
30
+ generate,
31
+ lnd,
32
+ to: target,
33
+ });
23
34
 
24
- const targetToRemoteChan = await setupChannel({
25
- generate: target.generate,
26
- lnd: target.lnd,
27
- to: remote,
28
- });
35
+ const targetToRemoteChan = await setupChannel({
36
+ generate: target.generate,
37
+ lnd: target.lnd,
38
+ to: remote,
39
+ });
29
40
 
30
- await addPeer({lnd, public_key: remote.id, socket: remote.socket});
41
+ await addPeer({lnd, public_key: remote.id, socket: remote.socket});
31
42
 
32
- const {id, request} = await createInvoice({tokens, lnd: remote.lnd});
43
+ const {id, request} = await createInvoice({tokens, lnd: remote.lnd});
33
44
 
34
- await waitForRoute({lnd, tokens, destination: remote.id});
45
+ await asyncRetry({interval, times}, async () => {
46
+ const {channels, nodes} = await getNetworkGraph({lnd});
35
47
 
36
- try {
37
- await payViaPaymentRequest({lnd, request});
38
- } catch (err) {
39
- equal(err, null, 'Expected no error paying payment request');
40
- }
48
+ const limitedFeatures = nodes.find(node => {
49
+ return !node.features.find(n => n.bit === tlvOnionBit);
50
+ });
41
51
 
42
- try {
43
- await probeForRoute({lnd, tokens, destination: remote.id});
44
- } catch (err) {}
52
+ const policies = flatten(channels.map(n => n.policies));
45
53
 
46
- {
47
- const {nodes} = await getForwardingReputations({lnd});
54
+ const cltvDeltas = policies.map(n => n.cltv_delta);
48
55
 
49
- equal(nodes.length, 2, 'Reputations should exist');
50
- }
56
+ if (!!cltvDeltas.filter(n => !n).length) {
57
+ throw new Error('ExpectedAllChannelPolicies');
58
+ }
51
59
 
52
- await deleteForwardingReputations({lnd});
60
+ if (!!limitedFeatures) {
61
+ throw new Error('NetworkGraphSyncIncomplete');
62
+ }
63
+ });
53
64
 
54
- {
55
- const {nodes} = await getForwardingReputations({lnd});
65
+ await waitForRoute({lnd, tokens, destination: remote.id});
56
66
 
57
- equal(nodes.length, [].length, 'Reputations should be wiped');
58
- }
67
+ try {
68
+ await payViaPaymentRequest({lnd, request});
69
+ } catch (err) {
70
+ equal(err, null, 'Expected no error paying payment request');
71
+ }
59
72
 
60
- await kill({});
73
+ try {
74
+ await probeForRoute({lnd, tokens, destination: remote.id});
75
+ } catch (err) {}
76
+
77
+ {
78
+ const {nodes} = await getForwardingReputations({lnd});
79
+
80
+ equal(nodes.length, 2, 'Reputations should exist');
81
+ }
82
+
83
+ await deleteForwardingReputations({lnd});
84
+
85
+ {
86
+ const {nodes} = await getForwardingReputations({lnd});
87
+
88
+ equal(nodes.length, [].length, 'Reputations should be wiped');
89
+ }
90
+ } catch (err) {
91
+ equal(err, null, 'Expected no error');
92
+ } finally {
93
+ await kill({});
94
+ }
61
95
 
62
96
  return end();
63
97
  });
@@ -5,7 +5,7 @@ const {test} = require('@alexbosworth/tap');
5
5
  const {addPeer} = require('./../../');
6
6
  const {getChannels} = require('./../../');
7
7
  const {getForwardingReputations} = require('./../../');
8
- const {payViaRoutes} = require('./../../');
8
+ const {getNetworkGraph} = require('./../../');
9
9
  const {probeForRoute} = require('./../../');
10
10
  const {setupChannel} = require('./../macros');
11
11
  const {waitForRoute} = require('./../macros');
@@ -15,9 +15,12 @@ const channelCapacityTokens = 1e6;
15
15
  const confirmationCount = 20;
16
16
  const defaultFee = 1e3;
17
17
  const defaultOdds = 950000;
18
+ const flatten = arr => [].concat(...arr);
18
19
  const interval = 10;
20
+ const maturity = 100;
19
21
  const size = 3;
20
22
  const times = 2000;
23
+ const tlvOnionBit = 14;
21
24
  const tokens = 1e6 / 2;
22
25
 
23
26
  // Getting forwarding reputations should return reputations
@@ -26,66 +29,95 @@ test('Get forwarding reputations', async ({end, equal}) => {
26
29
 
27
30
  const [{generate, id, lnd}, target, remote] = cluster.nodes;
28
31
 
29
- await generate({count: 400});
32
+ try {
33
+ await generate({count: maturity});
34
+
35
+ // Create a channel from the control to the target node
36
+ await setupChannel({
37
+ generate,
38
+ lnd,
39
+ capacity: channelCapacityTokens * 2,
40
+ to: target,
41
+ });
42
+
43
+ const targetToRemoteChan = await setupChannel({
44
+ generate: target.generate,
45
+ give: Math.round(channelCapacityTokens / 2),
46
+ lnd: target.lnd,
47
+ to: remote,
48
+ });
49
+
50
+ await asyncRetry({interval, times}, async () => {
51
+ const {channels, nodes} = await getNetworkGraph({lnd});
52
+
53
+ const limitedFeatures = nodes.find(node => {
54
+ return !node.features.find(n => n.bit === tlvOnionBit);
55
+ });
30
56
 
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
- });
57
+ const policies = flatten(channels.map(n => n.policies));
38
58
 
39
- const targetToRemoteChan = await setupChannel({
40
- generate: target.generate,
41
- give: Math.round(channelCapacityTokens / 2),
42
- lnd: target.lnd,
43
- to: remote,
44
- });
59
+ const cltvDeltas = policies.map(n => n.cltv_delta);
45
60
 
46
- await asyncRetry({interval, times}, async () => {
47
- await addPeer({lnd, public_key: remote.id, socket: remote.socket});
61
+ if (!!cltvDeltas.filter(n => !n).length) {
62
+ throw new Error('ExpectedAllChannelPolicies');
63
+ }
48
64
 
49
- const {channels} = await getChannels({lnd: remote.lnd});
65
+ if (!!limitedFeatures) {
66
+ throw new Error('NetworkGraphSyncIncomplete');
67
+ }
68
+ });
50
69
 
51
- await waitForRoute({lnd, tokens, destination: remote.id});
70
+ await asyncRetry({interval, times}, async () => {
71
+ await generate({});
52
72
 
53
- try {
54
- const res = await probeForRoute({
73
+ await addPeer({
74
+ lnd,
75
+ public_key: remote.id,
76
+ socket: remote.socket,
77
+ retry_count: 1,
78
+ retry_delay: 1,
79
+ timeout: 1,
80
+ });
81
+
82
+ const {channels} = await getChannels({lnd: remote.lnd});
83
+
84
+ await waitForRoute({lnd, tokens, destination: remote.id});
85
+
86
+ await probeForRoute({
55
87
  lnd,
56
88
  tokens,
57
89
  destination: remote.id,
58
90
  is_ignoring_past_failures: true,
59
91
  });
60
- } catch (err) {
61
- equal(err, null, 'Expected no error probing');
62
- }
63
-
64
- const {nodes} = await getForwardingReputations({lnd});
65
92
 
66
- const [node] = nodes;
93
+ const {nodes} = await getForwardingReputations({lnd});
67
94
 
68
- if (!node) {
69
- throw new Error('ExpectedForwardingNode');
70
- }
95
+ const [node] = nodes;
71
96
 
72
- equal(!!node.public_key, true, 'Temp fail node added');
97
+ if (!node) {
98
+ throw new Error('ExpectedForwardingNode');
99
+ }
73
100
 
74
- const [peer] = node.peers;
101
+ equal(!!node.public_key, true, 'Temp fail node added');
75
102
 
76
- if (!peer) {
77
- throw new Error('ExpectedNodePeer');
78
- }
103
+ const [peer] = node.peers;
79
104
 
80
- if (!peer.last_failed_forward_at) {
81
- throw new Error('ExpectedLastFailTimeReturned');
82
- }
105
+ if (!peer) {
106
+ throw new Error('ExpectedNodePeer');
107
+ }
83
108
 
84
- equal(!!peer.last_failed_forward_at, true, 'Last fail time returned');
85
- equal(!!peer.to_public_key, true, 'Got peer pub key');
86
- });
109
+ if (!peer.last_failed_forward_at) {
110
+ throw new Error('ExpectedLastFailTimeReturned');
111
+ }
87
112
 
88
- await cluster.kill({});
113
+ equal(!!peer.last_failed_forward_at, true, 'Last fail time returned');
114
+ equal(!!peer.to_public_key, true, 'Got peer pub key');
115
+ });
116
+ } catch (err) {
117
+ equal(err, null, 'Expected no error');
118
+ } finally {
119
+ await cluster.kill({});
120
+ }
89
121
 
90
122
  return end();
91
123
  });
@@ -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,17 +8,22 @@ 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('./../../');
14
- const {getWalletVersion} = require('./../../');
15
15
  const {payViaRoutes} = require('./../../');
16
16
  const {setupChannel} = require('./../macros');
17
17
  const {waitForRoute} = require('./../macros');
18
18
 
19
19
  const confirmationCount = 6;
20
+ const flatten = arr => [].concat(...arr);
21
+ const interval = 10;
22
+ const maturity = 100;
20
23
  const messages = [{type: '1000000', value: '01'}];
21
24
  const size = 3;
25
+ const times = 1000;
26
+ const tlvOnionBit = 14;
22
27
  const tokens = 100;
23
28
 
24
29
  // Getting a route through hops should result in a route through specified hops
@@ -27,8 +32,7 @@ test(`Get route through hops`, async ({end, equal, strictSame}) => {
27
32
 
28
33
  const [{generate, lnd}, target, remote] = nodes;
29
34
 
30
- await target.generate({count: 100});
31
- await remote.generate({count: 100});
35
+ await target.generate({count: maturity});
32
36
 
33
37
  const controlToTargetChan = await setupChannel({generate, lnd, to: target});
34
38
 
@@ -40,7 +44,7 @@ test(`Get route through hops`, async ({end, equal, strictSame}) => {
40
44
 
41
45
  await target.generate({count: confirmationCount});
42
46
 
43
- await asyncRetry({interval: 10, times: 1000}, async () => {
47
+ await asyncRetry({interval, times}, async () => {
44
48
  const wallet = await getWalletInfo({lnd: remote.lnd});
45
49
 
46
50
  await addPeer({lnd, public_key: remote.id, socket: remote.socket});
@@ -50,6 +54,26 @@ test(`Get route through hops`, async ({end, equal, strictSame}) => {
50
54
  }
51
55
  });
52
56
 
57
+ await asyncRetry({interval, times}, async () => {
58
+ const {channels, nodes} = await getNetworkGraph({lnd});
59
+
60
+ const limitedFeatures = nodes.find(node => {
61
+ return !node.features.find(n => n.bit === tlvOnionBit);
62
+ });
63
+
64
+ const policies = flatten(channels.map(n => n.policies));
65
+
66
+ const cltvDeltas = policies.map(n => n.cltv_delta);
67
+
68
+ if (!!cltvDeltas.filter(n => !n).length) {
69
+ throw new Error('ExpectedAllChannelPolicies');
70
+ }
71
+
72
+ if (!!limitedFeatures) {
73
+ throw new Error('NetworkGraphSyncIncomplete');
74
+ }
75
+ });
76
+
53
77
  const invoice = await createInvoice({tokens, lnd: remote.lnd});
54
78
 
55
79
  const {id} = invoice;
@@ -59,21 +83,25 @@ test(`Get route through hops`, async ({end, equal, strictSame}) => {
59
83
 
60
84
  await waitForRoute({lnd, destination: remote.id, tokens: invoice.tokens});
61
85
 
62
- const {route} = await getRouteToDestination({
63
- lnd,
64
- cltv_delta: decodedRequest.cltv_delta,
65
- destination: decodedRequest.destination,
66
- tokens: invoice.tokens,
86
+ const {route} = await asyncRetry({interval, times}, async () => {
87
+ return await getRouteToDestination({
88
+ lnd,
89
+ cltv_delta: decodedRequest.cltv_delta,
90
+ destination: decodedRequest.destination,
91
+ tokens: invoice.tokens,
92
+ });
67
93
  });
68
94
 
69
- const res = await getRouteThroughHops({
70
- lnd,
71
- messages,
72
- cltv_delta: decodedRequest.cltv_delta + 6,
73
- mtokens: (BigInt(invoice.tokens) * BigInt(1e3)).toString(),
74
- payment: decodedRequest.payment,
75
- public_keys: route.hops.map(n => n.public_key),
76
- total_mtokens: invoice.mtokens,
95
+ const res = await asyncRetry({interval, times}, async () => {
96
+ return await getRouteThroughHops({
97
+ lnd,
98
+ messages,
99
+ cltv_delta: decodedRequest.cltv_delta + 6,
100
+ mtokens: (BigInt(invoice.tokens) * BigInt(1e3)).toString(),
101
+ payment: decodedRequest.payment,
102
+ public_keys: route.hops.map(n => n.public_key),
103
+ total_mtokens: invoice.mtokens,
104
+ });
77
105
  });
78
106
 
79
107
  await payViaRoutes({lnd, id: invoice.id, routes: [res.route]});
@@ -4,7 +4,6 @@ const {test} = require('@alexbosworth/tap');
4
4
  const {createInvoice} = require('./../../');
5
5
  const {getInvoice} = require('./../../');
6
6
  const {getRouteToDestination} = require('./../../');
7
- const {getWalletVersion} = require('./../../');
8
7
  const {parsePaymentRequest} = require('./../../');
9
8
  const {payViaPaymentRequest} = require('./../../');
10
9
  const {payViaRoutes} = require('./../../');