ln-docker-daemons 1.2.0 → 2.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 +20 -0
- package/README.md +19 -3
- package/bitcoind/spawn_bitcoind_docker.js +2 -6
- package/bitcoinrpc/add_peer.js +54 -0
- package/bitcoinrpc/get_block_info.js +57 -0
- package/bitcoinrpc/index.js +8 -1
- package/bitcoinrpc/rpc.js +0 -4
- package/cluster/spawn_lightning_cluster.js +111 -42
- package/docker/spawn_docker_image.js +12 -6
- package/lnd/constants.json +1 -1
- package/lnd/spawn_lightning_docker.js +22 -0
- package/lnd/spawn_lnd_docker.js +46 -36
- package/package.json +5 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 2.2.0
|
|
4
|
+
|
|
5
|
+
- `spawnLightningCluster`, `spawnLightningDocker`: Add `lnd_configuration` to
|
|
6
|
+
allow specifying additional LND configuration parameters
|
|
7
|
+
|
|
8
|
+
## 2.1.1
|
|
9
|
+
|
|
10
|
+
- `DOCKER_LND_VERSION`: add environment variable to control docker lnd image
|
|
11
|
+
|
|
12
|
+
## 2.0.0
|
|
13
|
+
|
|
14
|
+
- `spawnLightningCluster`: add `socket` to reveal node LN p2p sockets
|
|
15
|
+
- `spawnLightningDocker`: add `add_chain_peer` method to add a chain peer
|
|
16
|
+
- `spawnLightningDocker`: add `chain_socket` method for the chain p2p socket
|
|
17
|
+
- `spawnLightningDocker`: add `ln_socket` method for the chain p2p socket
|
|
18
|
+
|
|
19
|
+
### Breaking Changes
|
|
20
|
+
|
|
21
|
+
- Node 12+ is required
|
|
22
|
+
|
|
3
23
|
## 1.2.0
|
|
4
24
|
|
|
5
25
|
- `spawnLightningCluster` add `generate` to generate coins for a node
|
package/README.md
CHANGED
|
@@ -18,6 +18,16 @@ const publicKey = (await getIdentity({lnd})).public_key;
|
|
|
18
18
|
await kill({});
|
|
19
19
|
```
|
|
20
20
|
|
|
21
|
+
## Environment Variables
|
|
22
|
+
|
|
23
|
+
- `DOCKER_LND_VERSION`: set this to use a custom LND docker image
|
|
24
|
+
|
|
25
|
+
Example:
|
|
26
|
+
|
|
27
|
+
```shell
|
|
28
|
+
export DOCKER_LND_VERSION="v0.14.0-beta"
|
|
29
|
+
```
|
|
30
|
+
|
|
21
31
|
## spawnBitcoindDocker
|
|
22
32
|
|
|
23
33
|
Spawn a Bitcoin Core Docker image
|
|
@@ -31,6 +41,7 @@ Spawn a Bitcoin Core Docker image
|
|
|
31
41
|
|
|
32
42
|
@returns via cbk or Promise
|
|
33
43
|
{
|
|
44
|
+
host: <Host String>
|
|
34
45
|
kill: ({}, [cbk]) => <Kill Promise>
|
|
35
46
|
rpc_pass: <RPC Password String>
|
|
36
47
|
rpc_user: <RPC Username String>
|
|
@@ -58,6 +69,7 @@ await kill({});
|
|
|
58
69
|
Spawn a cluster of nodes
|
|
59
70
|
|
|
60
71
|
{
|
|
72
|
+
[lnd_configuration]: [<LND Configuration Argument String>]
|
|
61
73
|
[size]: <Total Lightning Nodes Number>
|
|
62
74
|
}
|
|
63
75
|
|
|
@@ -68,6 +80,7 @@ Spawn a cluster of nodes
|
|
|
68
80
|
id: <Node Public Key Hex String>
|
|
69
81
|
kill: <Kill Function> ({}, cbk) => {}
|
|
70
82
|
lnd: <Authenticated LND API Object>
|
|
83
|
+
socket: <Node Socket String>
|
|
71
84
|
}]
|
|
72
85
|
}
|
|
73
86
|
|
|
@@ -81,11 +94,10 @@ const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
|
81
94
|
const {nodes} = await spawnLightningCluster({});
|
|
82
95
|
const [{lnd, generate, kill}] = nodes;
|
|
83
96
|
|
|
84
|
-
const
|
|
97
|
+
const publicKey = (await getIdentity({lnd})).public_key;
|
|
85
98
|
|
|
86
99
|
// Generate some coins for the wallet
|
|
87
|
-
|
|
88
|
-
await generate({address, count: 500});
|
|
100
|
+
await generate({count: 500});
|
|
89
101
|
|
|
90
102
|
// Stop the image
|
|
91
103
|
await kill({});
|
|
@@ -103,12 +115,16 @@ Spawn an LND Docker
|
|
|
103
115
|
generate_address: <Generate Blocks to Address String>
|
|
104
116
|
lightning_p2p_port: <Lightning Network P2P Listen Port Number>
|
|
105
117
|
lightning_rpc_port: <Lightning Node RPC Port Number>
|
|
118
|
+
[lnd_configuration]: [<LND Configuration Argument String>]
|
|
106
119
|
}
|
|
107
120
|
|
|
108
121
|
@returns via cbk or Promise
|
|
109
122
|
{
|
|
123
|
+
add_chain_peer: <Add Peer Function> ({socket}) => {}
|
|
110
124
|
cert: <LND Base64 Serialized TLS Cert>
|
|
125
|
+
chain_socket: <Chain P2P Socket String>
|
|
111
126
|
kill: ({}, [cbk]) => <Kill LND Daemon Promise>
|
|
127
|
+
ln_socket: <LN P2P Socket String>
|
|
112
128
|
macaroon: <LND Base64 Serialized Macaroon String>
|
|
113
129
|
public_key: <Identity Public Key Hex String>
|
|
114
130
|
socket: <LND RPC Host:Port Network Address String>
|
|
@@ -30,6 +30,7 @@ const trim = string => string.replace(/=+$/g, '');
|
|
|
30
30
|
|
|
31
31
|
@returns via cbk or Promise
|
|
32
32
|
{
|
|
33
|
+
host: <Host String>
|
|
33
34
|
kill: ({}, [cbk]) => <Kill Promise>
|
|
34
35
|
rpc_pass: <RPC Password String>
|
|
35
36
|
rpc_user: <RPC Username String>
|
|
@@ -75,6 +76,7 @@ module.exports = (args, cbk) => {
|
|
|
75
76
|
return spawnDockerImage({
|
|
76
77
|
arguments: [
|
|
77
78
|
'--disablewallet',
|
|
79
|
+
'--listen=1',
|
|
78
80
|
'--persistmempool=false',
|
|
79
81
|
'--printtoconsole',
|
|
80
82
|
'--regtest',
|
|
@@ -86,12 +88,6 @@ module.exports = (args, cbk) => {
|
|
|
86
88
|
`--zmqpubrawblock=tcp://*:${args.zmq_block_port}`,
|
|
87
89
|
`--zmqpubrawtx=tcp://*:${args.zmq_tx_port}`,
|
|
88
90
|
],
|
|
89
|
-
expose: [
|
|
90
|
-
'18443/tcp',
|
|
91
|
-
'18444/tcp',
|
|
92
|
-
[`${args.zmq_block_port}/tcp`],
|
|
93
|
-
[`${args.zmq_tx_port}/tcp`],
|
|
94
|
-
],
|
|
95
91
|
image: dockerBitcoindImage,
|
|
96
92
|
ports: {
|
|
97
93
|
'18443/tcp': args.rpc_port,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {returnResult} = require('asyncjs-util');
|
|
3
|
+
|
|
4
|
+
const rpc = require('./rpc');
|
|
5
|
+
|
|
6
|
+
const action = 'add';
|
|
7
|
+
const cmd = 'addnode';
|
|
8
|
+
const host = 'localhost';
|
|
9
|
+
|
|
10
|
+
/** Add a node as a peer
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
pass: <RPC Password String>
|
|
14
|
+
port: <RPC Port Number>
|
|
15
|
+
socket: <Socket to Connect to String>
|
|
16
|
+
user: <RPC Username String>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@returns via cbk or Promise
|
|
20
|
+
*/
|
|
21
|
+
module.exports = ({pass, port, socket, user}, cbk) => {
|
|
22
|
+
return new Promise((resolve, reject) => {
|
|
23
|
+
return asyncAuto({
|
|
24
|
+
// Check arguments
|
|
25
|
+
validate: cbk => {
|
|
26
|
+
if (!pass) {
|
|
27
|
+
return cbk([400, 'ExpectedRpcPasswordToAddChainPeer']);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
if (!port) {
|
|
31
|
+
return cbk([400, 'ExpectedRpcPortNumberToAddChainPeer']);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (!socket) {
|
|
35
|
+
return cbk([400, 'ExpectedSocketToAddChainPeer']);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (!user) {
|
|
39
|
+
return cbk([400, 'ExpectedRpcUsernameToAddChainPeer']);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
return cbk();
|
|
43
|
+
},
|
|
44
|
+
|
|
45
|
+
// Execute request
|
|
46
|
+
request: ['validate', ({}, cbk) => {
|
|
47
|
+
const params = [socket, action];
|
|
48
|
+
|
|
49
|
+
return rpc({cmd, host, pass, params, port, user}, cbk);
|
|
50
|
+
}],
|
|
51
|
+
},
|
|
52
|
+
returnResult({reject, resolve}, cbk));
|
|
53
|
+
});
|
|
54
|
+
};
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const {returnResult} = require('asyncjs-util');
|
|
3
|
+
|
|
4
|
+
const rpc = require('./rpc');
|
|
5
|
+
|
|
6
|
+
const cmd = 'getblock';
|
|
7
|
+
const host = 'localhost';
|
|
8
|
+
const infoVerbosityFlag = 1;
|
|
9
|
+
|
|
10
|
+
/** Get block info from Bitcoin Core daemon
|
|
11
|
+
|
|
12
|
+
{
|
|
13
|
+
id: <Block Hash Hex String>
|
|
14
|
+
pass: <RPC Password String>
|
|
15
|
+
port: <RPC Port Number>
|
|
16
|
+
user: <RPC Username String>
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
@returns via cbk or Promise
|
|
20
|
+
{
|
|
21
|
+
tx: [<Transaction Id Hex String>]
|
|
22
|
+
}
|
|
23
|
+
*/
|
|
24
|
+
module.exports = ({id, pass, port, user}, cbk) => {
|
|
25
|
+
return new Promise((resolve, reject) => {
|
|
26
|
+
return asyncAuto({
|
|
27
|
+
// Check arguments
|
|
28
|
+
validate: cbk => {
|
|
29
|
+
if (!id) {
|
|
30
|
+
return cbk([400, 'ExpectedBlockIdToGetBlockInfo']);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
if (!pass) {
|
|
34
|
+
return cbk([400, 'ExpectedRpcPasswordToGetBlockInfo']);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
if (!port) {
|
|
38
|
+
return cbk([400, 'ExpectedRpcPortNumberToGetBlockInfo']);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (!user) {
|
|
42
|
+
return cbk([400, 'ExpectedRpcUsernameToGetBlockInfo']);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
return cbk();
|
|
46
|
+
},
|
|
47
|
+
|
|
48
|
+
// Execute request
|
|
49
|
+
request: ['validate', ({}, cbk) => {
|
|
50
|
+
const params = [id, infoVerbosityFlag];
|
|
51
|
+
|
|
52
|
+
return rpc({cmd, host, pass, params, port, user}, cbk);
|
|
53
|
+
}],
|
|
54
|
+
},
|
|
55
|
+
returnResult({reject, resolve, of: 'request'}, cbk));
|
|
56
|
+
});
|
|
57
|
+
};
|
package/bitcoinrpc/index.js
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
+
const addPeer = require('./add_peer');
|
|
1
2
|
const generateToAddress = require('./generate_to_address');
|
|
3
|
+
const getBlockInfo = require('./get_block_info');
|
|
2
4
|
const getBlockchainInfo = require('./get_blockchain_info');
|
|
3
5
|
|
|
4
|
-
module.exports = {
|
|
6
|
+
module.exports = {
|
|
7
|
+
addPeer,
|
|
8
|
+
generateToAddress,
|
|
9
|
+
getBlockInfo,
|
|
10
|
+
getBlockchainInfo,
|
|
11
|
+
};
|
package/bitcoinrpc/rpc.js
CHANGED
|
@@ -88,10 +88,6 @@ module.exports = ({cert, cmd, host, params, pass, port, user}, cbk) => {
|
|
|
88
88
|
|
|
89
89
|
const {result} = await response.json();
|
|
90
90
|
|
|
91
|
-
if (!result) {
|
|
92
|
-
throw [503, 'ExpectedResultOfRpcRequest'];
|
|
93
|
-
}
|
|
94
|
-
|
|
95
91
|
return result;
|
|
96
92
|
} catch (err) {
|
|
97
93
|
if (err.code === 'ECONNRESET') {
|
|
@@ -1,85 +1,154 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncEach = require('async/each');
|
|
2
3
|
const asyncMap = require('async/map');
|
|
4
|
+
const asyncRetry = require('async/retry');
|
|
3
5
|
const {authenticatedLndGrpc} = require('lightning');
|
|
6
|
+
const {createChainAddress} = require('lightning');
|
|
4
7
|
const {findFreePorts} = require('find-free-ports');
|
|
8
|
+
const {getUtxos} = require('lightning');
|
|
5
9
|
const {getIdentity} = require('lightning');
|
|
6
10
|
const {returnResult} = require('asyncjs-util');
|
|
7
11
|
|
|
8
12
|
const {spawnLightningDocker} = require('./../lnd');
|
|
9
13
|
|
|
14
|
+
const between = (min, max) => Math.floor(Math.random() * (max - min) + min);
|
|
10
15
|
const chunk = (arr, n, size) => [...Array(size)].map(_ => arr.splice(0, n));
|
|
11
16
|
const count = size => size || 1;
|
|
17
|
+
const endPort = 65000;
|
|
12
18
|
const generateAddress = '2N8hwP1WmJrFF5QWABn38y63uYLhnJYJYTF';
|
|
19
|
+
const interval = 10;
|
|
20
|
+
const makeAddress = ({lnd}) => createChainAddress({lnd});
|
|
21
|
+
const maturity = 100;
|
|
22
|
+
const pairs = n => n.map((x, i) => n.slice(i + 1).map(y => [x, y])).flat();
|
|
13
23
|
const portsPerLnd = 6;
|
|
24
|
+
const startPort = 1025;
|
|
25
|
+
const times = 3000;
|
|
14
26
|
|
|
15
27
|
/** Spawn a cluster of nodes
|
|
16
28
|
|
|
17
29
|
{
|
|
30
|
+
[lnd_configuration]: [<LND Configuration Argument String>]
|
|
18
31
|
[size]: <Total Lightning Nodes Number>
|
|
19
32
|
}
|
|
20
33
|
|
|
21
34
|
@returns via cbk or Promise
|
|
22
35
|
{
|
|
23
36
|
nodes: [{
|
|
24
|
-
generate: ({address}, [cbk]) => {}
|
|
37
|
+
generate: ({address, count}, [cbk]) => {}
|
|
25
38
|
id: <Node Public Key Hex String>
|
|
26
39
|
kill: <Kill Function> ({}, cbk) => {}
|
|
27
40
|
lnd: <Authenticated LND API Object>
|
|
41
|
+
socket: <Node Socket String>
|
|
28
42
|
}]
|
|
29
43
|
}
|
|
30
44
|
*/
|
|
31
|
-
module.exports = (
|
|
45
|
+
module.exports = (args, cbk) => {
|
|
32
46
|
return new Promise((resolve, reject) => {
|
|
33
47
|
return asyncAuto({
|
|
34
|
-
// Find ports for the requested daemons
|
|
35
|
-
findPorts: async () => {
|
|
36
|
-
return await findFreePorts(portsPerLnd * count(size));
|
|
37
|
-
},
|
|
38
|
-
|
|
39
48
|
// Spawn nodes
|
|
40
|
-
spawn:
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
49
|
+
spawn: async () => {
|
|
50
|
+
return await asyncRetry({interval, times: 25}, async () => {
|
|
51
|
+
const options = {startPort: between(startPort, endPort)};
|
|
52
|
+
|
|
53
|
+
// Find ports for the requested daemons
|
|
54
|
+
const findPorts = await findFreePorts(
|
|
55
|
+
portsPerLnd * count(args.size),
|
|
56
|
+
options
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
const nodes = chunk(findPorts, portsPerLnd, count(args.size));
|
|
60
|
+
|
|
61
|
+
return await asyncMap(nodes, async (ports) => {
|
|
62
|
+
const [
|
|
63
|
+
chainP2pPort,
|
|
64
|
+
chainRpcPort,
|
|
65
|
+
chainZmqBlockPort,
|
|
66
|
+
chainZmqTxPort,
|
|
67
|
+
lightningP2pPort,
|
|
68
|
+
lightningRpcPort,
|
|
69
|
+
] = ports;
|
|
70
|
+
|
|
71
|
+
const lightningDocker = await spawnLightningDocker({
|
|
72
|
+
chain_p2p_port: chainP2pPort,
|
|
73
|
+
chain_rpc_port: chainRpcPort,
|
|
74
|
+
chain_zmq_block_port: chainZmqBlockPort,
|
|
75
|
+
chain_zmq_tx_port: chainZmqTxPort,
|
|
76
|
+
generate_address: generateAddress,
|
|
77
|
+
lightning_p2p_port: lightningP2pPort,
|
|
78
|
+
lightning_rpc_port: lightningRpcPort,
|
|
79
|
+
lnd_configuration: args.lnd_configuration,
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
const {lnd} = authenticatedLndGrpc({
|
|
83
|
+
cert: lightningDocker.cert,
|
|
84
|
+
macaroon: lightningDocker.macaroon,
|
|
85
|
+
socket: lightningDocker.socket,
|
|
86
|
+
});
|
|
62
87
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
88
|
+
const id = (await getIdentity({lnd})).public_key;
|
|
89
|
+
|
|
90
|
+
return {
|
|
91
|
+
id,
|
|
92
|
+
lnd,
|
|
93
|
+
chain: {
|
|
94
|
+
addPeer: lightningDocker.add_chain_peer,
|
|
95
|
+
generateToAddress: lightningDocker.generate,
|
|
96
|
+
getBlockInfo: lightningDocker.get_block_info,
|
|
97
|
+
socket: lightningDocker.chain_socket,
|
|
98
|
+
},
|
|
99
|
+
generate: ({address, count}) => {
|
|
100
|
+
return new Promise(async (resolve, reject) => {
|
|
101
|
+
await lightningDocker.generate({
|
|
102
|
+
count,
|
|
103
|
+
address: address || (await makeAddress({lnd})).address,
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (!count || count < maturity) {
|
|
107
|
+
return resolve();
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
await asyncRetry({interval, times}, async () => {
|
|
111
|
+
const [utxo] = (await getUtxos({lnd})).utxos;
|
|
112
|
+
|
|
113
|
+
if (!utxo) {
|
|
114
|
+
throw new Error('ExpectedUtxoInUtxos');
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
return utxo;
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
return resolve();
|
|
121
|
+
});
|
|
122
|
+
},
|
|
123
|
+
kill: lightningDocker.kill,
|
|
124
|
+
public_key: id,
|
|
125
|
+
socket: lightningDocker.ln_socket,
|
|
126
|
+
};
|
|
67
127
|
});
|
|
128
|
+
});
|
|
129
|
+
},
|
|
68
130
|
|
|
69
|
-
|
|
131
|
+
// Connect nodes in the cluster to each other
|
|
132
|
+
connect: ['spawn', async ({spawn}) => {
|
|
133
|
+
return await asyncEach(pairs(spawn), async pair => {
|
|
134
|
+
const [a, b] = pair.map(({chain}) => chain);
|
|
70
135
|
|
|
71
|
-
return {
|
|
72
|
-
id,
|
|
73
|
-
lnd,
|
|
74
|
-
generate: lightningDocker.generate,
|
|
75
|
-
kill: lightningDocker.kill,
|
|
76
|
-
};
|
|
136
|
+
return await a.addPeer({socket: b.socket});
|
|
77
137
|
});
|
|
78
138
|
}],
|
|
79
139
|
|
|
80
140
|
// Final set of nodes
|
|
81
|
-
nodes: ['spawn', async ({spawn}) => {
|
|
82
|
-
return {
|
|
141
|
+
nodes: ['connect', 'spawn', async ({spawn}) => {
|
|
142
|
+
return {
|
|
143
|
+
kill: ({}) => asyncEach(spawn, async ({kill}) => await kill({})),
|
|
144
|
+
nodes: spawn.map(node => ({
|
|
145
|
+
generate: node.generate,
|
|
146
|
+
id: node.id,
|
|
147
|
+
kill: node.kill,
|
|
148
|
+
lnd: node.lnd,
|
|
149
|
+
socket: node.socket,
|
|
150
|
+
})),
|
|
151
|
+
};
|
|
83
152
|
}],
|
|
84
153
|
},
|
|
85
154
|
returnResult({reject, resolve, of: 'nodes'}, cbk));
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncRetry = require('async/retry');
|
|
2
3
|
const Dockerode = require('dockerode');
|
|
3
4
|
const {returnResult} = require('asyncjs-util');
|
|
4
5
|
|
|
@@ -66,6 +67,8 @@ module.exports = ({arguments, expose, image, ports}, cbk) => {
|
|
|
66
67
|
throw [503, 'CannotConnectToDockerDaemon'];
|
|
67
68
|
}
|
|
68
69
|
|
|
70
|
+
console.log("ERR", err);
|
|
71
|
+
|
|
69
72
|
throw [503, 'UnexpectedErrorGettingDockerImage', {err}];
|
|
70
73
|
}
|
|
71
74
|
}],
|
|
@@ -125,13 +128,16 @@ module.exports = ({arguments, expose, image, ports}, cbk) => {
|
|
|
125
128
|
|
|
126
129
|
// Start the image
|
|
127
130
|
start: ['container', 'docker', ({container, docker}, cbk) => {
|
|
128
|
-
return
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
131
|
+
return asyncRetry({}, cbk => {
|
|
132
|
+
return container.start(err => {
|
|
133
|
+
if (!!err) {
|
|
134
|
+
return cbk([503, 'UnexpectedErrorStartingContainer', {err}]);
|
|
135
|
+
}
|
|
132
136
|
|
|
133
|
-
|
|
134
|
-
|
|
137
|
+
return cbk();
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
cbk);
|
|
135
141
|
}],
|
|
136
142
|
|
|
137
143
|
// Get the details about the container
|
package/lnd/constants.json
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
const asyncAuto = require('async/auto');
|
|
2
2
|
const {returnResult} = require('asyncjs-util');
|
|
3
3
|
|
|
4
|
+
const {addPeer} = require('./../bitcoinrpc');
|
|
4
5
|
const {generateToAddress} = require('./../bitcoinrpc');
|
|
6
|
+
const {getBlockInfo} = require('./../bitcoinrpc');
|
|
5
7
|
const {killDockers} = require('./../docker');
|
|
6
8
|
const {spawnBitcoindDocker} = require('./../bitcoind');
|
|
7
9
|
const spawnLndDocker = require('./spawn_lnd_docker');
|
|
@@ -16,13 +18,18 @@ const spawnLndDocker = require('./spawn_lnd_docker');
|
|
|
16
18
|
generate_address: <Generate Blocks to Address String>
|
|
17
19
|
lightning_p2p_port: <Lightning Network P2P Listen Port Number>
|
|
18
20
|
lightning_rpc_port: <Lightning Node RPC Port Number>
|
|
21
|
+
[lnd_configuration]: [<LND Configuration Argument String>]
|
|
19
22
|
}
|
|
20
23
|
|
|
21
24
|
@returns via cbk or Promise
|
|
22
25
|
{
|
|
26
|
+
add_chain_peer: <Add Peer Function> ({socket}) => {}
|
|
23
27
|
cert: <LND Base64 Serialized TLS Cert>
|
|
28
|
+
chain_socket: <Chain P2P Socket String>
|
|
24
29
|
generate: ({address, count}, cbk) => <Generate to Address Promise>
|
|
30
|
+
get_block_info: <Get Block Info Function> ({id}) => {}
|
|
25
31
|
kill: ({}, [cbk]) => <Kill LND Daemon Promise>
|
|
32
|
+
ln_socket: <LN P2P Socket String>
|
|
26
33
|
macaroon: <LND Base64 Serialized Macaroon String>
|
|
27
34
|
public_key: <Identity Public Key Hex String>
|
|
28
35
|
socket: <LND RPC Host:Port Network Address String>
|
|
@@ -93,6 +100,7 @@ module.exports = (args, cbk) => {
|
|
|
93
100
|
({spawnChainDaemon}, cbk) =>
|
|
94
101
|
{
|
|
95
102
|
return spawnLndDocker({
|
|
103
|
+
configuration: args.lnd_configuration,
|
|
96
104
|
bitcoind_rpc_host: spawnChainDaemon.host,
|
|
97
105
|
bitcoind_rpc_pass: spawnChainDaemon.rpc_pass,
|
|
98
106
|
bitcoind_rpc_port: args.chain_rpc_port,
|
|
@@ -114,7 +122,14 @@ module.exports = (args, cbk) => {
|
|
|
114
122
|
const dockers = [spawnChainDaemon, spawnLightningDaemon];
|
|
115
123
|
|
|
116
124
|
return cbk(null, {
|
|
125
|
+
add_chain_peer: ({socket}) => addPeer({
|
|
126
|
+
socket,
|
|
127
|
+
pass: spawnChainDaemon.rpc_pass,
|
|
128
|
+
port: args.chain_rpc_port,
|
|
129
|
+
user: spawnChainDaemon.rpc_user,
|
|
130
|
+
}),
|
|
117
131
|
cert: spawnLightningDaemon.cert,
|
|
132
|
+
chain_socket: `${spawnChainDaemon.host}`,
|
|
118
133
|
generate: ({address, count}) => generateToAddress({
|
|
119
134
|
address,
|
|
120
135
|
count,
|
|
@@ -122,8 +137,15 @@ module.exports = (args, cbk) => {
|
|
|
122
137
|
port: args.chain_rpc_port,
|
|
123
138
|
user: spawnChainDaemon.rpc_user,
|
|
124
139
|
}),
|
|
140
|
+
get_block_info: ({id}) => getBlockInfo({
|
|
141
|
+
id,
|
|
142
|
+
pass: spawnChainDaemon.rpc_pass,
|
|
143
|
+
port: args.chain_rpc_port,
|
|
144
|
+
user: spawnChainDaemon.rpc_user,
|
|
145
|
+
}),
|
|
125
146
|
kill: ({}, cbk) => killDockers({dockers}, cbk),
|
|
126
147
|
macaroon: spawnLightningDaemon.macaroon,
|
|
148
|
+
ln_socket: `${spawnLightningDaemon.host}:9735`,
|
|
127
149
|
public_key: spawnLightningDaemon.public_key,
|
|
128
150
|
socket: spawnLightningDaemon.socket,
|
|
129
151
|
});
|
package/lnd/spawn_lnd_docker.js
CHANGED
|
@@ -8,7 +8,8 @@ const {unauthenticatedLndGrpc} = require('lightning');
|
|
|
8
8
|
const {dockerLndImage} = require('./constants');
|
|
9
9
|
const {spawnDockerImage} = require('./../docker');
|
|
10
10
|
|
|
11
|
-
const
|
|
11
|
+
const imageName = ver => !!ver ? `lightninglabs/lnd:${ver}` : dockerLndImage;
|
|
12
|
+
const interval = 100;
|
|
12
13
|
const macaroonPath = '/root/.lnd/data/chain/bitcoin/regtest/admin.macaroon';
|
|
13
14
|
const times = 500;
|
|
14
15
|
const tlsCertPath = '/root/.lnd/tls.cert';
|
|
@@ -22,6 +23,7 @@ const tlsCertPath = '/root/.lnd/tls.cert';
|
|
|
22
23
|
bitcoind_rpc_user: <Bitcoin Core RPC Username String>
|
|
23
24
|
bitcoind_zmq_block_port: <Bitcoin Core ZMQ Block Port Number>
|
|
24
25
|
bitcoind_zmq_tx_port: <Bitcoin Core ZMQ Transaction Port Number>
|
|
26
|
+
[configuration]: [<LND Configuration Argument String>]
|
|
25
27
|
p2p_port: <LND Peer to Peer Listen Port Number>
|
|
26
28
|
rpc_port: <LND RPC Port Number>
|
|
27
29
|
}
|
|
@@ -77,29 +79,33 @@ module.exports = (args, cbk) => {
|
|
|
77
79
|
const zmqBlockPort = args.bitcoind_zmq_block_port;
|
|
78
80
|
const zmqTxPort = args.bitcoind_zmq_tx_port;
|
|
79
81
|
|
|
82
|
+
const arguments = [
|
|
83
|
+
'--accept-keysend',
|
|
84
|
+
'--allow-circular-route',
|
|
85
|
+
'--autopilot.heuristic=externalscore:0.5',
|
|
86
|
+
'--autopilot.heuristic=preferential:0.5',
|
|
87
|
+
'--bitcoin.active',
|
|
88
|
+
'--bitcoin.minhtlc=1000',
|
|
89
|
+
'--bitcoin.node=bitcoind',
|
|
90
|
+
'--bitcoin.regtest',
|
|
91
|
+
`--bitcoind.rpchost=${chainHost}:18443`,
|
|
92
|
+
`--bitcoind.rpcpass=${args.bitcoind_rpc_pass}`,
|
|
93
|
+
`--bitcoind.rpcuser=${args.bitcoind_rpc_user}`,
|
|
94
|
+
`--bitcoind.zmqpubrawblock=tcp://${chainHost}:${zmqBlockPort}`,
|
|
95
|
+
`--bitcoind.zmqpubrawtx=tcp://${chainHost}:${zmqTxPort}`,
|
|
96
|
+
'--debuglevel=trace',
|
|
97
|
+
`--externalip=127.0.0.1:9735`,
|
|
98
|
+
'--historicalsyncinterval=1s',
|
|
99
|
+
`--listen=0.0.0.0:9735`,
|
|
100
|
+
'--nobootstrap',
|
|
101
|
+
`--rpclisten=0.0.0.0:10009`,
|
|
102
|
+
'--trickledelay=1',
|
|
103
|
+
'--unsafe-disconnect',
|
|
104
|
+
];
|
|
105
|
+
|
|
80
106
|
return spawnDockerImage({
|
|
81
|
-
arguments: [
|
|
82
|
-
|
|
83
|
-
'--autopilot.heuristic=preferential:0.5',
|
|
84
|
-
'--bitcoin.active',
|
|
85
|
-
'--bitcoin.minhtlc=1000',
|
|
86
|
-
'--bitcoin.node=bitcoind',
|
|
87
|
-
'--bitcoin.regtest',
|
|
88
|
-
`--bitcoind.rpchost=${chainHost}:18443`,
|
|
89
|
-
`--bitcoind.rpcpass=${args.bitcoind_rpc_pass}`,
|
|
90
|
-
`--bitcoind.rpcuser=${args.bitcoind_rpc_user}`,
|
|
91
|
-
`--bitcoind.zmqpubrawblock=tcp://${chainHost}:${zmqBlockPort}`,
|
|
92
|
-
`--bitcoind.zmqpubrawtx=tcp://${chainHost}:${zmqTxPort}`,
|
|
93
|
-
'--debuglevel=trace',
|
|
94
|
-
`--externalip=127.0.0.1:9735`,
|
|
95
|
-
'--historicalsyncinterval=1s',
|
|
96
|
-
`--listen=0.0.0.0:9735`,
|
|
97
|
-
'--nobootstrap',
|
|
98
|
-
`--rpclisten=0.0.0.0:10009`,
|
|
99
|
-
'--trickledelay=1',
|
|
100
|
-
'--unsafe-disconnect',
|
|
101
|
-
],
|
|
102
|
-
image: dockerLndImage,
|
|
107
|
+
arguments: arguments.concat(args.configuration || []),
|
|
108
|
+
image: imageName(process.env.DOCKER_LND_VERSION),
|
|
103
109
|
ports: {
|
|
104
110
|
'9735/tcp': args.p2p_port,
|
|
105
111
|
'10009/tcp': args.rpc_port,
|
|
@@ -123,23 +129,26 @@ module.exports = (args, cbk) => {
|
|
|
123
129
|
|
|
124
130
|
const {lnd} = unauthenticatedLndGrpc({cert, socket});
|
|
125
131
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
return cbk([503, 'UnexpectedErrorGeneratingSeed', {err}]);
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
lnd.unlocker.initWallet({
|
|
132
|
-
cipher_seed_mnemonic: res.cipher_seed_mnemonic,
|
|
133
|
-
wallet_password: Buffer.from('password', 'utf8'),
|
|
134
|
-
},
|
|
135
|
-
err => {
|
|
132
|
+
return asyncRetry({interval, times}, cbk => {
|
|
133
|
+
return lnd.unlocker.genSeed({}, (err, res) => {
|
|
136
134
|
if (!!err) {
|
|
137
|
-
return cbk([503, '
|
|
135
|
+
return cbk([503, 'UnexpectedErrorGeneratingSeed', {err}]);
|
|
138
136
|
}
|
|
139
137
|
|
|
140
|
-
|
|
138
|
+
lnd.unlocker.initWallet({
|
|
139
|
+
cipher_seed_mnemonic: res.cipher_seed_mnemonic,
|
|
140
|
+
wallet_password: Buffer.from('password', 'utf8'),
|
|
141
|
+
},
|
|
142
|
+
err => {
|
|
143
|
+
if (!!err) {
|
|
144
|
+
return cbk([503, 'UnexpectedErrorInitializingWallet', {err}]);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return cbk();
|
|
148
|
+
});
|
|
141
149
|
});
|
|
142
|
-
}
|
|
150
|
+
},
|
|
151
|
+
cbk);
|
|
143
152
|
}],
|
|
144
153
|
|
|
145
154
|
// Get the macaroon out of the docker image
|
|
@@ -183,6 +192,7 @@ module.exports = (args, cbk) => {
|
|
|
183
192
|
{
|
|
184
193
|
return cbk(null, {
|
|
185
194
|
cert: getCertificate.file.toString('base64'),
|
|
195
|
+
host: spawnDocker.host,
|
|
186
196
|
kill: spawnDocker.kill,
|
|
187
197
|
macaroon: getMacaroon.file.toString('base64'),
|
|
188
198
|
public_key: waitForRpc.public_key,
|
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.
|
|
11
|
+
"async": "3.2.3",
|
|
12
|
+
"asyncjs-util": "1.2.8",
|
|
13
13
|
"dockerode": "3.3.1",
|
|
14
14
|
"find-free-ports": "3.0.0",
|
|
15
|
-
"lightning": "
|
|
15
|
+
"lightning": "5.3.1",
|
|
16
16
|
"tar-stream": "2.2.0"
|
|
17
17
|
},
|
|
18
18
|
"description": "Spawn and control LN Docker daemons",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"@alexbosworth/tap": "15.0.10"
|
|
21
21
|
},
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
23
|
+
"node": ">=12"
|
|
24
24
|
},
|
|
25
25
|
"keywords": [
|
|
26
26
|
"docker"
|
|
@@ -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": "
|
|
38
|
+
"version": "2.2.0"
|
|
39
39
|
}
|