ln-service 57.14.1 → 57.14.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.
- package/CHANGELOG.md +1 -1
- package/package.json +4 -4
- package/test/integration/test_get_route_to_destination.js +101 -99
- package/test/routerrpc-integration/test_route_from_channels_complex.js +323 -0
- package/test/routerrpc-integration/{test_route_from_channels.js → test_route_from_channels_simple.js} +15 -2
package/CHANGELOG.md
CHANGED
package/package.json
CHANGED
|
@@ -7,9 +7,9 @@
|
|
|
7
7
|
"url": "https://github.com/alexbosworth/ln-service/issues"
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
|
-
"bolt07": "1.9.
|
|
10
|
+
"bolt07": "1.9.4",
|
|
11
11
|
"invoices": "3.0.0",
|
|
12
|
-
"lightning": "10.14.
|
|
12
|
+
"lightning": "10.14.1",
|
|
13
13
|
"macaroon": "3.0.4"
|
|
14
14
|
},
|
|
15
15
|
"description": "Interaction helper for your Lightning Network daemon",
|
|
@@ -24,7 +24,7 @@
|
|
|
24
24
|
"bn.js": "5.2.1",
|
|
25
25
|
"bs58check": "3.0.1",
|
|
26
26
|
"ecpair": "2.1.0",
|
|
27
|
-
"ln-docker-daemons": "6.0.
|
|
27
|
+
"ln-docker-daemons": "6.0.19",
|
|
28
28
|
"p2tr": "2.0.0",
|
|
29
29
|
"portfinder": "1.0.32",
|
|
30
30
|
"psbt": "3.0.0",
|
|
@@ -72,5 +72,5 @@
|
|
|
72
72
|
"integration-test-0.14.4": "DOCKER_LND_VERSION=v0.14.4-beta npm run test",
|
|
73
73
|
"test": "echo $DOCKER_LND_VERSION && node test/runner"
|
|
74
74
|
},
|
|
75
|
-
"version": "57.14.
|
|
75
|
+
"version": "57.14.3"
|
|
76
76
|
}
|
|
@@ -24,128 +24,130 @@ const tokens = 1000;
|
|
|
24
24
|
|
|
25
25
|
// Getting a route to a destination should return a route to the destination
|
|
26
26
|
test(`Get a route to a destination`, async () => {
|
|
27
|
-
|
|
27
|
+
await asyncRetry({}, async () => {
|
|
28
|
+
const {kill, nodes} = await spawnLightningCluster({size});
|
|
28
29
|
|
|
29
|
-
|
|
30
|
+
const [control, target, remote] = nodes;
|
|
30
31
|
|
|
31
|
-
|
|
32
|
+
await control.generate({count: 200});
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
await setupChannel({
|
|
40
|
-
generate: target.generate,
|
|
41
|
-
give_tokens: 1e5,
|
|
42
|
-
is_private: true,
|
|
43
|
-
lnd: target.lnd,
|
|
44
|
-
to: remote,
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
const invoice = await asyncRetry({interval, times}, async () => {
|
|
48
|
-
const invoice = await createInvoice({
|
|
49
|
-
tokens,
|
|
50
|
-
is_including_private_channels: true,
|
|
51
|
-
lnd: remote.lnd,
|
|
34
|
+
await setupChannel({
|
|
35
|
+
generate: control.generate,
|
|
36
|
+
lnd: control.lnd,
|
|
37
|
+
to: target,
|
|
52
38
|
});
|
|
53
39
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
40
|
+
await setupChannel({
|
|
41
|
+
generate: target.generate,
|
|
42
|
+
give_tokens: 1e5,
|
|
43
|
+
is_private: true,
|
|
44
|
+
lnd: target.lnd,
|
|
45
|
+
to: remote,
|
|
46
|
+
});
|
|
59
47
|
|
|
60
|
-
|
|
61
|
-
|
|
48
|
+
const invoice = await asyncRetry({interval, times}, async () => {
|
|
49
|
+
const invoice = await createInvoice({
|
|
50
|
+
tokens,
|
|
51
|
+
is_including_private_channels: true,
|
|
52
|
+
lnd: remote.lnd,
|
|
53
|
+
});
|
|
62
54
|
|
|
63
|
-
|
|
64
|
-
});
|
|
55
|
+
const {routes} = parsePaymentRequest({request: invoice.request});
|
|
65
56
|
|
|
66
|
-
|
|
57
|
+
// Wait for private routes to get picked up
|
|
58
|
+
if (!routes) {
|
|
59
|
+
await cancelHodlInvoice({id: invoice.id, lnd: remote.lnd});
|
|
67
60
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
destination: parsed.destination,
|
|
71
|
-
features: parsed.features,
|
|
72
|
-
lnd: control.lnd,
|
|
73
|
-
payment: parsed.payment,
|
|
74
|
-
routes: parsed.routes,
|
|
75
|
-
mtokens: parsed.mtokens,
|
|
76
|
-
total_mtokens: parsed.mtokens,
|
|
77
|
-
});
|
|
61
|
+
throw new Error('ExpectedRouteForInvoice');
|
|
62
|
+
}
|
|
78
63
|
|
|
79
|
-
|
|
80
|
-
id: parsed.id,
|
|
81
|
-
lnd: control.lnd,
|
|
82
|
-
routes: [route],
|
|
64
|
+
return invoice;
|
|
83
65
|
});
|
|
84
66
|
|
|
85
|
-
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
const inv = await createInvoice({tokens, lnd: target.lnd});
|
|
67
|
+
const parsed = parsePaymentRequest({request: invoice.request});
|
|
89
68
|
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
69
|
+
await asyncRetry({interval, times}, async () => {
|
|
70
|
+
const {route} = await getRouteToDestination({
|
|
71
|
+
destination: parsed.destination,
|
|
72
|
+
features: parsed.features,
|
|
73
|
+
lnd: control.lnd,
|
|
74
|
+
payment: parsed.payment,
|
|
75
|
+
routes: parsed.routes,
|
|
76
|
+
mtokens: parsed.mtokens,
|
|
77
|
+
total_mtokens: parsed.mtokens,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const paid = await payViaRoutes({
|
|
81
|
+
id: parsed.id,
|
|
82
|
+
lnd: control.lnd,
|
|
83
|
+
routes: [route],
|
|
84
|
+
});
|
|
94
85
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
features: invDetails.features,
|
|
98
|
-
lnd: control.lnd,
|
|
99
|
-
messages: [message],
|
|
100
|
-
payment: invDetails.payment,
|
|
101
|
-
tokens: invDetails.tokens / [control, remote].length,
|
|
102
|
-
total_mtokens: invDetails.mtokens,
|
|
103
|
-
});
|
|
86
|
+
strictEqual(invoice.secret, paid.secret, 'Paid multi-hop private route');
|
|
87
|
+
});
|
|
104
88
|
|
|
105
|
-
|
|
106
|
-
destination: target.id,
|
|
107
|
-
features: invDetails.features,
|
|
108
|
-
lnd: remote.lnd,
|
|
109
|
-
messages: [message],
|
|
110
|
-
payment: invDetails.payment,
|
|
111
|
-
tokens: invDetails.tokens / [control, remote].length,
|
|
112
|
-
total_mtokens: invDetails.mtokens,
|
|
113
|
-
});
|
|
89
|
+
const inv = await createInvoice({tokens, lnd: target.lnd});
|
|
114
90
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
lnd: control.lnd,
|
|
120
|
-
routes: [controlToTarget.route],
|
|
121
|
-
}),
|
|
122
|
-
payViaRoutes({
|
|
123
|
-
id: invDetails.id,
|
|
124
|
-
lnd: remote.lnd,
|
|
125
|
-
routes: [remoteToTarget.route],
|
|
126
|
-
}),
|
|
127
|
-
]);
|
|
91
|
+
const invDetails = await decodePaymentRequest({
|
|
92
|
+
lnd: control.lnd,
|
|
93
|
+
request: inv.request,
|
|
94
|
+
});
|
|
128
95
|
|
|
129
|
-
|
|
130
|
-
|
|
96
|
+
const controlToTarget = await getRouteToDestination({
|
|
97
|
+
destination: target.id,
|
|
98
|
+
features: invDetails.features,
|
|
99
|
+
lnd: control.lnd,
|
|
100
|
+
messages: [message],
|
|
101
|
+
payment: invDetails.payment,
|
|
102
|
+
tokens: invDetails.tokens / [control, remote].length,
|
|
103
|
+
total_mtokens: invDetails.mtokens,
|
|
104
|
+
});
|
|
131
105
|
|
|
132
|
-
const
|
|
133
|
-
|
|
134
|
-
|
|
106
|
+
const remoteToTarget = await getRouteToDestination({
|
|
107
|
+
destination: target.id,
|
|
108
|
+
features: invDetails.features,
|
|
109
|
+
lnd: remote.lnd,
|
|
110
|
+
messages: [message],
|
|
111
|
+
payment: invDetails.payment,
|
|
112
|
+
tokens: invDetails.tokens / [control, remote].length,
|
|
113
|
+
total_mtokens: invDetails.mtokens,
|
|
135
114
|
});
|
|
136
115
|
|
|
137
|
-
|
|
116
|
+
try {
|
|
117
|
+
const [controlPay, remotePay] = await all([
|
|
118
|
+
payViaRoutes({
|
|
119
|
+
id: invDetails.id,
|
|
120
|
+
lnd: control.lnd,
|
|
121
|
+
routes: [controlToTarget.route],
|
|
122
|
+
}),
|
|
123
|
+
payViaRoutes({
|
|
124
|
+
id: invDetails.id,
|
|
125
|
+
lnd: remote.lnd,
|
|
126
|
+
routes: [remoteToTarget.route],
|
|
127
|
+
}),
|
|
128
|
+
]);
|
|
129
|
+
|
|
130
|
+
strictEqual(controlPay.secret, inv.secret, 'Control paid for secret');
|
|
131
|
+
strictEqual(remotePay.secret, inv.secret, 'Remote paid for secret');
|
|
132
|
+
|
|
133
|
+
const {payments} = await getInvoice({
|
|
134
|
+
id: invDetails.id,
|
|
135
|
+
lnd: target.lnd,
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
const [payment1, payment2] = payments;
|
|
138
139
|
|
|
139
|
-
|
|
140
|
-
|
|
140
|
+
const [message1] = payment1.messages;
|
|
141
|
+
const [message2] = payment2.messages;
|
|
141
142
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
143
|
+
deepStrictEqual(message1, message, 'Target received message');
|
|
144
|
+
deepStrictEqual(message2, message, 'Target received both messages');
|
|
145
|
+
} catch (err) {
|
|
146
|
+
strictEqual(err, null, 'Unexpected error paying invoice');
|
|
147
|
+
}
|
|
147
148
|
|
|
148
|
-
|
|
149
|
+
await kill({});
|
|
150
|
+
});
|
|
149
151
|
|
|
150
152
|
return;
|
|
151
153
|
});
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
const {equal} = require('node:assert').strict;
|
|
2
|
+
const test = require('node:test');
|
|
3
|
+
|
|
4
|
+
const asyncRetry = require('async/retry');
|
|
5
|
+
const {setupChannel} = require('ln-docker-daemons');
|
|
6
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
7
|
+
|
|
8
|
+
const {addPeer} = require('./../../');
|
|
9
|
+
const {createInvoice} = require('./../../');
|
|
10
|
+
const {decodePaymentRequest} = require('./../../');
|
|
11
|
+
const {getHeight} = require('./../../');
|
|
12
|
+
const {getChannel} = require('./../../');
|
|
13
|
+
const {getNode} = require('./../../');
|
|
14
|
+
const {getRouteThroughHops} = require('./../../');
|
|
15
|
+
const {getRouteToDestination} = require('./../../');
|
|
16
|
+
const {getWalletInfo} = require('./../../');
|
|
17
|
+
const {payViaRoutes} = require('./../../');
|
|
18
|
+
const {routeFromChannels} = require('./../../');
|
|
19
|
+
const {updateRoutingFees} = require('./../../');
|
|
20
|
+
const {waitForRoute} = require('./../macros');
|
|
21
|
+
|
|
22
|
+
const baseFee = '1000';
|
|
23
|
+
const confirmationCount = 6;
|
|
24
|
+
const discount = '1000';
|
|
25
|
+
const interval = 10;
|
|
26
|
+
const size = 5;
|
|
27
|
+
const times = 1000;
|
|
28
|
+
const tokens = 100;
|
|
29
|
+
|
|
30
|
+
// Calculating a route from complex channels set should result in a route
|
|
31
|
+
test(`Get route through complex hops`, async () => {
|
|
32
|
+
const {kill, nodes} = await spawnLightningCluster({size});
|
|
33
|
+
|
|
34
|
+
try {
|
|
35
|
+
const [{generate, lnd}, target, remote, far, farthest] = nodes;
|
|
36
|
+
|
|
37
|
+
const controlToTargetChan = await setupChannel({
|
|
38
|
+
generate,
|
|
39
|
+
lnd,
|
|
40
|
+
to: target,
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
await generate({});
|
|
44
|
+
|
|
45
|
+
const targetRemoteChannel = await asyncRetry({
|
|
46
|
+
interval,
|
|
47
|
+
times,
|
|
48
|
+
},
|
|
49
|
+
async () => {
|
|
50
|
+
await generate({});
|
|
51
|
+
|
|
52
|
+
await addPeer({
|
|
53
|
+
lnd: target.lnd,
|
|
54
|
+
public_key: remote.id,
|
|
55
|
+
socket: remote.socket,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return await setupChannel({
|
|
59
|
+
generate: target.generate,
|
|
60
|
+
lnd: target.lnd,
|
|
61
|
+
to: remote,
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
await generate({});
|
|
66
|
+
|
|
67
|
+
const remoteFarChannel = await asyncRetry({interval, times}, async () => {
|
|
68
|
+
await generate({});
|
|
69
|
+
|
|
70
|
+
await addPeer({lnd: remote.lnd, public_key: far.id, socket: far.socket});
|
|
71
|
+
|
|
72
|
+
return await setupChannel({
|
|
73
|
+
generate: remote.generate,
|
|
74
|
+
lnd: remote.lnd,
|
|
75
|
+
to: far,
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
await target.generate({count: confirmationCount});
|
|
80
|
+
|
|
81
|
+
const farFarthestChannel = await asyncRetry({
|
|
82
|
+
interval,
|
|
83
|
+
times,
|
|
84
|
+
},
|
|
85
|
+
async () => {
|
|
86
|
+
await generate({});
|
|
87
|
+
|
|
88
|
+
await addPeer({
|
|
89
|
+
lnd: far.lnd,
|
|
90
|
+
public_key: farthest.id,
|
|
91
|
+
socket: farthest.socket,
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
return await setupChannel({
|
|
95
|
+
generate: far.generate,
|
|
96
|
+
lnd: far.lnd,
|
|
97
|
+
to: farthest,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
await target.generate({count: confirmationCount});
|
|
102
|
+
|
|
103
|
+
await asyncRetry({interval, times}, async () => {
|
|
104
|
+
const wallet = await getWalletInfo({lnd: remote.lnd});
|
|
105
|
+
|
|
106
|
+
await addPeer({lnd, public_key: remote.id, socket: remote.socket});
|
|
107
|
+
|
|
108
|
+
if (!wallet.is_synced_to_chain) {
|
|
109
|
+
throw new Error('ExpectedWalletSyncedToChain');
|
|
110
|
+
}
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
await asyncRetry({interval, times}, async () => {
|
|
114
|
+
const wallet = await getWalletInfo({lnd: far.lnd});
|
|
115
|
+
|
|
116
|
+
await addPeer({lnd, public_key: far.id, socket: far.socket});
|
|
117
|
+
|
|
118
|
+
if (!wallet.is_synced_to_chain) {
|
|
119
|
+
throw new Error('ExpectedWalletSyncedToChain');
|
|
120
|
+
}
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
await asyncRetry({interval, times}, async () => {
|
|
124
|
+
const wallet = await getWalletInfo({lnd: farthest.lnd});
|
|
125
|
+
|
|
126
|
+
await addPeer({lnd, public_key: farthest.id, socket: farthest.socket});
|
|
127
|
+
|
|
128
|
+
if (!wallet.is_synced_to_chain) {
|
|
129
|
+
throw new Error('ExpectedWalletSyncedToChain');
|
|
130
|
+
}
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
await asyncRetry({interval, times}, async () => {
|
|
134
|
+
await getNode({lnd, public_key: remote.id});
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
await asyncRetry({interval, times}, async () => {
|
|
138
|
+
const {features} = await getNode({lnd, public_key: far.id});
|
|
139
|
+
|
|
140
|
+
if (!features.length) {
|
|
141
|
+
throw new Error('ExpectedFarFeatures');
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
await asyncRetry({interval, times}, async () => {
|
|
146
|
+
const {features} = await getNode({lnd, public_key: farthest.id});
|
|
147
|
+
|
|
148
|
+
if (!features.length) {
|
|
149
|
+
throw new Error('ExpectedFarthestFeatures');
|
|
150
|
+
}
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const invoice = await createInvoice({
|
|
154
|
+
tokens,
|
|
155
|
+
cltv_delta: 50,
|
|
156
|
+
lnd: farthest.lnd,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const {id} = invoice;
|
|
160
|
+
const {request} = invoice;
|
|
161
|
+
|
|
162
|
+
const decodedRequest = await decodePaymentRequest({lnd, request});
|
|
163
|
+
|
|
164
|
+
await waitForRoute({
|
|
165
|
+
lnd,
|
|
166
|
+
destination: farthest.id,
|
|
167
|
+
tokens: invoice.tokens,
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const {route} = await asyncRetry({interval, times}, async () => {
|
|
171
|
+
return await getRouteToDestination({
|
|
172
|
+
lnd,
|
|
173
|
+
cltv_delta: decodedRequest.cltv_delta,
|
|
174
|
+
destination: decodedRequest.destination,
|
|
175
|
+
tokens: invoice.tokens,
|
|
176
|
+
});
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const policyAStart = await getChannel({lnd, id: controlToTargetChan.id});
|
|
180
|
+
const policyBStart = await getChannel({lnd, id: targetRemoteChannel.id});
|
|
181
|
+
const policyCStart = await getChannel({lnd, id: remoteFarChannel.id});
|
|
182
|
+
const policyDStart = await getChannel({lnd, id: farFarthestChannel.id});
|
|
183
|
+
|
|
184
|
+
await updateRoutingFees({
|
|
185
|
+
cltv_delta: 200,
|
|
186
|
+
lnd: target.lnd,
|
|
187
|
+
transaction_id: targetRemoteChannel.transaction_id,
|
|
188
|
+
transaction_vout: targetRemoteChannel.transaction_vout,
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
await updateRoutingFees({
|
|
192
|
+
cltv_delta: 200,
|
|
193
|
+
lnd: remote.lnd,
|
|
194
|
+
transaction_id: targetRemoteChannel.transaction_id,
|
|
195
|
+
transaction_vout: targetRemoteChannel.transaction_vout,
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
await updateRoutingFees({
|
|
199
|
+
cltv_delta: 100,
|
|
200
|
+
inbound_base_discount_mtokens: discount,
|
|
201
|
+
lnd: target.lnd,
|
|
202
|
+
transaction_id: controlToTargetChan.transaction_id,
|
|
203
|
+
transaction_vout: controlToTargetChan.transaction_vout,
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
await updateRoutingFees({
|
|
207
|
+
cltv_delta: 300,
|
|
208
|
+
lnd: far.lnd,
|
|
209
|
+
transaction_id: remoteFarChannel.transaction_id,
|
|
210
|
+
transaction_vout: remoteFarChannel.transaction_vout,
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
await updateRoutingFees({
|
|
214
|
+
cltv_delta: 400,
|
|
215
|
+
lnd: remote.lnd,
|
|
216
|
+
transaction_id: remoteFarChannel.transaction_id,
|
|
217
|
+
transaction_vout: remoteFarChannel.transaction_vout,
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// Control updates their routing policy
|
|
221
|
+
await updateRoutingFees({
|
|
222
|
+
lnd,
|
|
223
|
+
cltv_delta: 100,
|
|
224
|
+
transaction_id: controlToTargetChan.transaction_id,
|
|
225
|
+
transaction_vout: controlToTargetChan.transaction_vout,
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
await updateRoutingFees({
|
|
229
|
+
cltv_delta: 500,
|
|
230
|
+
lnd: far.lnd,
|
|
231
|
+
transaction_id: farFarthestChannel.transaction_id,
|
|
232
|
+
transaction_vout: farFarthestChannel.transaction_vout,
|
|
233
|
+
});
|
|
234
|
+
|
|
235
|
+
await updateRoutingFees({
|
|
236
|
+
cltv_delta: 100,
|
|
237
|
+
lnd: farthest.lnd,
|
|
238
|
+
transaction_id: farFarthestChannel.transaction_id,
|
|
239
|
+
transaction_vout: farFarthestChannel.transaction_vout,
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
// Wait for policy to be updated
|
|
243
|
+
const policyA = await asyncRetry({interval, times}, async () => {
|
|
244
|
+
const policy = await getChannel({lnd, id: controlToTargetChan.id});
|
|
245
|
+
|
|
246
|
+
if (policy.updated_at === policyAStart.updated_at) {
|
|
247
|
+
throw new Error('PolicyNotUpdatedYet');
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return policy;
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
// A discount should be set for traffic from control to remote
|
|
254
|
+
const discountFee = policyA.policies.find(n => n.public_key === target.id);
|
|
255
|
+
|
|
256
|
+
// Wait for policy to be updated
|
|
257
|
+
const policyB = await asyncRetry({interval, times}, async () => {
|
|
258
|
+
const policy = await getChannel({lnd, id: targetRemoteChannel.id});
|
|
259
|
+
|
|
260
|
+
if (policy.updated_at === policyBStart.updated_at) {
|
|
261
|
+
throw new Error('PolicyNotUpdatedYet');
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
return policy;
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// Wait for policy to be updated
|
|
268
|
+
const policyC = await asyncRetry({interval, times}, async () => {
|
|
269
|
+
const policy = await getChannel({lnd, id: remoteFarChannel.id});
|
|
270
|
+
|
|
271
|
+
if (policy.updated_at === policyCStart.updated_at) {
|
|
272
|
+
throw new Error('PolicyNotUpdatedYet');
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
return policy;
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
const policyD = await asyncRetry({interval, times}, async () => {
|
|
279
|
+
const policy = await getChannel({lnd, id: farFarthestChannel.id});
|
|
280
|
+
|
|
281
|
+
if (policy.updated_at === policyDStart.updated_at) {
|
|
282
|
+
throw new Error('PolicyNotUpdatedYet');
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
return policy;
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
const channelsRoute = routeFromChannels({
|
|
289
|
+
channels: [policyA, policyB, policyC, policyD],
|
|
290
|
+
cltv_delta: decodedRequest.cltv_delta + confirmationCount,
|
|
291
|
+
destination: decodedRequest.destination,
|
|
292
|
+
height: (await getHeight({lnd})).current_block_height,
|
|
293
|
+
mtokens: decodedRequest.mtokens,
|
|
294
|
+
payment: decodedRequest.payment,
|
|
295
|
+
total_mtokens: decodedRequest.mtokens,
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
const lndRoute = await getRouteThroughHops({
|
|
299
|
+
lnd,
|
|
300
|
+
cltv_delta: decodedRequest.cltv_delta + confirmationCount,
|
|
301
|
+
mtokens: decodedRequest.mtokens,
|
|
302
|
+
payment: decodedRequest.payment,
|
|
303
|
+
public_keys: [target.id, remote.id, far.id, farthest.id],
|
|
304
|
+
total_mtokens: decodedRequest.mtokens,
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const discounted = BigInt(discountFee.inbound_base_discount_mtokens);
|
|
308
|
+
|
|
309
|
+
const gotTotalFee = BigInt(channelsRoute.route.fee_mtokens);
|
|
310
|
+
|
|
311
|
+
await payViaRoutes({lnd, id: invoice.id, routes: [channelsRoute.route]});
|
|
312
|
+
|
|
313
|
+
equal(gotTotalFee, BigInt(baseFee * 2), 'Got expected discount');
|
|
314
|
+
|
|
315
|
+
await kill({});
|
|
316
|
+
} catch (err) {
|
|
317
|
+
await kill({});
|
|
318
|
+
|
|
319
|
+
equal(err, null, 'Expected no error');
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
return;
|
|
323
|
+
});
|
|
@@ -64,7 +64,11 @@ test(`Get route through hops`, async () => {
|
|
|
64
64
|
}
|
|
65
65
|
});
|
|
66
66
|
|
|
67
|
-
const invoice = await createInvoice({
|
|
67
|
+
const invoice = await createInvoice({
|
|
68
|
+
tokens,
|
|
69
|
+
cltv_delta: 60,
|
|
70
|
+
lnd: remote.lnd,
|
|
71
|
+
});
|
|
68
72
|
|
|
69
73
|
const {id} = invoice;
|
|
70
74
|
const {request} = invoice;
|
|
@@ -122,6 +126,15 @@ test(`Get route through hops`, async () => {
|
|
|
122
126
|
total_mtokens: decodedRequest.mtokens,
|
|
123
127
|
});
|
|
124
128
|
|
|
129
|
+
const lndRoute = await getRouteThroughHops({
|
|
130
|
+
lnd,
|
|
131
|
+
cltv_delta: decodedRequest.cltv_delta + confirmationCount,
|
|
132
|
+
mtokens: decodedRequest.mtokens,
|
|
133
|
+
payment: decodedRequest.payment,
|
|
134
|
+
public_keys: [target.id, remote.id],
|
|
135
|
+
total_mtokens: decodedRequest.mtokens,
|
|
136
|
+
});
|
|
137
|
+
|
|
125
138
|
const discounted = BigInt(discountFee.inbound_base_discount_mtokens);
|
|
126
139
|
|
|
127
140
|
const gotTotalFee = BigInt(channelsRoute.route.fee_mtokens);
|
|
@@ -133,4 +146,4 @@ test(`Get route through hops`, async () => {
|
|
|
133
146
|
equal(gotTotalFee, BigInt(baseFee) - discounted, 'Got expected discount');
|
|
134
147
|
|
|
135
148
|
return;
|
|
136
|
-
});
|
|
149
|
+
});
|