ln-service 54.1.2 → 54.2.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 +5 -0
- package/README.md +10 -0
- package/package.json +3 -3
- 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/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
package/README.md
CHANGED
|
@@ -3571,9 +3571,14 @@ If give_tokens is set, it is a gift and it does not alter the capacity
|
|
|
3571
3571
|
|
|
3572
3572
|
Requires `offchain:write`, `onchain:write`, `peers:write` permissions
|
|
3573
3573
|
|
|
3574
|
+
`base_fee_mtokens` is not supported on LND 0.15.2 and below
|
|
3575
|
+
`fee_rate` is not supported on LND 0.15.2 and below
|
|
3576
|
+
|
|
3574
3577
|
{
|
|
3578
|
+
[base_fee_mtokens]: <Routing Base Fee Millitokens Charged String>
|
|
3575
3579
|
[chain_fee_tokens_per_vbyte]: <Chain Fee Tokens Per VByte Number>
|
|
3576
3580
|
[cooperative_close_address]: <Restrict Cooperative Close To Address String>
|
|
3581
|
+
[fee_rate]: <Routing Fee Rate In Millitokens Per Million Number>
|
|
3577
3582
|
[give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
|
|
3578
3583
|
[is_private]: <Channel is Private Bool> // Defaults to false
|
|
3579
3584
|
lnd: <Authenticated LND API Object>
|
|
@@ -3619,10 +3624,15 @@ after the funding step.
|
|
|
3619
3624
|
`--protocol.option-scid-alias` and `--protocol.zero-conf` set on both sides
|
|
3620
3625
|
as well as a channel open request listener to accept the trusted funding.
|
|
3621
3626
|
|
|
3627
|
+
`base_fee_mtokens` is not supported on LND 0.15.2 and below
|
|
3628
|
+
`fee_rate` is not supported on LND 0.15.2 and below
|
|
3629
|
+
|
|
3622
3630
|
{
|
|
3623
3631
|
channels: [{
|
|
3632
|
+
[base_fee_mtokens]: <Routing Base Fee Millitokens Charged String>
|
|
3624
3633
|
capacity: <Channel Capacity Tokens Number>
|
|
3625
3634
|
[cooperative_close_address]: <Restrict Coop Close To Address String>
|
|
3635
|
+
[fee_rate]: <Routing Fee Rate In Millitokens Per Million Number>
|
|
3626
3636
|
[give_tokens]: <Tokens to Gift To Partner Number> // Defaults to zero
|
|
3627
3637
|
[is_private]: <Channel is Private Bool> // Defaults to false
|
|
3628
3638
|
[is_trusted_funding]: <Peer Should Avoid Waiting For Confirmation Bool>
|
package/package.json
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
"cors": "2.8.5",
|
|
12
12
|
"express": "4.18.1",
|
|
13
13
|
"invoices": "2.2.0",
|
|
14
|
-
"lightning": "6.
|
|
14
|
+
"lightning": "6.2.0",
|
|
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.0
|
|
31
|
+
"ln-docker-daemons": "3.1.0",
|
|
32
32
|
"p2tr": "1.3.2",
|
|
33
33
|
"portfinder": "1.0.32",
|
|
34
34
|
"psbt": "2.7.1",
|
|
@@ -71,5 +71,5 @@
|
|
|
71
71
|
"integration-test-0.12.0": "DOCKER_LND_VERSION=v0.12.0-beta npm run test",
|
|
72
72
|
"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
73
|
},
|
|
74
|
-
"version": "54.
|
|
74
|
+
"version": "54.2.0"
|
|
75
75
|
}
|
|
@@ -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.2 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.2 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
|
+
});
|
|
@@ -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
|
-
});
|