ln-service 53.6.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.
- package/CHANGELOG.md +4 -0
- package/README.md +9 -1
- package/package.json +3 -3
- package/test/integration/test_add_peer.js +22 -18
- package/test/integration/test_get_failed_payments.js +123 -119
- package/test/integration/test_get_node.js +48 -44
- package/test/integration/test_get_wallet_info.js +11 -0
- package/test/integration/test_subscribe_to_channels.js +1 -1
- package/test/integration/test_subscribe_to_peer_messages.js +77 -71
- package/test/routerrpc-integration/test_get_forwarding_reputations.js +64 -60
- package/test/routerrpc-integration/test_get_route_confidence.js +38 -34
- package/test/routerrpc-integration/test_get_route_through_hops.js +23 -6
- package/test/routerrpc-integration/test_pay_via_routes.js +19 -1
- package/test/routerrpc-integration/test_subscribe_to_forward_requests.js +2 -2
package/CHANGELOG.md
CHANGED
package/README.md
CHANGED
|
@@ -2530,7 +2530,7 @@ LND 0.11.1 and below do not return `last_reconnected` or `reconnection_rate`
|
|
|
2530
2530
|
}]
|
|
2531
2531
|
is_inbound: <Is Inbound Peer Bool>
|
|
2532
2532
|
[is_sync_peer]: <Is Syncing Graph Data Bool>
|
|
2533
|
-
[
|
|
2533
|
+
[last_reconnection]: <Peer Last Reconnected At ISO 8601 Date String>
|
|
2534
2534
|
ping_time: <Ping Latency Milliseconds Number>
|
|
2535
2535
|
public_key: <Node Identity Public Key String>
|
|
2536
2536
|
[reconnection_rate]: <Count of Reconnections Over Time Number>
|
|
@@ -3706,6 +3706,10 @@ Requires `offchain:write` permission
|
|
|
3706
3706
|
fee_mtokens: <Fee Millitokens String>
|
|
3707
3707
|
forward: <Forward Tokens Number>
|
|
3708
3708
|
forward_mtokens: <Forward Millitokens String>
|
|
3709
|
+
[messages]: [{
|
|
3710
|
+
type: <Message Type Number String>
|
|
3711
|
+
value: <Message Raw Value Hex Encoded String>
|
|
3712
|
+
}]
|
|
3709
3713
|
[public_key]: <Public Key Hex String>
|
|
3710
3714
|
timeout: <Timeout Block Height Number>
|
|
3711
3715
|
}]
|
|
@@ -5692,6 +5696,10 @@ Requires `offchain:write` permission
|
|
|
5692
5696
|
fee_mtokens: <Fee Millitokens String>
|
|
5693
5697
|
forward: <Forward Tokens Number>
|
|
5694
5698
|
forward_mtokens: <Forward Millitokens String>
|
|
5699
|
+
[messages]: [{
|
|
5700
|
+
type: <Message Type Number String>
|
|
5701
|
+
value: <Message Raw Value Hex Encoded String>
|
|
5702
|
+
}]
|
|
5695
5703
|
public_key: <Public Key Hex String>
|
|
5696
5704
|
timeout: <Timeout Block Height Number>
|
|
5697
5705
|
}]
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"cors": "2.8.5",
|
|
12
12
|
"express": "4.17.2",
|
|
13
13
|
"invoices": "2.0.3",
|
|
14
|
-
"lightning": "5.
|
|
14
|
+
"lightning": "5.6.0",
|
|
15
15
|
"macaroon": "3.0.4",
|
|
16
16
|
"morgan": "1.10.0",
|
|
17
17
|
"ws": "8.4.2"
|
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
"bitcoinjs-lib": "6.0.1",
|
|
27
27
|
"bn.js": "5.2.0",
|
|
28
28
|
"ecpair": "2.0.1",
|
|
29
|
-
"ln-docker-daemons": "2.2.
|
|
29
|
+
"ln-docker-daemons": "2.2.3",
|
|
30
30
|
"portfinder": "1.0.28",
|
|
31
31
|
"psbt": "1.1.11",
|
|
32
32
|
"rimraf": "3.0.2",
|
|
@@ -65,5 +65,5 @@
|
|
|
65
65
|
"integration-test-0.12.0": "DOCKER_LND_VERSION=v0.12.0-beta npm run test",
|
|
66
66
|
"test": "echo $DOCKER_LND_VERSION && tap -j 2 --branches=1 --functions=1 --lines=1 --statements=1 -t 200 test/autopilotrpc-integration/*.js test/chainrpc-integration/*.js test/integration/*.js test/invoicesrpc-integration/*.js test/routerrpc-integration/*.js test/signerrpc-integration/*.js test/tower_clientrpc-integration/*.js test/tower_serverrpc-integration/*.js test/walletrpc-integration/*.js"
|
|
67
67
|
},
|
|
68
|
-
"version": "53.
|
|
68
|
+
"version": "53.7.0"
|
|
69
69
|
}
|
|
@@ -17,30 +17,34 @@ test(`Add a peer`, async ({end, equal}) => {
|
|
|
17
17
|
|
|
18
18
|
const [{lnd}, target] = nodes;
|
|
19
19
|
|
|
20
|
-
|
|
20
|
+
try {
|
|
21
|
+
const connectedKeys = (await getPeers({lnd})).peers.map(n => n.public_key);
|
|
21
22
|
|
|
22
|
-
|
|
23
|
+
equal(connectedKeys.find(n => n === target.id), undefined, 'No peer');
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
const {peers} = await getPeers({lnd});
|
|
25
|
+
await asyncRetry({interval, times}, async () => {
|
|
26
|
+
await addPeer({
|
|
27
|
+
lnd,
|
|
28
|
+
timeout,
|
|
29
|
+
public_key: target.id,
|
|
30
|
+
socket: target.socket,
|
|
31
|
+
});
|
|
33
32
|
|
|
34
|
-
|
|
33
|
+
const {peers} = await getPeers({lnd});
|
|
35
34
|
|
|
36
|
-
|
|
37
|
-
throw new Error('ExpectedConnectionToTarget');
|
|
38
|
-
}
|
|
35
|
+
const connected = peers.find(n => n.public_key === target.id);
|
|
39
36
|
|
|
40
|
-
|
|
41
|
-
|
|
37
|
+
if (!connected) {
|
|
38
|
+
throw new Error('ExpectedConnectionToTarget');
|
|
39
|
+
}
|
|
42
40
|
|
|
43
|
-
|
|
41
|
+
equal(connected.public_key, target.id, 'Connected to remote node');
|
|
42
|
+
});
|
|
43
|
+
} catch (err) {
|
|
44
|
+
equal(err, null, 'Expected no error');
|
|
45
|
+
} finally {
|
|
46
|
+
await kill({});
|
|
47
|
+
}
|
|
44
48
|
|
|
45
49
|
return end();
|
|
46
50
|
});
|
|
@@ -28,128 +28,132 @@ test('Get failed payments', async ({end, equal, strictSame}) => {
|
|
|
28
28
|
|
|
29
29
|
const [{generate, lnd}, target, remote] = nodes;
|
|
30
30
|
|
|
31
|
-
const {address} = await createChainAddress({lnd: remote.lnd});
|
|
32
|
-
|
|
33
|
-
await generate({count});
|
|
34
|
-
|
|
35
|
-
// Send coins to remote so that it can accept the channel
|
|
36
|
-
await sendToChainAddress({lnd, address, tokens: channelCapacityTokens});
|
|
37
|
-
|
|
38
|
-
// Generate to confirm the tx
|
|
39
|
-
await generate({count: confirmationCount});
|
|
40
|
-
await remote.generate({count: confirmationCount});
|
|
41
|
-
|
|
42
|
-
await setupChannel({
|
|
43
|
-
generate,
|
|
44
|
-
lnd,
|
|
45
|
-
capacity: channelCapacityTokens + channelCapacityTokens,
|
|
46
|
-
to: target,
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
await setupChannel({
|
|
50
|
-
capacity: channelCapacityTokens,
|
|
51
|
-
lnd: target.lnd,
|
|
52
|
-
generate: target.generate,
|
|
53
|
-
generator: target,
|
|
54
|
-
give: Math.round(channelCapacityTokens / 2),
|
|
55
|
-
to: remote,
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
await addPeer({lnd, public_key: remote.id, socket: remote.socket});
|
|
59
|
-
|
|
60
|
-
const invoice = await createInvoice({tokens, lnd: remote.lnd});
|
|
61
|
-
|
|
62
|
-
const bigInvoice = await createInvoice({
|
|
63
|
-
tokens: (channelCapacityTokens / 2) + (channelCapacityTokens / 4),
|
|
64
|
-
lnd: remote.lnd,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
31
|
try {
|
|
68
|
-
await
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
generate:
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
32
|
+
const {address} = await createChainAddress({lnd: remote.lnd});
|
|
33
|
+
|
|
34
|
+
await generate({count});
|
|
35
|
+
|
|
36
|
+
// Send coins to remote so that it can accept the channel
|
|
37
|
+
await sendToChainAddress({lnd, address, tokens: channelCapacityTokens});
|
|
38
|
+
|
|
39
|
+
// Generate to confirm the tx
|
|
40
|
+
await generate({count: confirmationCount});
|
|
41
|
+
await remote.generate({count: confirmationCount});
|
|
42
|
+
|
|
43
|
+
await setupChannel({
|
|
44
|
+
generate,
|
|
45
|
+
lnd,
|
|
46
|
+
capacity: channelCapacityTokens + channelCapacityTokens,
|
|
47
|
+
to: target,
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
await setupChannel({
|
|
51
|
+
capacity: channelCapacityTokens,
|
|
52
|
+
lnd: target.lnd,
|
|
53
|
+
generate: target.generate,
|
|
54
|
+
generator: target,
|
|
55
|
+
give: Math.round(channelCapacityTokens / 2),
|
|
56
|
+
to: remote,
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
await addPeer({lnd, public_key: remote.id, socket: remote.socket});
|
|
60
|
+
|
|
61
|
+
const invoice = await createInvoice({tokens, lnd: remote.lnd});
|
|
62
|
+
|
|
63
|
+
const bigInvoice = await createInvoice({
|
|
64
|
+
tokens: (channelCapacityTokens / 2) + (channelCapacityTokens / 4),
|
|
65
|
+
lnd: remote.lnd,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
try {
|
|
69
|
+
await pay({lnd, request: bigInvoice.request});
|
|
70
|
+
} catch (err) {
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Create a new channel to increase total edge liquidity
|
|
74
|
+
await setupChannel({
|
|
75
|
+
capacity: channelCapacityTokens,
|
|
76
|
+
lnd: target.lnd,
|
|
77
|
+
generate: target.generate,
|
|
78
|
+
generator: target,
|
|
79
|
+
to: remote,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
await deleteForwardingReputations({lnd});
|
|
83
|
+
|
|
84
|
+
await asyncRetry({times}, async () => {
|
|
85
|
+
await pay({lnd, request: invoice.request});
|
|
86
|
+
});
|
|
87
|
+
|
|
88
|
+
{
|
|
89
|
+
const {payments} = await getFailedPayments({lnd});
|
|
90
|
+
|
|
91
|
+
const [payment] = payments.filter(n => n.mtokens === bigInvoice.mtokens);
|
|
92
|
+
|
|
93
|
+
equal(payment.destination, remote.id, 'Payment to');
|
|
94
|
+
equal(payment.confirmed_at, undefined, 'No confirmation date');
|
|
95
|
+
equal(!!payment.created_at, true, 'Got payment created date');
|
|
96
|
+
equal(payment.fee, undefined, 'No fee when not paid');
|
|
97
|
+
equal(payment.fee_mtokens, undefined, 'No fee mtokens when not paid');
|
|
98
|
+
equal(!!payment.id, true, 'Got a payment id');
|
|
99
|
+
equal(!!payment.index, true, 'Got payment index');
|
|
100
|
+
equal(payment.is_confirmed, false, 'Failed payment is not confirmed');
|
|
101
|
+
equal(payment.is_outgoing, true, 'Failed payment is outgoing');
|
|
102
|
+
equal(payment.mtokens, bigInvoice.mtokens, 'Payment has mtokens');
|
|
103
|
+
equal(payment.request, bigInvoice.request, 'Probe has a request');
|
|
104
|
+
equal(payment.secret, undefined, 'Failed has no secret');
|
|
105
|
+
equal(payment.safe_fee, undefined, 'Failed has no fee');
|
|
106
|
+
equal(payment.safe_tokens, bigInvoice.tokens, 'Failed has safe tokens');
|
|
107
|
+
equal(payment.tokens, bigInvoice.tokens, 'Failed has tokens');
|
|
108
|
+
|
|
109
|
+
const gotFailed = await getPayment({lnd, id: payment.id});
|
|
110
|
+
|
|
111
|
+
strictSame(
|
|
112
|
+
gotFailed,
|
|
113
|
+
{
|
|
114
|
+
failed: {
|
|
115
|
+
is_insufficient_balance: false,
|
|
116
|
+
is_invalid_payment: false,
|
|
117
|
+
is_pathfinding_timeout: false,
|
|
118
|
+
is_route_not_found: true,
|
|
119
|
+
},
|
|
120
|
+
is_confirmed: false,
|
|
121
|
+
is_failed: true,
|
|
122
|
+
is_pending: false,
|
|
123
|
+
payment: undefined,
|
|
124
|
+
pending: undefined,
|
|
118
125
|
},
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
equal(payment.tokens, invoice.tokens, 'Failed has tokens');
|
|
126
|
+
'Got failed state'
|
|
127
|
+
);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
{
|
|
131
|
+
const {payments} = await getPayments({lnd});
|
|
132
|
+
|
|
133
|
+
const [payment] = payments;
|
|
134
|
+
|
|
135
|
+
equal(payment.destination, remote.id, 'Paid to');
|
|
136
|
+
equal(!!payment.confirmed_at, true, 'Got confirmation date');
|
|
137
|
+
equal(!!payment.created_at, true, 'Got payment start date');
|
|
138
|
+
equal(payment.fee, 1, 'Got fee paid');
|
|
139
|
+
equal(payment.fee_mtokens, '1500', 'Got fee mtokens paid');
|
|
140
|
+
strictSame(payment.hops, [target.id], 'Got hops');
|
|
141
|
+
equal(!!payment.id, true, 'Got a payment id');
|
|
142
|
+
equal(!!payment.index, true, 'Got payment index');
|
|
143
|
+
equal(payment.is_confirmed, true, 'Failed payment is not confirmed');
|
|
144
|
+
equal(payment.is_outgoing, true, 'Failed payment is outgoing');
|
|
145
|
+
equal(payment.mtokens, invoice.mtokens, 'Payment has mtokens');
|
|
146
|
+
equal(payment.request, invoice.request, 'Payment has a request');
|
|
147
|
+
equal(!!payment.secret, true, 'Failed has no secret');
|
|
148
|
+
equal(payment.safe_fee, 2, 'Failed has no fee');
|
|
149
|
+
equal(payment.safe_tokens, invoice.tokens, 'Failed has safe tokens');
|
|
150
|
+
equal(payment.tokens, invoice.tokens, 'Failed has tokens');
|
|
151
|
+
}
|
|
152
|
+
} catch (err) {
|
|
153
|
+
strictSame(err, null, 'Expected no error');
|
|
154
|
+
} finally {
|
|
155
|
+
await kill({});
|
|
150
156
|
}
|
|
151
157
|
|
|
152
|
-
await kill({});
|
|
153
|
-
|
|
154
158
|
return end();
|
|
155
159
|
});
|
|
@@ -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
|
-
|
|
27
|
+
try {
|
|
28
|
+
const controlToTarget = await setupChannel({generate, lnd, to: target});
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
30
|
+
const targetToRemote = await setupChannel({
|
|
31
|
+
generate: target.generate,
|
|
32
|
+
lnd: target.lnd,
|
|
33
|
+
to: remote,
|
|
34
|
+
});
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
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
|
-
|
|
45
|
+
await addPeer({lnd, public_key: remote.id, socket: remote.socket});
|
|
45
46
|
|
|
46
|
-
|
|
47
|
+
await delay(3000);
|
|
47
48
|
|
|
48
|
-
|
|
49
|
+
const node = await getNode({lnd, public_key: id});
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
51
|
+
{
|
|
52
|
+
const {channels} = await getNode({
|
|
53
|
+
lnd,
|
|
54
|
+
is_omitting_channels: true,
|
|
55
|
+
public_key: id,
|
|
56
|
+
});
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
if (!!node.channels.length) {
|
|
61
|
-
const [{policies}] = node.channels;
|
|
58
|
+
equal(channels.length, [].length, 'Channels are omitted')
|
|
59
|
+
}
|
|
62
60
|
|
|
63
|
-
|
|
61
|
+
if (!!node.channels.length) {
|
|
62
|
+
const [{policies}] = node.channels;
|
|
64
63
|
|
|
65
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
});
|
|
@@ -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 =
|
|
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
|
|
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
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
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
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
49
|
+
const messages = [];
|
|
50
|
+
const targetSub = subscribeToPeerMessages({lnd: target.lnd});
|
|
51
|
+
const remoteSub = subscribeToPeerMessages({lnd: remote.lnd});
|
|
52
|
+
const targetMessages = [];
|
|
52
53
|
|
|
53
|
-
|
|
54
|
+
remoteSub.on('message_received', message => messages.push(message));
|
|
54
55
|
|
|
55
|
-
|
|
56
|
-
|
|
56
|
+
targetSub.on('message_received', async ({message, type}) => {
|
|
57
|
+
targetMessages.push(message);
|
|
57
58
|
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
64
|
-
|
|
80
|
+
await asyncRetry({interval, times}, async () => {
|
|
81
|
+
// Control send a message to target peer
|
|
65
82
|
await sendMessageToPeer({
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
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 (!
|
|
73
|
-
throw new Error('
|
|
89
|
+
if (!targetMessages.length) {
|
|
90
|
+
throw new Error('ExpectedTargetMessageReceived');
|
|
74
91
|
}
|
|
75
92
|
});
|
|
76
|
-
});
|
|
77
93
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
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:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
await
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
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
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
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
|
|
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
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
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});
|
|
@@ -20,8 +20,8 @@ const {waitForRoute} = require('./../macros');
|
|
|
20
20
|
const size = 3;
|
|
21
21
|
const tokens = 100;
|
|
22
22
|
|
|
23
|
-
//
|
|
24
|
-
test(`
|
|
23
|
+
// Subscribing to forward requests should intercept forwards
|
|
24
|
+
test(`Subscribe to requests`, async ({end, equal, rejects, strictSame}) => {
|
|
25
25
|
const {kill, nodes} = await spawnLightningCluster({size});
|
|
26
26
|
|
|
27
27
|
const [{generate, lnd}, target, remote] = nodes;
|