ln-service 54.1.2 → 54.2.1
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 +12 -0
- package/README.md +12 -5
- package/package.json +5 -17
- package/test/chainrpc-integration/test_subscribe_to_blocks.js +1 -1
- package/test/integration/test_grant_access.js +6 -20
- package/test/integration/test_open_channel.js +32 -1
- package/test/integration/test_open_channels.js +18 -0
- package/test/integration/test_recover_funds_from_channel.js +196 -0
- package/test/integration/test_recover_funds_from_channels.js +198 -0
- package/test/macros/change_password.js +1 -1
- package/test/routerrpc-integration/test_subscribe_to_payments.js +1 -1
- package/test/walletrpc-integration/test_broadcast_chain_transaction.js +35 -32
- package/test/walletrpc-integration/test_request_chain_fee_increase.js +22 -33
- package/test/extra-integration/test_recover_funds_from_channel.js +0 -85
- package/test/extra-integration/test_recover_funds_from_channels.js +0 -112
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 54.2.1
|
|
4
|
+
|
|
5
|
+
- `getWalletInfo`: Add support for LND 0.15.2
|
|
6
|
+
|
|
7
|
+
- Due to LND chain sync failure prior to LND 0.15.2, those versions are no
|
|
8
|
+
longer supported
|
|
9
|
+
|
|
10
|
+
## 54.2.0
|
|
11
|
+
|
|
12
|
+
- `openChannel`, `openChannels`: Add `base_fee_mtokens`, `fee_rate` to set
|
|
13
|
+
initial routing fee rate.
|
|
14
|
+
|
|
3
15
|
## 54.1.2
|
|
4
16
|
|
|
5
17
|
- `subscribeToRpcRequests`: Fix support for LND 0.15.1
|
package/README.md
CHANGED
|
@@ -9,10 +9,7 @@ through npm.
|
|
|
9
9
|
|
|
10
10
|
Supported LND versions:
|
|
11
11
|
|
|
12
|
-
- v0.15.
|
|
13
|
-
- v0.14.0-beta to v0.14.3-beta
|
|
14
|
-
- v0.13.0-beta to v0.13.4-beta
|
|
15
|
-
- v0.12.0-beta to v0.12.1-beta
|
|
12
|
+
- v0.15.2-beta
|
|
16
13
|
|
|
17
14
|
For typescript-ready methods, check out https://github.com/alexbosworth/lightning#readme
|
|
18
15
|
|
|
@@ -3571,9 +3568,14 @@ If give_tokens is set, it is a gift and it does not alter the capacity
|
|
|
3571
3568
|
|
|
3572
3569
|
Requires `offchain:write`, `onchain:write`, `peers:write` permissions
|
|
3573
3570
|
|
|
3571
|
+
`base_fee_mtokens` is not supported on LND 0.15.3 and below
|
|
3572
|
+
`fee_rate` is not supported on LND 0.15.3 and below
|
|
3573
|
+
|
|
3574
3574
|
{
|
|
3575
|
+
[base_fee_mtokens]: <Routing Base Fee Millitokens Charged String>
|
|
3575
3576
|
[chain_fee_tokens_per_vbyte]: <Chain Fee Tokens Per VByte Number>
|
|
3576
3577
|
[cooperative_close_address]: <Restrict Cooperative Close To Address String>
|
|
3578
|
+
[fee_rate]: <Routing Fee Rate In Millitokens Per Million Number>
|
|
3577
3579
|
[give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
|
|
3578
3580
|
[is_private]: <Channel is Private Bool> // Defaults to false
|
|
3579
3581
|
lnd: <Authenticated LND API Object>
|
|
@@ -3619,10 +3621,15 @@ after the funding step.
|
|
|
3619
3621
|
`--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
|
|
3620
3622
|
as well as a channel open request listener to accept the trusted funding.
|
|
3621
3623
|
|
|
3624
|
+
`base_fee_mtokens` is not supported on LND 0.15.3 and below
|
|
3625
|
+
`fee_rate` is not supported on LND 0.15.3 and below
|
|
3626
|
+
|
|
3622
3627
|
{
|
|
3623
3628
|
channels: [{
|
|
3629
|
+
[base_fee_mtokens]: <Routing Base Fee Millitokens Charged String>
|
|
3624
3630
|
capacity: <Channel Capacity Tokens Number>
|
|
3625
3631
|
[cooperative_close_address]: <Restrict Coop Close To Address String>
|
|
3632
|
+
[fee_rate]: <Routing Fee Rate In Millitokens Per Million Number>
|
|
3626
3633
|
[give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
|
|
3627
3634
|
[is_private]: <Channel is Private Bool> // Defaults to false
|
|
3628
3635
|
[is_trusted_funding]: <Peer Should Avoid Waiting For Confirmation Bool>
|
|
@@ -6261,7 +6268,7 @@ Subscribe to outgoing payments
|
|
|
6261
6268
|
|
|
6262
6269
|
Requires `offchain:read` permission
|
|
6263
6270
|
|
|
6264
|
-
Note: Method not supported on LND 0.15.
|
|
6271
|
+
Note: Method not supported on LND 0.15.3 and below
|
|
6265
6272
|
|
|
6266
6273
|
{
|
|
6267
6274
|
lnd: <Authenticated LND API Object>
|
package/package.json
CHANGED
|
@@ -9,9 +9,9 @@
|
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"bolt07": "1.8.2",
|
|
11
11
|
"cors": "2.8.5",
|
|
12
|
-
"express": "4.18.
|
|
12
|
+
"express": "4.18.2",
|
|
13
13
|
"invoices": "2.2.0",
|
|
14
|
-
"lightning": "6.
|
|
14
|
+
"lightning": "6.2.2",
|
|
15
15
|
"macaroon": "3.0.4",
|
|
16
16
|
"morgan": "1.10.0",
|
|
17
17
|
"ws": "8.9.0"
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"bn.js": "5.2.1",
|
|
29
29
|
"bs58check": "2.1.2",
|
|
30
30
|
"ecpair": "2.1.0",
|
|
31
|
-
"ln-docker-daemons": "3.
|
|
31
|
+
"ln-docker-daemons": "3.1.1",
|
|
32
32
|
"p2tr": "1.3.2",
|
|
33
33
|
"portfinder": "1.0.32",
|
|
34
34
|
"psbt": "2.7.1",
|
|
@@ -56,20 +56,8 @@
|
|
|
56
56
|
"url": "https://github.com/alexbosworth/ln-service.git"
|
|
57
57
|
},
|
|
58
58
|
"scripts": {
|
|
59
|
-
"integration-test-0.15.
|
|
60
|
-
"integration-test-0.15.0": "DOCKER_LND_VERSION=v0.15.0-beta npm run test",
|
|
61
|
-
"integration-test-0.14.3": "DOCKER_LND_VERSION=v0.14.3-beta npm run test",
|
|
62
|
-
"integration-test-0.14.2": "DOCKER_LND_VERSION=v0.14.2-beta npm run test",
|
|
63
|
-
"integration-test-0.14.1": "DOCKER_LND_VERSION=v0.14.1-beta npm run test",
|
|
64
|
-
"integration-test-0.14.0": "DOCKER_LND_VERSION=v0.14.0-beta npm run test",
|
|
65
|
-
"integration-test-0.13.4": "DOCKER_LND_VERSION=v0.13.4-beta npm run test",
|
|
66
|
-
"integration-test-0.13.3": "DOCKER_LND_VERSION=v0.13.3-beta npm run test",
|
|
67
|
-
"integration-test-0.13.2": "DOCKER_LND_VERSION=v0.13.2-beta npm run test",
|
|
68
|
-
"integration-test-0.13.1": "DOCKER_LND_VERSION=v0.13.1-beta npm run test",
|
|
69
|
-
"integration-test-0.13.0": "DOCKER_LND_VERSION=v0.13.0-beta npm run test",
|
|
70
|
-
"integration-test-0.12.1": "DOCKER_LND_VERSION=v0.12.1-beta npm run test",
|
|
71
|
-
"integration-test-0.12.0": "DOCKER_LND_VERSION=v0.12.0-beta npm run test",
|
|
59
|
+
"integration-test-0.15.2": "DOCKER_LND_VERSION=v0.15.2-beta npm run test",
|
|
72
60
|
"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/peersrpc-integration/*.js test/routerrpc-integration/*.js test/signerrpc-integration/*.js test/tower_clientrpc-integration/*.js test/tower_serverrpc-integration/*.js test/walletrpc-integration/*.js"
|
|
73
61
|
},
|
|
74
|
-
"version": "54.1
|
|
62
|
+
"version": "54.2.1"
|
|
75
63
|
}
|
|
@@ -14,7 +14,7 @@ const {subscribeToBlocks} = require('./../../');
|
|
|
14
14
|
const {waitForTermination} = require('./../macros');
|
|
15
15
|
|
|
16
16
|
const confirmationCount = 6;
|
|
17
|
-
const interval =
|
|
17
|
+
const interval = 10;
|
|
18
18
|
const race = promises => Promise.race(promises);
|
|
19
19
|
const times = 4000;
|
|
20
20
|
|
|
@@ -1,19 +1,15 @@
|
|
|
1
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
1
2
|
const {test} = require('@alexbosworth/tap');
|
|
2
3
|
|
|
3
|
-
const {authenticatedLndGrpc} = require('./../../');
|
|
4
4
|
const {createChainAddress} = require('./../../');
|
|
5
5
|
const {getWalletVersion} = require('./../../');
|
|
6
6
|
const {grantAccess} = require('./../../');
|
|
7
|
-
const {spawnLnd} = require('./../macros');
|
|
8
|
-
const {waitForTermination} = require('./../macros');
|
|
9
7
|
|
|
10
8
|
const format = 'np2wpkh';
|
|
11
9
|
|
|
12
10
|
// Granting access should result in access granted
|
|
13
11
|
test(`Get access credentials`, async ({end, equal, rejects, strictSame}) => {
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
const {lnd, kill} = spawned;
|
|
12
|
+
const [{lnd, kill, rpc}] = (await spawnLightningCluster({})).nodes;
|
|
17
13
|
|
|
18
14
|
await grantAccess({lnd, is_ok_to_create_chain_addresses: true});
|
|
19
15
|
|
|
@@ -27,17 +23,11 @@ test(`Get access credentials`, async ({end, equal, rejects, strictSame}) => {
|
|
|
27
23
|
|
|
28
24
|
strictSame(makeChainAddresses.permissions, permissions, 'Got permissions');
|
|
29
25
|
|
|
30
|
-
const canPay =
|
|
31
|
-
cert: spawned.lnd_cert,
|
|
26
|
+
const canPay = rpc({
|
|
32
27
|
macaroon: (await grantAccess({lnd, is_ok_to_pay: true})).macaroon,
|
|
33
|
-
socket: `localhost:${spawned.rpc_port}`,
|
|
34
28
|
});
|
|
35
29
|
|
|
36
|
-
const makeAddress =
|
|
37
|
-
cert: spawned.lnd_cert,
|
|
38
|
-
macaroon: makeChainAddresses.macaroon,
|
|
39
|
-
socket: `localhost:${spawned.rpc_port}`,
|
|
40
|
-
});
|
|
30
|
+
const makeAddress = rpc({macaroon: makeChainAddresses.macaroon});
|
|
41
31
|
|
|
42
32
|
await rejects(
|
|
43
33
|
grantAccess({lnd: makeAddress.lnd, is_ok_to_create_chain_addresses: true}),
|
|
@@ -64,10 +54,8 @@ test(`Get access credentials`, async ({end, equal, rejects, strictSame}) => {
|
|
|
64
54
|
methods: ['createChainAddress'],
|
|
65
55
|
});
|
|
66
56
|
|
|
67
|
-
const authenticatedToCreateAddress =
|
|
68
|
-
cert: spawned.lnd_cert,
|
|
57
|
+
const authenticatedToCreateAddress = rpc({
|
|
69
58
|
macaroon: createChainAddressCredential.macaroon,
|
|
70
|
-
socket: `localhost:${spawned.rpc_port}`,
|
|
71
59
|
});
|
|
72
60
|
|
|
73
61
|
const created = await createChainAddress({
|
|
@@ -78,9 +66,7 @@ test(`Get access credentials`, async ({end, equal, rejects, strictSame}) => {
|
|
|
78
66
|
equal(!!created, true, 'Can make address with URI credential');
|
|
79
67
|
}
|
|
80
68
|
|
|
81
|
-
kill();
|
|
82
|
-
|
|
83
|
-
await waitForTermination({lnd});
|
|
69
|
+
await kill({});
|
|
84
70
|
|
|
85
71
|
return end();
|
|
86
72
|
});
|
|
@@ -5,12 +5,17 @@ const {test} = require('@alexbosworth/tap');
|
|
|
5
5
|
const {addPeer} = require('./../../');
|
|
6
6
|
const {createChainAddress} = require('./../../');
|
|
7
7
|
const {getChainBalance} = require('./../../');
|
|
8
|
+
const {getChannel} = require('./../../');
|
|
9
|
+
const {getChannels} = require('./../../');
|
|
8
10
|
const {openChannel} = require('./../../');
|
|
9
11
|
|
|
12
|
+
const baseFee = '1337';
|
|
10
13
|
const channelCapacityTokens = 1e6;
|
|
11
14
|
const count = 100;
|
|
15
|
+
const defaultBaseFee = '1000';
|
|
12
16
|
const defaultFee = 1e3;
|
|
13
17
|
const defaultVout = 0;
|
|
18
|
+
const feeRate = 420;
|
|
14
19
|
const giftTokens = 1000;
|
|
15
20
|
const interval = 250;
|
|
16
21
|
const size = 2;
|
|
@@ -21,7 +26,7 @@ const txIdHexLength = 32 * 2;
|
|
|
21
26
|
test(`Open channel`, async ({end, equal}) => {
|
|
22
27
|
const {kill, nodes} = await spawnLightningCluster({size});
|
|
23
28
|
|
|
24
|
-
const [{generate, lnd}, target] = nodes;
|
|
29
|
+
const [{generate, id, lnd}, target] = nodes;
|
|
25
30
|
|
|
26
31
|
const {address} = await createChainAddress({lnd});
|
|
27
32
|
|
|
@@ -32,8 +37,10 @@ test(`Open channel`, async ({end, equal}) => {
|
|
|
32
37
|
|
|
33
38
|
return await openChannel({
|
|
34
39
|
lnd,
|
|
40
|
+
base_fee_mtokens: baseFee,
|
|
35
41
|
chain_fee_tokens_per_vbyte: defaultFee,
|
|
36
42
|
cooperative_close_address: address,
|
|
43
|
+
fee_rate: feeRate,
|
|
37
44
|
give_tokens: giftTokens,
|
|
38
45
|
local_tokens: channelCapacityTokens,
|
|
39
46
|
partner_public_key: target.id,
|
|
@@ -44,6 +51,30 @@ test(`Open channel`, async ({end, equal}) => {
|
|
|
44
51
|
equal(channelOpen.transaction_id.length, txIdHexLength, 'Channel tx id');
|
|
45
52
|
equal(channelOpen.transaction_vout, defaultVout, 'Channel tx output index');
|
|
46
53
|
|
|
54
|
+
await asyncRetry({interval, times}, async () => {
|
|
55
|
+
await generate({});
|
|
56
|
+
|
|
57
|
+
const {channels} = await getChannels({lnd});
|
|
58
|
+
|
|
59
|
+
const [channel] = channels;
|
|
60
|
+
|
|
61
|
+
if (!channel) {
|
|
62
|
+
throw new Error('ExpectedChannelOpened');
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const {policies} = await getChannel({lnd, id: channel.id});
|
|
66
|
+
|
|
67
|
+
const policy = policies.find(n => n.public_key === id);
|
|
68
|
+
|
|
69
|
+
// LND 0.15.3 and below do not support setting fees on open
|
|
70
|
+
if (policy.base_fee_mtokens === defaultBaseFee) {
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
equal(policy.base_fee_mtokens, baseFee, 'Base fee is set');
|
|
75
|
+
equal(policy.fee_rate, feeRate, 'Fee rate is set');
|
|
76
|
+
});
|
|
77
|
+
|
|
47
78
|
await kill({});
|
|
48
79
|
|
|
49
80
|
return end();
|
|
@@ -13,15 +13,19 @@ const {delay} = require('./../macros');
|
|
|
13
13
|
const {fundPendingChannels} = require('./../../');
|
|
14
14
|
const {getChainBalance} = require('./../../');
|
|
15
15
|
const {getChainTransactions} = require('./../../');
|
|
16
|
+
const {getChannel} = require('./../../');
|
|
16
17
|
const {getChannels} = require('./../../');
|
|
17
18
|
const {getHeight} = require('./../../');
|
|
18
19
|
const {getPeers} = require('./../../');
|
|
19
20
|
const {openChannels} = require('./../../');
|
|
20
21
|
const {sendToChainAddresses} = require('./../../');
|
|
21
22
|
|
|
23
|
+
const baseFeeMtokens = '1234';
|
|
22
24
|
const capacity = 1e6;
|
|
23
25
|
const count = 10;
|
|
26
|
+
const defaultBaseFee = '1000';
|
|
24
27
|
const interval = 10;
|
|
28
|
+
const feeRate = 56;
|
|
25
29
|
const maturity = 100;
|
|
26
30
|
const race = promises => Promise.race(promises);
|
|
27
31
|
const size = 3;
|
|
@@ -61,7 +65,9 @@ test(`Open channels`, async ({end, equal}) => {
|
|
|
61
65
|
|
|
62
66
|
const channels = [target, remote].map(({id}) => ({
|
|
63
67
|
capacity,
|
|
68
|
+
base_fee_mtokens: baseFeeMtokens,
|
|
64
69
|
cooperative_close_address: address,
|
|
70
|
+
fee_rate: feeRate,
|
|
65
71
|
partner_public_key: id,
|
|
66
72
|
}));
|
|
67
73
|
|
|
@@ -129,6 +135,18 @@ test(`Open channels`, async ({end, equal}) => {
|
|
|
129
135
|
|
|
130
136
|
equal(channel.cooperative_close_address, address, 'Channel close addr');
|
|
131
137
|
|
|
138
|
+
const {policies} = await getChannel({lnd, id: channel.id});
|
|
139
|
+
|
|
140
|
+
const policy = policies.find(n => !!n.cltv_delta);
|
|
141
|
+
|
|
142
|
+
// LND 0.15.3 and below do not support setting fees on open
|
|
143
|
+
if (policy.base_fee_mtokens === defaultBaseFee) {
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
equal(policy.base_fee_mtokens, baseFeeMtokens, 'Base fee is set');
|
|
148
|
+
equal(policy.fee_rate, feeRate, 'Fee rate is set');
|
|
149
|
+
|
|
132
150
|
return;
|
|
133
151
|
});
|
|
134
152
|
} catch (err) {
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
const asyncRetry = require('async/retry');
|
|
2
|
+
const {getPortPromise: getPort} = require('portfinder');
|
|
3
|
+
const {setupChannel} = require('ln-docker-daemons');
|
|
4
|
+
const {spawnLightningDocker} = require('ln-docker-daemons');
|
|
5
|
+
const {test} = require('@alexbosworth/tap');
|
|
6
|
+
|
|
7
|
+
const {addPeer} = require('./../../');
|
|
8
|
+
const {authenticatedLndGrpc} = require('./../../');
|
|
9
|
+
const {createChainAddress} = require('./../../');
|
|
10
|
+
const {getBackup} = require('./../../');
|
|
11
|
+
const {getIdentity} = require('./../../');
|
|
12
|
+
const {getPendingChannels} = require('./../../');
|
|
13
|
+
const {getUtxos} = require('./../../');
|
|
14
|
+
const {recoverFundsFromChannel} = require('./../../');
|
|
15
|
+
|
|
16
|
+
const confirmationCount = 20;
|
|
17
|
+
const generateAddress = '2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF';
|
|
18
|
+
const giftTokens = 1e5;
|
|
19
|
+
const interval = 10;
|
|
20
|
+
const makeAddress = ({lnd}) => createChainAddress({lnd});
|
|
21
|
+
const maturity = 100;
|
|
22
|
+
const seed = 'about rabbit ozone hope jaguar quit scare twenty punch crisp consider clutch ring frost universe okay execute shrug drink notice abandon wine denial retreat';
|
|
23
|
+
const times = 3000;
|
|
24
|
+
|
|
25
|
+
// Using a channel backup should recover funds
|
|
26
|
+
test(`Recover funds from channel`, async ({end, equal}) => {
|
|
27
|
+
const control = await spawnLightningDocker({
|
|
28
|
+
seed,
|
|
29
|
+
chain_p2p_port: await getPort({port: 8000, stopPort: 9000}),
|
|
30
|
+
chain_rpc_port: await getPort({port: 9001, stopPort: 10000}),
|
|
31
|
+
chain_zmq_block_port: await getPort({port: 10001, stopPort: 11000}),
|
|
32
|
+
chain_zmq_tx_port: await getPort({port: 11001, stopPort: 12000}),
|
|
33
|
+
generate_address: generateAddress,
|
|
34
|
+
lightning_p2p_port: await getPort({port: 12001, stopPort: 13000}),
|
|
35
|
+
lightning_rpc_port: await getPort({port: 13001, stopPort: 14000}),
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
const target = await spawnLightningDocker({
|
|
39
|
+
chain_p2p_port: await getPort({port: 8000, stopPort: 9000}),
|
|
40
|
+
chain_rpc_port: await getPort({port: 9001, stopPort: 10000}),
|
|
41
|
+
chain_zmq_block_port: await getPort({port: 10001, stopPort: 11000}),
|
|
42
|
+
chain_zmq_tx_port: await getPort({port: 11001, stopPort: 12000}),
|
|
43
|
+
generate_address: generateAddress,
|
|
44
|
+
lightning_p2p_port: await getPort({port: 12001, stopPort: 13000}),
|
|
45
|
+
lightning_rpc_port: await getPort({port: 13001, stopPort: 14000}),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
await control.add_chain_peer({socket: target.chain_socket});
|
|
49
|
+
await target.add_chain_peer({socket: control.chain_socket});
|
|
50
|
+
|
|
51
|
+
const controlLnd = authenticatedLndGrpc({
|
|
52
|
+
cert: control.cert,
|
|
53
|
+
macaroon: control.macaroon,
|
|
54
|
+
socket: control.socket,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
const id = (await getIdentity({lnd: controlLnd.lnd})).public_key;
|
|
58
|
+
|
|
59
|
+
const targetLnd = authenticatedLndGrpc({
|
|
60
|
+
cert: target.cert,
|
|
61
|
+
macaroon: target.macaroon,
|
|
62
|
+
socket: target.socket,
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
const targetId = (await getIdentity({lnd: targetLnd.lnd})).public_key;
|
|
66
|
+
|
|
67
|
+
const channelOpen = await setupChannel({
|
|
68
|
+
generate: ({address, count}) => {
|
|
69
|
+
return new Promise(async (resolve, reject) => {
|
|
70
|
+
const {lnd} = targetLnd;
|
|
71
|
+
|
|
72
|
+
await target.generate({
|
|
73
|
+
count,
|
|
74
|
+
address: (await makeAddress({lnd})).address,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
if (!count || count < maturity) {
|
|
78
|
+
return resolve();
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
await asyncRetry({interval, times}, async () => {
|
|
82
|
+
const [utxo] = (await getUtxos({lnd})).utxos;
|
|
83
|
+
|
|
84
|
+
if (!utxo) {
|
|
85
|
+
throw new Error('ExpectedUtxoInUtxos');
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
return resolve();
|
|
90
|
+
});
|
|
91
|
+
},
|
|
92
|
+
give_tokens: giftTokens,
|
|
93
|
+
lnd: targetLnd.lnd,
|
|
94
|
+
to: {id, socket: control.ln_socket},
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
const {backup} = await getBackup({
|
|
98
|
+
lnd: controlLnd.lnd,
|
|
99
|
+
transaction_id: channelOpen.transaction_id,
|
|
100
|
+
transaction_vout: channelOpen.transaction_vout,
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await control.kill({});
|
|
104
|
+
|
|
105
|
+
const clone = await spawnLightningDocker({
|
|
106
|
+
seed,
|
|
107
|
+
chain_p2p_port: await getPort({port: 8000, stopPort: 9000}),
|
|
108
|
+
chain_rpc_port: await getPort({port: 9001, stopPort: 10000}),
|
|
109
|
+
chain_zmq_block_port: await getPort({port: 10001, stopPort: 11000}),
|
|
110
|
+
chain_zmq_tx_port: await getPort({port: 11001, stopPort: 12000}),
|
|
111
|
+
generate_address: generateAddress,
|
|
112
|
+
lightning_p2p_port: await getPort({port: 12001, stopPort: 13000}),
|
|
113
|
+
lightning_rpc_port: await getPort({port: 13001, stopPort: 14000}),
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
await clone.add_chain_peer({socket: target.chain_socket});
|
|
117
|
+
|
|
118
|
+
await target.add_chain_peer({socket: clone.chain_socket});
|
|
119
|
+
|
|
120
|
+
const cloneLnd = authenticatedLndGrpc({
|
|
121
|
+
cert: clone.cert,
|
|
122
|
+
macaroon: clone.macaroon,
|
|
123
|
+
socket: clone.socket,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
await addPeer({
|
|
127
|
+
lnd: cloneLnd.lnd,
|
|
128
|
+
public_key: targetId,
|
|
129
|
+
socket: target.ln_socket,
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
await asyncRetry({interval, times}, async () => {
|
|
133
|
+
await recoverFundsFromChannel({backup, lnd: cloneLnd.lnd});
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
await clone.generate({
|
|
137
|
+
address: generateAddress,
|
|
138
|
+
count: confirmationCount,
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
await target.generate({
|
|
142
|
+
address: generateAddress,
|
|
143
|
+
count: confirmationCount,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
// Target should force close the channel
|
|
147
|
+
{
|
|
148
|
+
const {lnd} = targetLnd;
|
|
149
|
+
|
|
150
|
+
await asyncRetry({interval, times}, async () => {
|
|
151
|
+
await addPeer({
|
|
152
|
+
lnd: cloneLnd.lnd,
|
|
153
|
+
public_key: targetId,
|
|
154
|
+
socket: target.ln_socket,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const [chan] = (await getPendingChannels({lnd})).pending_channels;
|
|
158
|
+
|
|
159
|
+
if (!chan) {
|
|
160
|
+
throw new Error('ExpectedChannelClosing');
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Make sure that the clone is getting the recovered funds
|
|
166
|
+
{
|
|
167
|
+
const {lnd} = cloneLnd;
|
|
168
|
+
|
|
169
|
+
await asyncRetry({interval, times}, async () => {
|
|
170
|
+
const [chan] = (await getPendingChannels({lnd})).pending_channels;
|
|
171
|
+
|
|
172
|
+
await target.generate({address: generateAddress});
|
|
173
|
+
|
|
174
|
+
if (!chan.local_balance) {
|
|
175
|
+
throw new Error('ExpectedChannelClosingBalance');
|
|
176
|
+
}
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
const [chan] = (await getPendingChannels({lnd})).pending_channels;
|
|
180
|
+
|
|
181
|
+
equal(!!chan.close_transaction_id, true, 'Close transaction id found');
|
|
182
|
+
equal(chan.is_active, false, 'Chan no longer active');
|
|
183
|
+
equal(chan.is_closing, true, 'Channel is closing');
|
|
184
|
+
equal(chan.is_opening, false, 'Channel closing');
|
|
185
|
+
equal(chan.local_balance, giftTokens, 'Funds are being restored');
|
|
186
|
+
equal(chan.partner_public_key, targetId, 'Peer key');
|
|
187
|
+
equal(chan.transaction_id, channelOpen.transaction_id, 'Chan tx id');
|
|
188
|
+
equal(chan.transaction_vout, channelOpen.transaction_vout, 'Chan tx vout');
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
await clone.kill({});
|
|
192
|
+
|
|
193
|
+
await target.kill({});
|
|
194
|
+
|
|
195
|
+
return end();
|
|
196
|
+
});
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
const asyncRetry = require('async/retry');
|
|
2
|
+
const {getPortPromise: getPort} = require('portfinder');
|
|
3
|
+
const {setupChannel} = require('ln-docker-daemons');
|
|
4
|
+
const {spawnLightningDocker} = require('ln-docker-daemons');
|
|
5
|
+
const {test} = require('@alexbosworth/tap');
|
|
6
|
+
|
|
7
|
+
const {addPeer} = require('./../../');
|
|
8
|
+
const {authenticatedLndGrpc} = require('./../../');
|
|
9
|
+
const {createChainAddress} = require('./../../');
|
|
10
|
+
const {getBackups} = require('./../../');
|
|
11
|
+
const {getIdentity} = require('./../../');
|
|
12
|
+
const {getPendingChannels} = require('./../../');
|
|
13
|
+
const {getUtxos} = require('./../../');
|
|
14
|
+
const {recoverFundsFromChannels} = require('./../../');
|
|
15
|
+
|
|
16
|
+
const confirmationCount = 20;
|
|
17
|
+
const generateAddress = '2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF';
|
|
18
|
+
const giftTokens = 1e5;
|
|
19
|
+
const interval = 10;
|
|
20
|
+
const makeAddress = ({lnd}) => createChainAddress({lnd});
|
|
21
|
+
const maturity = 100;
|
|
22
|
+
const seed = 'about rabbit ozone hope jaguar quit scare twenty punch crisp consider clutch ring frost universe okay execute shrug drink notice abandon wine denial retreat';
|
|
23
|
+
const times = 3000;
|
|
24
|
+
|
|
25
|
+
// Using a channels backup should recover funds
|
|
26
|
+
test(`Recover funds from channels`, async ({end, equal}) => {
|
|
27
|
+
const control = await asyncRetry({interval, times}, async () => {
|
|
28
|
+
return await spawnLightningDocker({
|
|
29
|
+
seed,
|
|
30
|
+
chain_p2p_port: await getPort({port: 8000, stopPort: 9000}),
|
|
31
|
+
chain_rpc_port: await getPort({port: 9001, stopPort: 10000}),
|
|
32
|
+
chain_zmq_block_port: await getPort({port: 10001, stopPort: 11000}),
|
|
33
|
+
chain_zmq_tx_port: await getPort({port: 11001, stopPort: 12000}),
|
|
34
|
+
generate_address: generateAddress,
|
|
35
|
+
lightning_p2p_port: await getPort({port: 12001, stopPort: 13000}),
|
|
36
|
+
lightning_rpc_port: await getPort({port: 13001, stopPort: 14000}),
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const target = await asyncRetry({interval, times}, async () => {
|
|
41
|
+
return await spawnLightningDocker({
|
|
42
|
+
chain_p2p_port: await getPort({port: 8000, stopPort: 9000}),
|
|
43
|
+
chain_rpc_port: await getPort({port: 9001, stopPort: 10000}),
|
|
44
|
+
chain_zmq_block_port: await getPort({port: 10001, stopPort: 11000}),
|
|
45
|
+
chain_zmq_tx_port: await getPort({port: 11001, stopPort: 12000}),
|
|
46
|
+
generate_address: generateAddress,
|
|
47
|
+
lightning_p2p_port: await getPort({port: 12001, stopPort: 13000}),
|
|
48
|
+
lightning_rpc_port: await getPort({port: 13001, stopPort: 14000}),
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
await control.add_chain_peer({socket: target.chain_socket});
|
|
53
|
+
await target.add_chain_peer({socket: control.chain_socket});
|
|
54
|
+
|
|
55
|
+
const controlLnd = authenticatedLndGrpc({
|
|
56
|
+
cert: control.cert,
|
|
57
|
+
macaroon: control.macaroon,
|
|
58
|
+
socket: control.socket,
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
const id = (await getIdentity({lnd: controlLnd.lnd})).public_key;
|
|
62
|
+
|
|
63
|
+
const targetLnd = authenticatedLndGrpc({
|
|
64
|
+
cert: target.cert,
|
|
65
|
+
macaroon: target.macaroon,
|
|
66
|
+
socket: target.socket,
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
const targetId = (await getIdentity({lnd: targetLnd.lnd})).public_key;
|
|
70
|
+
|
|
71
|
+
const channelOpen = await setupChannel({
|
|
72
|
+
generate: ({address, count}) => {
|
|
73
|
+
return new Promise(async (resolve, reject) => {
|
|
74
|
+
const {lnd} = targetLnd;
|
|
75
|
+
|
|
76
|
+
await target.generate({
|
|
77
|
+
count,
|
|
78
|
+
address: (await makeAddress({lnd})).address,
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
if (!count || count < maturity) {
|
|
82
|
+
return resolve();
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
await asyncRetry({interval, times}, async () => {
|
|
86
|
+
const [utxo] = (await getUtxos({lnd})).utxos;
|
|
87
|
+
|
|
88
|
+
if (!utxo) {
|
|
89
|
+
throw new Error('ExpectedUtxoInUtxos');
|
|
90
|
+
}
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
return resolve();
|
|
94
|
+
});
|
|
95
|
+
},
|
|
96
|
+
give_tokens: giftTokens,
|
|
97
|
+
lnd: targetLnd.lnd,
|
|
98
|
+
to: {id, socket: control.ln_socket},
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
const {backup} = await getBackups({lnd: controlLnd.lnd});
|
|
102
|
+
|
|
103
|
+
await control.kill({});
|
|
104
|
+
|
|
105
|
+
const clone = await asyncRetry({interval, times}, async () => {
|
|
106
|
+
return await spawnLightningDocker({
|
|
107
|
+
seed,
|
|
108
|
+
chain_p2p_port: await getPort({port: 8000, stopPort: 9000}),
|
|
109
|
+
chain_rpc_port: await getPort({port: 9001, stopPort: 10000}),
|
|
110
|
+
chain_zmq_block_port: await getPort({port: 10001, stopPort: 11000}),
|
|
111
|
+
chain_zmq_tx_port: await getPort({port: 11001, stopPort: 12000}),
|
|
112
|
+
generate_address: generateAddress,
|
|
113
|
+
lightning_p2p_port: await getPort({port: 12001, stopPort: 13000}),
|
|
114
|
+
lightning_rpc_port: await getPort({port: 13001, stopPort: 14000}),
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
await clone.add_chain_peer({socket: target.chain_socket});
|
|
119
|
+
|
|
120
|
+
await target.add_chain_peer({socket: clone.chain_socket});
|
|
121
|
+
|
|
122
|
+
const cloneLnd = authenticatedLndGrpc({
|
|
123
|
+
cert: clone.cert,
|
|
124
|
+
macaroon: clone.macaroon,
|
|
125
|
+
socket: clone.socket,
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
await addPeer({
|
|
129
|
+
lnd: cloneLnd.lnd,
|
|
130
|
+
public_key: targetId,
|
|
131
|
+
socket: target.ln_socket,
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
await asyncRetry({interval, times}, async () => {
|
|
135
|
+
await recoverFundsFromChannels({backup, lnd: cloneLnd.lnd});
|
|
136
|
+
});
|
|
137
|
+
|
|
138
|
+
await clone.generate({
|
|
139
|
+
address: generateAddress,
|
|
140
|
+
count: confirmationCount,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
await target.generate({
|
|
144
|
+
address: generateAddress,
|
|
145
|
+
count: confirmationCount,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Target should force close the channel
|
|
149
|
+
{
|
|
150
|
+
const {lnd} = targetLnd;
|
|
151
|
+
|
|
152
|
+
await asyncRetry({interval, times}, async () => {
|
|
153
|
+
await addPeer({
|
|
154
|
+
lnd: cloneLnd.lnd,
|
|
155
|
+
public_key: targetId,
|
|
156
|
+
socket: target.ln_socket,
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
const [chan] = (await getPendingChannels({lnd})).pending_channels;
|
|
160
|
+
|
|
161
|
+
if (!chan) {
|
|
162
|
+
throw new Error('ExpectedChannelClosing');
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Make sure that the clone is getting the recovered funds
|
|
168
|
+
{
|
|
169
|
+
const {lnd} = cloneLnd;
|
|
170
|
+
|
|
171
|
+
await asyncRetry({interval, times}, async () => {
|
|
172
|
+
const [chan] = (await getPendingChannels({lnd})).pending_channels;
|
|
173
|
+
|
|
174
|
+
await target.generate({address: generateAddress});
|
|
175
|
+
|
|
176
|
+
if (!chan.local_balance) {
|
|
177
|
+
throw new Error('ExpectedChannelClosingBalance');
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
181
|
+
const [chan] = (await getPendingChannels({lnd})).pending_channels;
|
|
182
|
+
|
|
183
|
+
equal(!!chan.close_transaction_id, true, 'Close transaction id found');
|
|
184
|
+
equal(chan.is_active, false, 'Chan no longer active');
|
|
185
|
+
equal(chan.is_closing, true, 'Channel is closing');
|
|
186
|
+
equal(chan.is_opening, false, 'Channel closing');
|
|
187
|
+
equal(chan.local_balance, giftTokens, 'Funds are being restored');
|
|
188
|
+
equal(chan.partner_public_key, targetId, 'Peer key');
|
|
189
|
+
equal(chan.transaction_id, channelOpen.transaction_id, 'Chan tx id');
|
|
190
|
+
equal(chan.transaction_vout, channelOpen.transaction_vout, 'Chan tx vout');
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
await clone.kill({});
|
|
194
|
+
|
|
195
|
+
await target.kill({});
|
|
196
|
+
|
|
197
|
+
return end();
|
|
198
|
+
});
|
|
@@ -43,7 +43,7 @@ test(`Subscribe to payments`, async ({end, rejects, strictSame}) => {
|
|
|
43
43
|
sub.on('error', error => {
|
|
44
44
|
const [,, {err}] = error;
|
|
45
45
|
|
|
46
|
-
// subscribeToPayments is not supported on LND 0.15.
|
|
46
|
+
// subscribeToPayments is not supported on LND 0.15.3 and below
|
|
47
47
|
if (err.details === unsupported) {
|
|
48
48
|
return isLegacy.push(error);
|
|
49
49
|
}
|
|
@@ -1,57 +1,60 @@
|
|
|
1
|
+
const asyncRetry = require('async/retry');
|
|
2
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
1
3
|
const {test} = require('@alexbosworth/tap');
|
|
2
|
-
const tinysecp = require('tiny-secp256k1');
|
|
3
4
|
|
|
4
5
|
const {broadcastChainTransaction} = require('./../../');
|
|
5
|
-
const {chainSendTransaction} = require('./../macros');
|
|
6
6
|
const {createChainAddress} = require('./../../');
|
|
7
|
-
const {
|
|
8
|
-
const {generateBlocks} = require('./../macros');
|
|
7
|
+
const {fundPsbt} = require('./../../');
|
|
9
8
|
const {getChainTransactions} = require('./../../');
|
|
10
|
-
const {
|
|
11
|
-
const {waitForTermination} = require('./../macros');
|
|
9
|
+
const {signPsbt} = require('./../../');
|
|
12
10
|
|
|
13
11
|
const count = 100;
|
|
14
|
-
const
|
|
15
|
-
const
|
|
16
|
-
const
|
|
12
|
+
const description = 'description';
|
|
13
|
+
const interval = 10;
|
|
14
|
+
const times = 2000;
|
|
17
15
|
const tokens = 1e8;
|
|
18
16
|
|
|
19
17
|
// Test sending a chain transaction to Bitcoin network peers
|
|
20
|
-
test(`
|
|
21
|
-
const
|
|
18
|
+
test(`Broadcast chain transaction`, async ({end, equal}) => {
|
|
19
|
+
const [{generate, kill, lnd}] = (await spawnLightningCluster({})).nodes;
|
|
22
20
|
|
|
23
|
-
|
|
21
|
+
try {
|
|
22
|
+
await generate({count});
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
const {blocks} = await node.generate({count});
|
|
24
|
+
const {address} = await createChainAddress({lnd});
|
|
27
25
|
|
|
28
|
-
|
|
26
|
+
const {psbt} = await fundPsbt({lnd, outputs: [{address, tokens}]});
|
|
29
27
|
|
|
30
|
-
|
|
28
|
+
const {transaction} = await signPsbt({lnd, psbt});
|
|
31
29
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
private_key: node.mining_key,
|
|
38
|
-
spend_transaction_id: coinbaseTransactionId,
|
|
39
|
-
spend_vout: defaultVout,
|
|
40
|
-
});
|
|
30
|
+
const {id} = await broadcastChainTransaction({
|
|
31
|
+
description,
|
|
32
|
+
lnd,
|
|
33
|
+
transaction,
|
|
34
|
+
});
|
|
41
35
|
|
|
42
|
-
|
|
36
|
+
await asyncRetry({interval, times}, async () => {
|
|
37
|
+
const {transactions} = await getChainTransactions({lnd});
|
|
43
38
|
|
|
44
|
-
|
|
39
|
+
await generate({});
|
|
45
40
|
|
|
46
|
-
|
|
41
|
+
const tx = transactions.find(n => n.id === id);
|
|
47
42
|
|
|
48
|
-
|
|
43
|
+
if (!tx) {
|
|
44
|
+
throw new Error('ExpectedTransactionBroadcast');
|
|
45
|
+
}
|
|
49
46
|
|
|
50
|
-
|
|
47
|
+
if (!tx.is_confirmed) {
|
|
48
|
+
throw new Error('ExpectedTransactionConfirmed');
|
|
49
|
+
}
|
|
51
50
|
|
|
52
|
-
|
|
51
|
+
equal(tx.description, description, 'Description is set');
|
|
52
|
+
});
|
|
53
|
+
} catch (err) {
|
|
54
|
+
equal(err, null, 'Expected no error');
|
|
55
|
+
}
|
|
53
56
|
|
|
54
|
-
await
|
|
57
|
+
await kill({});
|
|
55
58
|
|
|
56
59
|
return end();
|
|
57
60
|
});
|
|
@@ -1,54 +1,43 @@
|
|
|
1
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
1
2
|
const {test} = require('@alexbosworth/tap');
|
|
2
|
-
const tinysecp = require('tiny-secp256k1');
|
|
3
3
|
|
|
4
4
|
const {broadcastChainTransaction} = require('./../../');
|
|
5
|
-
const {chainSendTransaction} = require('./../macros');
|
|
6
5
|
const {createChainAddress} = require('./../../');
|
|
7
|
-
const {
|
|
6
|
+
const {fundPsbt} = require('./../../');
|
|
7
|
+
const {getUtxos} = require('./../../');
|
|
8
8
|
const {requestChainFeeIncrease} = require('./../../');
|
|
9
|
-
const {
|
|
10
|
-
const {waitForTermination} = require('./../macros');
|
|
9
|
+
const {signPsbt} = require('./../../');
|
|
11
10
|
|
|
12
11
|
const count = 100;
|
|
13
|
-
const defaultVout = 0;
|
|
14
|
-
const fee = 1e3;
|
|
15
|
-
const format = 'np2wpkh';
|
|
16
12
|
const tokens = 1e8;
|
|
17
13
|
|
|
18
|
-
// Test requesting
|
|
14
|
+
// Test requesting a chain fee increase
|
|
19
15
|
test(`Request chain fee increase`, async ({end, equal}) => {
|
|
20
|
-
const
|
|
16
|
+
const [{generate, kill, lnd}] = (await spawnLightningCluster({})).nodes;
|
|
21
17
|
|
|
22
|
-
|
|
18
|
+
try {
|
|
19
|
+
await generate({count});
|
|
23
20
|
|
|
24
|
-
|
|
25
|
-
const {blocks} = await node.generate({count});
|
|
21
|
+
const {address} = await createChainAddress({lnd});
|
|
26
22
|
|
|
27
|
-
|
|
23
|
+
const {psbt} = await fundPsbt({lnd, outputs: [{address, tokens}]});
|
|
28
24
|
|
|
29
|
-
|
|
25
|
+
const {transaction} = await signPsbt({lnd, psbt});
|
|
30
26
|
|
|
31
|
-
|
|
32
|
-
fee,
|
|
33
|
-
tokens,
|
|
34
|
-
destination: (await createChainAddress({format, lnd})).address,
|
|
35
|
-
ecp: (await import('ecpair')).ECPairFactory(tinysecp),
|
|
36
|
-
private_key: node.mining_key,
|
|
37
|
-
spend_transaction_id: coinbaseTransactionId,
|
|
38
|
-
spend_vout: defaultVout,
|
|
39
|
-
});
|
|
27
|
+
await broadcastChainTransaction({lnd, transaction});
|
|
40
28
|
|
|
41
|
-
|
|
29
|
+
const bump = (await getUtxos({lnd})).utxos.find(n => n.tokens === tokens);
|
|
42
30
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
31
|
+
await requestChainFeeIncrease({
|
|
32
|
+
lnd,
|
|
33
|
+
transaction_id: bump.transaction_id,
|
|
34
|
+
transaction_vout: bump.transaction_vout,
|
|
35
|
+
});
|
|
36
|
+
} catch (err) {
|
|
37
|
+
equal(err, null, 'Expected no error');
|
|
38
|
+
}
|
|
48
39
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
await waitForTermination({lnd});
|
|
40
|
+
await kill({});
|
|
52
41
|
|
|
53
42
|
return end();
|
|
54
43
|
});
|
|
@@ -1,85 +0,0 @@
|
|
|
1
|
-
const {test} = require('@alexbosworth/tap');
|
|
2
|
-
|
|
3
|
-
const {createCluster} = require('./../macros');
|
|
4
|
-
const {delay} = require('./../macros');
|
|
5
|
-
const {getBackup} = require('./../../');
|
|
6
|
-
const {getPendingChannels} = require('./../../');
|
|
7
|
-
const {recoverFundsFromChannel} = require('./../../');
|
|
8
|
-
const {setupChannel} = require('./../macros');
|
|
9
|
-
const {spawnLnd} = require('./../macros');
|
|
10
|
-
const {stopDaemon} = require('./../../');
|
|
11
|
-
const {waitForPendingChannel} = require('./../macros');
|
|
12
|
-
const {waitForTermination} = require('./../macros');
|
|
13
|
-
|
|
14
|
-
const channelCapacityTokens = 1e6;
|
|
15
|
-
const confirmationCount = 20;
|
|
16
|
-
const defaultFee = 1e3;
|
|
17
|
-
const giftTokens = 1e5;
|
|
18
|
-
const seed = 'abandon tank dose ripple foil subway close flock laptop cabbage primary silent plastic unhappy west weird panda plastic brave prefer diesel glad jazz isolate';
|
|
19
|
-
|
|
20
|
-
// Using a channel backup should recover funds
|
|
21
|
-
test(`Recover funds from channel`, async ({end, equal}) => {
|
|
22
|
-
const clone = await spawnLnd({seed});
|
|
23
|
-
|
|
24
|
-
const cluster = await createCluster({
|
|
25
|
-
is_remote_skipped: true,
|
|
26
|
-
nodes: [clone],
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
const {lnd} = cluster.control;
|
|
30
|
-
|
|
31
|
-
const channelOpen = await setupChannel({
|
|
32
|
-
generate: cluster.generate,
|
|
33
|
-
generator: cluster.target,
|
|
34
|
-
give: giftTokens,
|
|
35
|
-
lnd: cluster.target.lnd,
|
|
36
|
-
to: cluster.control,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const {backup} = await getBackup({
|
|
40
|
-
lnd,
|
|
41
|
-
transaction_id: channelOpen.transaction_id,
|
|
42
|
-
transaction_vout: channelOpen.transaction_vout,
|
|
43
|
-
});
|
|
44
|
-
|
|
45
|
-
await stopDaemon({lnd});
|
|
46
|
-
|
|
47
|
-
cluster.control.kill();
|
|
48
|
-
|
|
49
|
-
await recoverFundsFromChannel({backup, lnd: clone.lnd});
|
|
50
|
-
|
|
51
|
-
await delay(3000);
|
|
52
|
-
|
|
53
|
-
await cluster.generate({count: confirmationCount, node: clone});
|
|
54
|
-
|
|
55
|
-
await delay(3000);
|
|
56
|
-
|
|
57
|
-
await cluster.generate({count: confirmationCount, node: cluster.target});
|
|
58
|
-
|
|
59
|
-
await delay(3000);
|
|
60
|
-
|
|
61
|
-
await waitForPendingChannel({
|
|
62
|
-
id: channelOpen.transaction_id,
|
|
63
|
-
is_closing: true,
|
|
64
|
-
lnd: clone.lnd,
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
const [chan] = (await getPendingChannels({lnd: clone.lnd})).pending_channels;
|
|
68
|
-
|
|
69
|
-
equal(!!chan.close_transaction_id, true, 'Close transaction id found');
|
|
70
|
-
equal(chan.is_active, false, 'Chan no longer active');
|
|
71
|
-
equal(chan.is_closing, true, 'Channel is closing');
|
|
72
|
-
equal(chan.is_opening, false, 'Channel closing');
|
|
73
|
-
equal(chan.local_balance, giftTokens, 'Funds are being restored');
|
|
74
|
-
equal(chan.partner_public_key, cluster.target_node_public_key, 'Peer key');
|
|
75
|
-
equal(chan.transaction_id, channelOpen.transaction_id, 'Chan tx id');
|
|
76
|
-
equal(chan.transaction_vout, channelOpen.transaction_vout, 'Chan tx vout');
|
|
77
|
-
|
|
78
|
-
clone.kill();
|
|
79
|
-
|
|
80
|
-
await waitForTermination({lnd: clone.lnd});
|
|
81
|
-
|
|
82
|
-
await cluster.kill({});
|
|
83
|
-
|
|
84
|
-
return end();
|
|
85
|
-
});
|
|
@@ -1,112 +0,0 @@
|
|
|
1
|
-
const asyncRetry = require('async/retry');
|
|
2
|
-
const {test} = require('@alexbosworth/tap');
|
|
3
|
-
|
|
4
|
-
const {createCluster} = require('./../macros');
|
|
5
|
-
const {delay} = require('./../macros');
|
|
6
|
-
const {getBackups} = require('./../../');
|
|
7
|
-
const {getPendingChannels} = require('./../../');
|
|
8
|
-
const {recoverFundsFromChannels} = require('./../../');
|
|
9
|
-
const {spawnLnd} = require('./../macros');
|
|
10
|
-
const {setupChannel} = require('./../macros');
|
|
11
|
-
const {stopDaemon} = require('./../../');
|
|
12
|
-
const {waitForPendingChannel} = require('./../macros');
|
|
13
|
-
const {waitForTermination} = require('./../macros');
|
|
14
|
-
|
|
15
|
-
const channelCapacityTokens = 1e6;
|
|
16
|
-
const confirmationCount = 20;
|
|
17
|
-
const defaultFee = 1e3;
|
|
18
|
-
const giftTokens = 1e5;
|
|
19
|
-
const seed = 'abandon tank dose ripple foil subway close flock laptop cabbage primary silent plastic unhappy west weird panda plastic brave prefer diesel glad jazz isolate';
|
|
20
|
-
|
|
21
|
-
// Using the channels backup should recover funds
|
|
22
|
-
test(`Recover funds with backup`, async ({end, equal}) => {
|
|
23
|
-
const clone = await spawnLnd({seed});
|
|
24
|
-
|
|
25
|
-
const cluster = await createCluster({
|
|
26
|
-
is_remote_skipped: true,
|
|
27
|
-
nodes: [clone],
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
let channelOpen;
|
|
31
|
-
const {lnd} = cluster.control;
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
channelOpen = await setupChannel({
|
|
35
|
-
generate: cluster.generate,
|
|
36
|
-
generator: cluster.target,
|
|
37
|
-
give: giftTokens,
|
|
38
|
-
lnd: cluster.target.lnd,
|
|
39
|
-
to: cluster.control,
|
|
40
|
-
});
|
|
41
|
-
} catch (err) {
|
|
42
|
-
equal(err, null, 'Expected no error setting up a channel');
|
|
43
|
-
|
|
44
|
-
clone.kill();
|
|
45
|
-
|
|
46
|
-
await waitForTermination({lnd: clone.lnd});
|
|
47
|
-
|
|
48
|
-
await cluster.kill({});
|
|
49
|
-
|
|
50
|
-
return end();
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
await delay(3000);
|
|
54
|
-
|
|
55
|
-
const {backup} = await getBackups({lnd});
|
|
56
|
-
|
|
57
|
-
await delay(3000);
|
|
58
|
-
|
|
59
|
-
await stopDaemon({lnd});
|
|
60
|
-
|
|
61
|
-
try {
|
|
62
|
-
const recover = await recoverFundsFromChannels({backup, lnd: clone.lnd});
|
|
63
|
-
|
|
64
|
-
equal(recover, undefined, 'Recover does not return anything');
|
|
65
|
-
} catch (err) {
|
|
66
|
-
equal(err, null, 'An error is not expected');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
await cluster.generate({count: confirmationCount, node: clone});
|
|
70
|
-
|
|
71
|
-
await waitForPendingChannel({
|
|
72
|
-
id: channelOpen.transaction_id,
|
|
73
|
-
is_recovering: true,
|
|
74
|
-
lnd: clone.lnd,
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
await delay(3000);
|
|
78
|
-
|
|
79
|
-
await cluster.generate({count: confirmationCount, node: clone});
|
|
80
|
-
|
|
81
|
-
await delay(3000);
|
|
82
|
-
|
|
83
|
-
await cluster.generate({count: confirmationCount, node: cluster.target});
|
|
84
|
-
|
|
85
|
-
const [chan] = (await getPendingChannels({lnd: clone.lnd})).pending_channels;
|
|
86
|
-
|
|
87
|
-
equal(!!chan.close_transaction_id, true, 'Close transaction id found');
|
|
88
|
-
equal(chan.is_active, false, 'Chan no longer active');
|
|
89
|
-
equal(chan.is_closing, true, 'Channel is closing');
|
|
90
|
-
equal(chan.is_opening, false, 'Channel closing');
|
|
91
|
-
equal(chan.local_balance, giftTokens, 'Funds are being restored');
|
|
92
|
-
equal(chan.partner_public_key, cluster.target_node_public_key, 'Peer key');
|
|
93
|
-
equal(chan.transaction_id, channelOpen.transaction_id, 'Chan tx id');
|
|
94
|
-
equal(chan.transaction_vout, channelOpen.transaction_vout, 'Chan tx vout');
|
|
95
|
-
|
|
96
|
-
const interval = retryCount => 50 * Math.pow(2, retryCount);
|
|
97
|
-
const times = 10;
|
|
98
|
-
|
|
99
|
-
await delay(3000);
|
|
100
|
-
|
|
101
|
-
clone.kill();
|
|
102
|
-
|
|
103
|
-
clone.kill();
|
|
104
|
-
|
|
105
|
-
clone.kill();
|
|
106
|
-
|
|
107
|
-
await waitForTermination({lnd: clone.lnd});
|
|
108
|
-
|
|
109
|
-
await cluster.kill({});
|
|
110
|
-
|
|
111
|
-
return end();
|
|
112
|
-
});
|