ln-docker-daemons 1.0.2 → 2.1.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 +23 -0
- package/README.md +52 -0
- package/bitcoind/spawn_bitcoind_docker.js +2 -6
- package/bitcoinrpc/add_peer.js +54 -0
- package/bitcoinrpc/generate_to_address.js +3 -2
- package/bitcoinrpc/get_block_info.js +57 -0
- package/bitcoinrpc/index.js +8 -1
- package/bitcoinrpc/rpc.js +0 -4
- package/cluster/index.js +3 -0
- package/cluster/spawn_lightning_cluster.js +154 -0
- package/docker/spawn_docker_image.js +16 -6
- package/index.js +6 -1
- package/lnd/constants.json +1 -1
- package/lnd/spawn_lightning_docker.js +28 -0
- package/lnd/spawn_lnd_docker.js +22 -15
- package/package.json +6 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,28 @@
|
|
|
1
1
|
# Versions
|
|
2
2
|
|
|
3
|
+
## 2.1.0
|
|
4
|
+
|
|
5
|
+
- `DOCKER_LND_VERSION`: add environment variable to control docker lnd image
|
|
6
|
+
|
|
7
|
+
## 2.0.0
|
|
8
|
+
|
|
9
|
+
- `spawnLightningCluster`: add `socket` to reveal node LN p2p sockets
|
|
10
|
+
- `spawnLightningDocker`: add `add_chain_peer` method to add a chain peer
|
|
11
|
+
- `spawnLightningDocker`: add `chain_socket` method for the chain p2p socket
|
|
12
|
+
- `spawnLightningDocker`: add `ln_socket` method for the chain p2p socket
|
|
13
|
+
|
|
14
|
+
### Breaking Changes
|
|
15
|
+
|
|
16
|
+
- Node 12+ is required
|
|
17
|
+
|
|
18
|
+
## 1.2.0
|
|
19
|
+
|
|
20
|
+
- `spawnLightningCluster` add `generate` to generate coins for a node
|
|
21
|
+
|
|
22
|
+
## 1.1.0
|
|
23
|
+
|
|
24
|
+
- Add `spawnLightningCluster` to spawn multiple lightning dockers
|
|
25
|
+
|
|
3
26
|
## 1.0.2
|
|
4
27
|
|
|
5
28
|
- Update lnd to 0.13.1 and Bitcoin Core to 0.21.1
|
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>
|
|
@@ -53,6 +64,44 @@ const {kill} = spawnBitcoindDocker({
|
|
|
53
64
|
await kill({});
|
|
54
65
|
```
|
|
55
66
|
|
|
67
|
+
## `spawnLightningCluster`
|
|
68
|
+
|
|
69
|
+
Spawn a cluster of nodes
|
|
70
|
+
|
|
71
|
+
{
|
|
72
|
+
[size]: <Total Lightning Nodes Number>
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
@returns via cbk or Promise
|
|
76
|
+
{
|
|
77
|
+
nodes: [{
|
|
78
|
+
generate: ({address, [count]}) => {}
|
|
79
|
+
id: <Node Public Key Hex String>
|
|
80
|
+
kill: <Kill Function> ({}, cbk) => {}
|
|
81
|
+
lnd: <Authenticated LND API Object>
|
|
82
|
+
socket: <Node Socket String>
|
|
83
|
+
}]
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
Example:
|
|
87
|
+
|
|
88
|
+
```node
|
|
89
|
+
const {createChainAddress, getIdentity} = require('lightning');
|
|
90
|
+
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
91
|
+
|
|
92
|
+
// Launch a lightning node
|
|
93
|
+
const {nodes} = await spawnLightningCluster({});
|
|
94
|
+
const [{lnd, generate, kill}] = nodes;
|
|
95
|
+
|
|
96
|
+
const publicKey = (await getIdentity({lnd})).public_key;
|
|
97
|
+
|
|
98
|
+
// Generate some coins for the wallet
|
|
99
|
+
await generate({count: 500});
|
|
100
|
+
|
|
101
|
+
// Stop the image
|
|
102
|
+
await kill({});
|
|
103
|
+
```
|
|
104
|
+
|
|
56
105
|
## spawnLightningDocker
|
|
57
106
|
|
|
58
107
|
Spawn an LND Docker
|
|
@@ -69,8 +118,11 @@ Spawn an LND Docker
|
|
|
69
118
|
|
|
70
119
|
@returns via cbk or Promise
|
|
71
120
|
{
|
|
121
|
+
add_chain_peer: <Add Peer Function> ({socket}) => {}
|
|
72
122
|
cert: <LND Base64 Serialized TLS Cert>
|
|
123
|
+
chain_socket: <Chain P2P Socket String>
|
|
73
124
|
kill: ({}, [cbk]) => <Kill LND Daemon Promise>
|
|
125
|
+
ln_socket: <LN P2P Socket String>
|
|
74
126
|
macaroon: <LND Base64 Serialized Macaroon String>
|
|
75
127
|
public_key: <Identity Public Key Hex String>
|
|
76
128
|
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
|
+
};
|
|
@@ -10,6 +10,7 @@ const host = 'localhost';
|
|
|
10
10
|
|
|
11
11
|
{
|
|
12
12
|
address: <Address to Mine Outputs Towards String>
|
|
13
|
+
[count]: <Generate Count Number>
|
|
13
14
|
pass: <RPC Password String>
|
|
14
15
|
port: <RPC Port Number>
|
|
15
16
|
user: <RPC Username String>
|
|
@@ -20,7 +21,7 @@ const host = 'localhost';
|
|
|
20
21
|
blocks: <Best Chain Block Height Number>
|
|
21
22
|
}
|
|
22
23
|
*/
|
|
23
|
-
module.exports = ({address, pass, port, user}, cbk) => {
|
|
24
|
+
module.exports = ({address, count, pass, port, user}, cbk) => {
|
|
24
25
|
return new Promise((resolve, reject) => {
|
|
25
26
|
return asyncAuto({
|
|
26
27
|
// Check arguments
|
|
@@ -46,7 +47,7 @@ module.exports = ({address, pass, port, user}, cbk) => {
|
|
|
46
47
|
|
|
47
48
|
// Execute request
|
|
48
49
|
request: ['validate', ({}, cbk) => {
|
|
49
|
-
const params = [[address].length, address];
|
|
50
|
+
const params = [count || [address].length, address];
|
|
50
51
|
|
|
51
52
|
return rpc({cmd, host, pass, params, port, user}, cbk);
|
|
52
53
|
}],
|
|
@@ -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') {
|
package/cluster/index.js
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
const asyncAuto = require('async/auto');
|
|
2
|
+
const asyncEach = require('async/each');
|
|
3
|
+
const asyncMap = require('async/map');
|
|
4
|
+
const asyncRetry = require('async/retry');
|
|
5
|
+
const {authenticatedLndGrpc} = require('lightning');
|
|
6
|
+
const {createChainAddress} = require('lightning');
|
|
7
|
+
const {findFreePorts} = require('find-free-ports');
|
|
8
|
+
const {getUtxos} = require('lightning');
|
|
9
|
+
const {getIdentity} = require('lightning');
|
|
10
|
+
const {returnResult} = require('asyncjs-util');
|
|
11
|
+
|
|
12
|
+
const {spawnLightningDocker} = require('./../lnd');
|
|
13
|
+
|
|
14
|
+
const between = (min, max) => Math.floor(Math.random() * (max - min) + min);
|
|
15
|
+
const chunk = (arr, n, size) => [...Array(size)].map(_ => arr.splice(0, n));
|
|
16
|
+
const count = size => size || 1;
|
|
17
|
+
const endPort = 65000;
|
|
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();
|
|
23
|
+
const portsPerLnd = 6;
|
|
24
|
+
const startPort = 1025;
|
|
25
|
+
const times = 3000;
|
|
26
|
+
|
|
27
|
+
/** Spawn a cluster of nodes
|
|
28
|
+
|
|
29
|
+
{
|
|
30
|
+
[size]: <Total Lightning Nodes Number>
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
@returns via cbk or Promise
|
|
34
|
+
{
|
|
35
|
+
nodes: [{
|
|
36
|
+
generate: ({address, count}, [cbk]) => {}
|
|
37
|
+
id: <Node Public Key Hex String>
|
|
38
|
+
kill: <Kill Function> ({}, cbk) => {}
|
|
39
|
+
lnd: <Authenticated LND API Object>
|
|
40
|
+
socket: <Node Socket String>
|
|
41
|
+
}]
|
|
42
|
+
}
|
|
43
|
+
*/
|
|
44
|
+
module.exports = (args, cbk) => {
|
|
45
|
+
return new Promise((resolve, reject) => {
|
|
46
|
+
return asyncAuto({
|
|
47
|
+
// Spawn nodes
|
|
48
|
+
spawn: async () => {
|
|
49
|
+
return await asyncRetry({interval, times: 25}, async () => {
|
|
50
|
+
const options = {startPort: between(startPort, endPort)};
|
|
51
|
+
|
|
52
|
+
// Find ports for the requested daemons
|
|
53
|
+
const findPorts = await findFreePorts(
|
|
54
|
+
portsPerLnd * count(args.size),
|
|
55
|
+
options
|
|
56
|
+
);
|
|
57
|
+
|
|
58
|
+
const nodes = chunk(findPorts, portsPerLnd, count(args.size));
|
|
59
|
+
|
|
60
|
+
return await asyncMap(nodes, async (ports) => {
|
|
61
|
+
const [
|
|
62
|
+
chainP2pPort,
|
|
63
|
+
chainRpcPort,
|
|
64
|
+
chainZmqBlockPort,
|
|
65
|
+
chainZmqTxPort,
|
|
66
|
+
lightningP2pPort,
|
|
67
|
+
lightningRpcPort,
|
|
68
|
+
] = ports;
|
|
69
|
+
|
|
70
|
+
const lightningDocker = await spawnLightningDocker({
|
|
71
|
+
chain_p2p_port: chainP2pPort,
|
|
72
|
+
chain_rpc_port: chainRpcPort,
|
|
73
|
+
chain_zmq_block_port: chainZmqBlockPort,
|
|
74
|
+
chain_zmq_tx_port: chainZmqTxPort,
|
|
75
|
+
generate_address: generateAddress,
|
|
76
|
+
lightning_p2p_port: lightningP2pPort,
|
|
77
|
+
lightning_rpc_port: lightningRpcPort,
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
const {lnd} = authenticatedLndGrpc({
|
|
81
|
+
cert: lightningDocker.cert,
|
|
82
|
+
macaroon: lightningDocker.macaroon,
|
|
83
|
+
socket: lightningDocker.socket,
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
const id = (await getIdentity({lnd})).public_key;
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
id,
|
|
90
|
+
lnd,
|
|
91
|
+
chain: {
|
|
92
|
+
addPeer: lightningDocker.add_chain_peer,
|
|
93
|
+
generateToAddress: lightningDocker.generate,
|
|
94
|
+
getBlockInfo: lightningDocker.get_block_info,
|
|
95
|
+
socket: lightningDocker.chain_socket,
|
|
96
|
+
},
|
|
97
|
+
generate: ({address, count}) => {
|
|
98
|
+
return new Promise(async (resolve, reject) => {
|
|
99
|
+
await lightningDocker.generate({
|
|
100
|
+
count,
|
|
101
|
+
address: address || (await makeAddress({lnd})).address,
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
if (!count || count < maturity) {
|
|
105
|
+
return resolve();
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
await asyncRetry({interval, times}, async () => {
|
|
109
|
+
const [utxo] = (await getUtxos({lnd})).utxos;
|
|
110
|
+
|
|
111
|
+
if (!utxo) {
|
|
112
|
+
throw new Error('ExpectedUtxoInUtxos');
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
return utxo;
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
return resolve();
|
|
119
|
+
});
|
|
120
|
+
},
|
|
121
|
+
kill: lightningDocker.kill,
|
|
122
|
+
public_key: id,
|
|
123
|
+
socket: lightningDocker.ln_socket,
|
|
124
|
+
};
|
|
125
|
+
});
|
|
126
|
+
});
|
|
127
|
+
},
|
|
128
|
+
|
|
129
|
+
// Connect nodes in the cluster to each other
|
|
130
|
+
connect: ['spawn', async ({spawn}) => {
|
|
131
|
+
return await asyncEach(pairs(spawn), async pair => {
|
|
132
|
+
const [a, b] = pair.map(({chain}) => chain);
|
|
133
|
+
|
|
134
|
+
return await a.addPeer({socket: b.socket});
|
|
135
|
+
});
|
|
136
|
+
}],
|
|
137
|
+
|
|
138
|
+
// Final set of nodes
|
|
139
|
+
nodes: ['connect', 'spawn', async ({spawn}) => {
|
|
140
|
+
return {
|
|
141
|
+
kill: ({}) => asyncEach(spawn, async ({kill}) => await kill({})),
|
|
142
|
+
nodes: spawn.map(node => ({
|
|
143
|
+
generate: node.generate,
|
|
144
|
+
id: node.id,
|
|
145
|
+
kill: node.kill,
|
|
146
|
+
lnd: node.lnd,
|
|
147
|
+
socket: node.socket,
|
|
148
|
+
})),
|
|
149
|
+
};
|
|
150
|
+
}],
|
|
151
|
+
},
|
|
152
|
+
returnResult({reject, resolve, of: 'nodes'}, cbk));
|
|
153
|
+
});
|
|
154
|
+
};
|
|
@@ -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
|
|
|
@@ -62,6 +63,12 @@ module.exports = ({arguments, expose, image, ports}, cbk) => {
|
|
|
62
63
|
return;
|
|
63
64
|
}
|
|
64
65
|
|
|
66
|
+
if (err.code === 'ECONNREFUSED') {
|
|
67
|
+
throw [503, 'CannotConnectToDockerDaemon'];
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
console.log("ERR", err);
|
|
71
|
+
|
|
65
72
|
throw [503, 'UnexpectedErrorGettingDockerImage', {err}];
|
|
66
73
|
}
|
|
67
74
|
}],
|
|
@@ -121,13 +128,16 @@ module.exports = ({arguments, expose, image, ports}, cbk) => {
|
|
|
121
128
|
|
|
122
129
|
// Start the image
|
|
123
130
|
start: ['container', 'docker', ({container, docker}, cbk) => {
|
|
124
|
-
return
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
131
|
+
return asyncRetry({}, cbk => {
|
|
132
|
+
return container.start(err => {
|
|
133
|
+
if (!!err) {
|
|
134
|
+
return cbk([503, 'UnexpectedErrorStartingContainer', {err}]);
|
|
135
|
+
}
|
|
128
136
|
|
|
129
|
-
|
|
130
|
-
|
|
137
|
+
return cbk();
|
|
138
|
+
});
|
|
139
|
+
},
|
|
140
|
+
cbk);
|
|
131
141
|
}],
|
|
132
142
|
|
|
133
143
|
// Get the details about the container
|
package/index.js
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
1
|
const {spawnBitcoindDocker} = require('./bitcoind');
|
|
2
|
+
const {spawnLightningCluster} = require('./cluster');
|
|
2
3
|
const {spawnLightningDocker} = require('./lnd');
|
|
3
4
|
|
|
4
|
-
module.exports = {
|
|
5
|
+
module.exports = {
|
|
6
|
+
spawnBitcoindDocker,
|
|
7
|
+
spawnLightningCluster,
|
|
8
|
+
spawnLightningDocker,
|
|
9
|
+
};
|
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');
|
|
@@ -20,8 +22,13 @@ const spawnLndDocker = require('./spawn_lnd_docker');
|
|
|
20
22
|
|
|
21
23
|
@returns via cbk or Promise
|
|
22
24
|
{
|
|
25
|
+
add_chain_peer: <Add Peer Function> ({socket}) => {}
|
|
23
26
|
cert: <LND Base64 Serialized TLS Cert>
|
|
27
|
+
chain_socket: <Chain P2P Socket String>
|
|
28
|
+
generate: ({address, count}, cbk) => <Generate to Address Promise>
|
|
29
|
+
get_block_info: <Get Block Info Function> ({id}) => {}
|
|
24
30
|
kill: ({}, [cbk]) => <Kill LND Daemon Promise>
|
|
31
|
+
ln_socket: <LN P2P Socket String>
|
|
25
32
|
macaroon: <LND Base64 Serialized Macaroon String>
|
|
26
33
|
public_key: <Identity Public Key Hex String>
|
|
27
34
|
socket: <LND RPC Host:Port Network Address String>
|
|
@@ -113,9 +120,30 @@ module.exports = (args, cbk) => {
|
|
|
113
120
|
const dockers = [spawnChainDaemon, spawnLightningDaemon];
|
|
114
121
|
|
|
115
122
|
return cbk(null, {
|
|
123
|
+
add_chain_peer: ({socket}) => addPeer({
|
|
124
|
+
socket,
|
|
125
|
+
pass: spawnChainDaemon.rpc_pass,
|
|
126
|
+
port: args.chain_rpc_port,
|
|
127
|
+
user: spawnChainDaemon.rpc_user,
|
|
128
|
+
}),
|
|
116
129
|
cert: spawnLightningDaemon.cert,
|
|
130
|
+
chain_socket: `${spawnChainDaemon.host}`,
|
|
131
|
+
generate: ({address, count}) => generateToAddress({
|
|
132
|
+
address,
|
|
133
|
+
count,
|
|
134
|
+
pass: spawnChainDaemon.rpc_pass,
|
|
135
|
+
port: args.chain_rpc_port,
|
|
136
|
+
user: spawnChainDaemon.rpc_user,
|
|
137
|
+
}),
|
|
138
|
+
get_block_info: ({id}) => getBlockInfo({
|
|
139
|
+
id,
|
|
140
|
+
pass: spawnChainDaemon.rpc_pass,
|
|
141
|
+
port: args.chain_rpc_port,
|
|
142
|
+
user: spawnChainDaemon.rpc_user,
|
|
143
|
+
}),
|
|
117
144
|
kill: ({}, cbk) => killDockers({dockers}, cbk),
|
|
118
145
|
macaroon: spawnLightningDaemon.macaroon,
|
|
146
|
+
ln_socket: `${spawnLightningDaemon.host}:9735`,
|
|
119
147
|
public_key: spawnLightningDaemon.public_key,
|
|
120
148
|
socket: spawnLightningDaemon.socket,
|
|
121
149
|
});
|
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';
|
|
@@ -79,6 +80,8 @@ module.exports = (args, cbk) => {
|
|
|
79
80
|
|
|
80
81
|
return spawnDockerImage({
|
|
81
82
|
arguments: [
|
|
83
|
+
'--accept-keysend',
|
|
84
|
+
'--allow-circular-route',
|
|
82
85
|
'--autopilot.heuristic=externalscore:0.5',
|
|
83
86
|
'--autopilot.heuristic=preferential:0.5',
|
|
84
87
|
'--bitcoin.active',
|
|
@@ -99,7 +102,7 @@ module.exports = (args, cbk) => {
|
|
|
99
102
|
'--trickledelay=1',
|
|
100
103
|
'--unsafe-disconnect',
|
|
101
104
|
],
|
|
102
|
-
image:
|
|
105
|
+
image: imageName(process.env.DOCKER_LND_VERSION),
|
|
103
106
|
ports: {
|
|
104
107
|
'9735/tcp': args.p2p_port,
|
|
105
108
|
'10009/tcp': args.rpc_port,
|
|
@@ -123,23 +126,26 @@ module.exports = (args, cbk) => {
|
|
|
123
126
|
|
|
124
127
|
const {lnd} = unauthenticatedLndGrpc({cert, socket});
|
|
125
128
|
|
|
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 => {
|
|
129
|
+
return asyncRetry({interval, times}, cbk => {
|
|
130
|
+
return lnd.unlocker.genSeed({}, (err, res) => {
|
|
136
131
|
if (!!err) {
|
|
137
|
-
return cbk([503, '
|
|
132
|
+
return cbk([503, 'UnexpectedErrorGeneratingSeed', {err}]);
|
|
138
133
|
}
|
|
139
134
|
|
|
140
|
-
|
|
135
|
+
lnd.unlocker.initWallet({
|
|
136
|
+
cipher_seed_mnemonic: res.cipher_seed_mnemonic,
|
|
137
|
+
wallet_password: Buffer.from('password', 'utf8'),
|
|
138
|
+
},
|
|
139
|
+
err => {
|
|
140
|
+
if (!!err) {
|
|
141
|
+
return cbk([503, 'UnexpectedErrorInitializingWallet', {err}]);
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
return cbk();
|
|
145
|
+
});
|
|
141
146
|
});
|
|
142
|
-
}
|
|
147
|
+
},
|
|
148
|
+
cbk);
|
|
143
149
|
}],
|
|
144
150
|
|
|
145
151
|
// Get the macaroon out of the docker image
|
|
@@ -183,6 +189,7 @@ module.exports = (args, cbk) => {
|
|
|
183
189
|
{
|
|
184
190
|
return cbk(null, {
|
|
185
191
|
cert: getCertificate.file.toString('base64'),
|
|
192
|
+
host: spawnDocker.host,
|
|
186
193
|
kill: spawnDocker.kill,
|
|
187
194
|
macaroon: getMacaroon.file.toString('base64'),
|
|
188
195
|
public_key: waitForRpc.public_key,
|
package/package.json
CHANGED
|
@@ -8,10 +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.2",
|
|
12
|
+
"asyncjs-util": "1.2.7",
|
|
13
13
|
"dockerode": "3.3.1",
|
|
14
|
-
"
|
|
14
|
+
"find-free-ports": "3.0.0",
|
|
15
|
+
"lightning": "5.0.0",
|
|
15
16
|
"tar-stream": "2.2.0"
|
|
16
17
|
},
|
|
17
18
|
"description": "Spawn and control LN Docker daemons",
|
|
@@ -19,7 +20,7 @@
|
|
|
19
20
|
"@alexbosworth/tap": "15.0.10"
|
|
20
21
|
},
|
|
21
22
|
"engines": {
|
|
22
|
-
"node": ">=
|
|
23
|
+
"node": ">=12"
|
|
23
24
|
},
|
|
24
25
|
"keywords": [
|
|
25
26
|
"docker"
|
|
@@ -34,5 +35,5 @@
|
|
|
34
35
|
"scripts": {
|
|
35
36
|
"test": "tap --branches=1 --functions=1 --lines=1 --statements=1 -j 1 test/bitcoind/*.js test/lnd/*.js"
|
|
36
37
|
},
|
|
37
|
-
"version": "1.0
|
|
38
|
+
"version": "2.1.0"
|
|
38
39
|
}
|