ln-docker-daemons 2.2.11 → 2.3.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 +5 -1
- package/LICENSE +1 -1
- package/README.md +56 -2
- package/index.js +2 -0
- package/package.json +5 -5
- package/setup/index.js +3 -0
- package/setup/setup_channel.js +98 -0
- package/setup/wait_for_channel.js +96 -0
- package/setup/wait_for_pending_channel.js +43 -0
package/CHANGELOG.md
CHANGED
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -18,6 +18,19 @@ const publicKey = (await getIdentity({lnd})).public_key;
|
|
|
18
18
|
await kill({});
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
Supported methods:
|
|
22
|
+
|
|
23
|
+
- setupChannel: Create a channel between lnds
|
|
24
|
+
- spawnBitcoindDocker: Run a Bitcoin Core container
|
|
25
|
+
- spawnLightningCluster: Spin up a group of nodes
|
|
26
|
+
- spawnLightningDocker: Run lnd + bitcoind
|
|
27
|
+
|
|
28
|
+
One liner for killing all running Docker containers:
|
|
29
|
+
|
|
30
|
+
```
|
|
31
|
+
docker container kill $(docker ps -q)
|
|
32
|
+
```
|
|
33
|
+
|
|
21
34
|
## Environment Variables
|
|
22
35
|
|
|
23
36
|
- `DOCKER_LND_VERSION`: set this to use a custom LND docker image
|
|
@@ -31,7 +44,48 @@ export DOCKER_LND_VERSION="v0.14.0-beta"
|
|
|
31
44
|
A list of available tags can be found here:
|
|
32
45
|
https://hub.docker.com/r/lightninglabs/lnd/tags
|
|
33
46
|
|
|
34
|
-
##
|
|
47
|
+
## `setupChannel`
|
|
48
|
+
|
|
49
|
+
Setup channel
|
|
50
|
+
|
|
51
|
+
{
|
|
52
|
+
[capacity]: <Channel Capacity Tokens Number>
|
|
53
|
+
generate: <Generate Blocks Promise>
|
|
54
|
+
[give_tokens]: <Gift Tokens Number>
|
|
55
|
+
lnd: <Authenticated LND API Object>
|
|
56
|
+
[partner_csv_delay]: <Partner CSV Delay Number>
|
|
57
|
+
to: {
|
|
58
|
+
id: <Partner Public Key Hex String>
|
|
59
|
+
socket: <Network Address String>
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@returns via cbk or Promise
|
|
64
|
+
{
|
|
65
|
+
id: <Standard Format Channel Id String>
|
|
66
|
+
transaction_id: <Funding Transaction Id Hex String>
|
|
67
|
+
transaction_vout: <Funding Transaction Output Index Number>
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
Example:
|
|
71
|
+
|
|
72
|
+
```node
|
|
73
|
+
const {getNetworkInfo} = require('ln-service');
|
|
74
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
75
|
+
|
|
76
|
+
const {kill, nodes} = await spawnLightningCluster({size: 2});
|
|
77
|
+
|
|
78
|
+
const [alice, bob] = nodes;
|
|
79
|
+
|
|
80
|
+
await setupChannel({generate: alice.generate, lnd: alice.lnd, to: bob});
|
|
81
|
+
|
|
82
|
+
const networkInfo = await getNetworkInfo({lnd: alice.lnd});
|
|
83
|
+
// networkInfo.channel_count now equals 1
|
|
84
|
+
|
|
85
|
+
await kill({});
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
## `spawnBitcoindDocker`
|
|
35
89
|
|
|
36
90
|
Spawn a Bitcoin Core Docker image
|
|
37
91
|
|
|
@@ -106,7 +160,7 @@ await generate({count: 500});
|
|
|
106
160
|
await kill({});
|
|
107
161
|
```
|
|
108
162
|
|
|
109
|
-
## spawnLightningDocker
|
|
163
|
+
## `spawnLightningDocker`
|
|
110
164
|
|
|
111
165
|
Spawn an LND Docker
|
|
112
166
|
|
package/index.js
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
const {setupChannel} = require('./setup');
|
|
1
2
|
const {spawnBitcoindDocker} = require('./bitcoind');
|
|
2
3
|
const {spawnLightningCluster} = require('./cluster');
|
|
3
4
|
const {spawnLightningDocker} = require('./lnd');
|
|
4
5
|
|
|
5
6
|
module.exports = {
|
|
7
|
+
setupChannel,
|
|
6
8
|
spawnBitcoindDocker,
|
|
7
9
|
spawnLightningCluster,
|
|
8
10
|
spawnLightningDocker,
|
package/package.json
CHANGED
|
@@ -8,11 +8,11 @@
|
|
|
8
8
|
},
|
|
9
9
|
"dependencies": {
|
|
10
10
|
"@alexbosworth/node-fetch": "2.6.2",
|
|
11
|
-
"async": "3.2.
|
|
12
|
-
"asyncjs-util": "1.2.
|
|
13
|
-
"dockerode": "3.3.
|
|
11
|
+
"async": "3.2.4",
|
|
12
|
+
"asyncjs-util": "1.2.10",
|
|
13
|
+
"dockerode": "3.3.2",
|
|
14
14
|
"find-free-ports": "3.0.0",
|
|
15
|
-
"lightning": "5.16.
|
|
15
|
+
"lightning": "5.16.3",
|
|
16
16
|
"tar-stream": "2.2.0"
|
|
17
17
|
},
|
|
18
18
|
"description": "Spawn and control LN Docker daemons",
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"scripts": {
|
|
36
36
|
"test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -j 1 test/bitcoind/*.js test/lnd/*.js"
|
|
37
37
|
},
|
|
38
|
-
"version": "2.
|
|
38
|
+
"version": "2.3.1"
|
|
39
39
|
}
|
package/setup/index.js
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
const {addPeer} = require('lightning');
|
|
2
|
+
const asyncAuto = require('async/auto');
|
|
3
|
+
const asyncRetry = require('async/retry');
|
|
4
|
+
const {getChainBalance} = require('lightning');
|
|
5
|
+
const {openChannel} = require('lightning');
|
|
6
|
+
const {returnResult} = require('asyncjs-util');
|
|
7
|
+
|
|
8
|
+
const waitForChannel = require('./wait_for_channel');
|
|
9
|
+
const waitForPendingChannel = require('./wait_for_pending_channel');
|
|
10
|
+
|
|
11
|
+
const channelCapacityTokens = 1e6;
|
|
12
|
+
const confCount = 6;
|
|
13
|
+
const count = 100;
|
|
14
|
+
const defaultFee = 1e3;
|
|
15
|
+
const interval = 100;
|
|
16
|
+
const times = 1500;
|
|
17
|
+
|
|
18
|
+
/** Setup channel
|
|
19
|
+
|
|
20
|
+
{
|
|
21
|
+
[capacity]: <Channel Capacity Tokens Number>
|
|
22
|
+
generate: <Generate Blocks Promise>
|
|
23
|
+
[give_tokens]: <Gift Tokens Number>
|
|
24
|
+
lnd: <Authenticated LND API Object>
|
|
25
|
+
[partner_csv_delay]: <Partner CSV Delay Number>
|
|
26
|
+
to: {
|
|
27
|
+
id: <Partner Public Key Hex String>
|
|
28
|
+
socket: <Network Address String>
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
@returns via cbk or Promise
|
|
33
|
+
{
|
|
34
|
+
id: <Standard Format Channel Id String>
|
|
35
|
+
transaction_id: <Funding Transaction Id Hex String>
|
|
36
|
+
transaction_vout: <Funding Transaction Output Index Number>
|
|
37
|
+
}
|
|
38
|
+
*/
|
|
39
|
+
module.exports = (args, cbk) => {
|
|
40
|
+
return new Promise((resolve, reject) => {
|
|
41
|
+
return asyncAuto({
|
|
42
|
+
// Make sure the node is connected
|
|
43
|
+
addPeer: cbk => {
|
|
44
|
+
return addPeer({
|
|
45
|
+
lnd: args.lnd,
|
|
46
|
+
public_key: args.to.id || args.to.public_key,
|
|
47
|
+
socket: args.to.socket,
|
|
48
|
+
},
|
|
49
|
+
cbk);
|
|
50
|
+
},
|
|
51
|
+
|
|
52
|
+
// Make sure the node has funds
|
|
53
|
+
generateFunds: async () => await args.generate({count}),
|
|
54
|
+
|
|
55
|
+
// Open channel
|
|
56
|
+
chanOpen: cbk => {
|
|
57
|
+
return asyncRetry({interval, times}, cbk => {
|
|
58
|
+
return openChannel({
|
|
59
|
+
chain_fee_tokens_per_vbyte: defaultFee,
|
|
60
|
+
give_tokens: args.give_tokens,
|
|
61
|
+
lnd: args.lnd,
|
|
62
|
+
local_tokens: args.capacity || channelCapacityTokens,
|
|
63
|
+
partner_csv_delay: args.partner_csv_delay,
|
|
64
|
+
partner_public_key: args.to.public_key || args.to.id,
|
|
65
|
+
socket: args.to.socket,
|
|
66
|
+
},
|
|
67
|
+
cbk);
|
|
68
|
+
},
|
|
69
|
+
cbk);
|
|
70
|
+
},
|
|
71
|
+
|
|
72
|
+
// Wait for pending
|
|
73
|
+
waitPending: ['chanOpen', ({chanOpen}, cbk) => {
|
|
74
|
+
return waitForPendingChannel({
|
|
75
|
+
id: chanOpen.transaction_id,
|
|
76
|
+
lnd: args.lnd,
|
|
77
|
+
},
|
|
78
|
+
cbk);
|
|
79
|
+
}],
|
|
80
|
+
|
|
81
|
+
// Generate blocks to confirm the pending channel
|
|
82
|
+
generate: ['waitPending', async ({}) => {
|
|
83
|
+
return await args.generate({count: confCount});
|
|
84
|
+
}],
|
|
85
|
+
|
|
86
|
+
// Wait for open
|
|
87
|
+
channel: ['chanOpen', ({chanOpen}, cbk) => {
|
|
88
|
+
return waitForChannel({
|
|
89
|
+
id: chanOpen.transaction_id,
|
|
90
|
+
lnd: args.lnd,
|
|
91
|
+
vout: chanOpen.transaction_vout,
|
|
92
|
+
},
|
|
93
|
+
cbk);
|
|
94
|
+
}],
|
|
95
|
+
},
|
|
96
|
+
returnResult({reject, resolve, of: 'channel'}, cbk));
|
|
97
|
+
});
|
|
98
|
+
};
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncRetry = require('async/retry');
|
|
3
|
+
const {returnResult} = require('asyncjs-util');
|
|
4
|
+
|
|
5
|
+
const {getChannel} = require('lightning');
|
|
6
|
+
const {getChannels} = require('lightning');
|
|
7
|
+
|
|
8
|
+
const interval = 20;
|
|
9
|
+
const times = 10000;
|
|
10
|
+
|
|
11
|
+
/** Wait for channel to be open
|
|
12
|
+
|
|
13
|
+
{
|
|
14
|
+
id: <Channel Transaction Id Hex String>
|
|
15
|
+
lnd: <Authenticated LND API Object>
|
|
16
|
+
vout: <Channel Output Index Number>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@returns via cbk or Promise
|
|
20
|
+
{
|
|
21
|
+
capacity: <Channel Token Capacity Number>
|
|
22
|
+
commit_transaction_fee: <Commit Transaction Fee Number>
|
|
23
|
+
commit_transaction_weight: <Commit Transaction Weight Number>
|
|
24
|
+
id: <Standard Format Channel Id String>
|
|
25
|
+
is_active: <Channel Active Bool>
|
|
26
|
+
is_closing: <Channel Is Closing Bool>
|
|
27
|
+
is_opening: <Channel Is Opening Bool>
|
|
28
|
+
is_partner_initiated: <Channel Partner Opened Channel>
|
|
29
|
+
is_private: <Channel Is Private Bool>
|
|
30
|
+
local_balance: <Local Balance Tokens Number>
|
|
31
|
+
partner_public_key: <Channel Partner Public Key String>
|
|
32
|
+
pending_payments: [{
|
|
33
|
+
id: <Payment Preimage Hash Hex String>
|
|
34
|
+
is_outgoing: <Payment Is Outgoing Bool>
|
|
35
|
+
timeout: <Chain Height Expiration Number>
|
|
36
|
+
tokens: <Payment Tokens Number>
|
|
37
|
+
}]
|
|
38
|
+
received: <Received Tokens Number>
|
|
39
|
+
remote_balance: <Remote Balance Tokens Number>
|
|
40
|
+
sent: <Sent Tokens Number>
|
|
41
|
+
transaction_id: <Blockchain Transaction Id String>
|
|
42
|
+
transaction_vout: <Blockchain Transaction Vout Number>
|
|
43
|
+
unsettled_balance: <Unsettled Balance Tokens Number>
|
|
44
|
+
}
|
|
45
|
+
*/
|
|
46
|
+
module.exports = (args, cbk) => {
|
|
47
|
+
return new Promise((resolve, reject) => {
|
|
48
|
+
return asyncAuto({
|
|
49
|
+
// Check arguments
|
|
50
|
+
validate: cbk => {
|
|
51
|
+
if (!args.id) {
|
|
52
|
+
return cbk([400, 'ExpectedTransactionIdToWaitForChannelOpen']);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (!args.lnd || !args.lnd.default) {
|
|
56
|
+
return cbk([400, 'ExpectedAuthenticatedLndToWaitForChannelOpen']);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return cbk();
|
|
60
|
+
},
|
|
61
|
+
|
|
62
|
+
// Find channel in channels list
|
|
63
|
+
channel: ['validate', async () => {
|
|
64
|
+
return await asyncRetry({interval, times}, async () => {
|
|
65
|
+
const {channels} = await getChannels({lnd: args.lnd});
|
|
66
|
+
|
|
67
|
+
const chan = channels.find(channel => {
|
|
68
|
+
const txVout = channel.transaction_vout;
|
|
69
|
+
|
|
70
|
+
return channel.transaction_id === args.id && txVout === args.vout;
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
if (!chan) {
|
|
74
|
+
throw new Error('FailedToFindChannelWithTransactionId');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
return chan;
|
|
78
|
+
});
|
|
79
|
+
}],
|
|
80
|
+
|
|
81
|
+
// Check channel fully created
|
|
82
|
+
gotChannel: ['channel', async ({channel}) => {
|
|
83
|
+
return await asyncRetry({interval, times}, async () => {
|
|
84
|
+
const {policies} = await getChannel({id: channel.id, lnd: args.lnd});
|
|
85
|
+
|
|
86
|
+
if (!!policies.find(n => !n.cltv_delta)) {
|
|
87
|
+
throw new Error('FailedToFindChannelWithFullPolicyDetails');
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
return;
|
|
91
|
+
});
|
|
92
|
+
}],
|
|
93
|
+
},
|
|
94
|
+
returnResult({reject, resolve, of: 'channel'}, cbk));
|
|
95
|
+
});
|
|
96
|
+
};
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
const asyncRetry = require('async/retry');
|
|
2
|
+
const {getPendingChannels} = require('lightning');
|
|
3
|
+
|
|
4
|
+
const interval = 10;
|
|
5
|
+
const times = 20000;
|
|
6
|
+
|
|
7
|
+
/** Wait for a pending channel to appear
|
|
8
|
+
|
|
9
|
+
{
|
|
10
|
+
id: <Channel Transaction Id Hex String>
|
|
11
|
+
lnd: <Authenticated LND API Object>
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
@returns via cbk
|
|
15
|
+
*/
|
|
16
|
+
module.exports = (args, cbk) => {
|
|
17
|
+
if (!args.id) {
|
|
18
|
+
return cbk([400, 'ExpectedTransactionIdToWaitForChannelPending']);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
if (!args.lnd || !args.lnd.default) {
|
|
22
|
+
return cbk([400, 'ExpectedAuthenticatedLndToWaitForChannelPending']);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const {id} = args;
|
|
26
|
+
|
|
27
|
+
return asyncRetry({interval, times}, cbk => {
|
|
28
|
+
return getPendingChannels({lnd: args.lnd}, (err, res) => {
|
|
29
|
+
if (!!err) {
|
|
30
|
+
return cbk(err);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
const channel = res.pending_channels.find(n => n.transaction_id === id);
|
|
34
|
+
|
|
35
|
+
if (!channel) {
|
|
36
|
+
return cbk([503, 'FailedToFindPendingChannelWithTransactionId']);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
return cbk(null, {channel});
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
cbk);
|
|
43
|
+
};
|