ln-service 53.6.0 → 53.7.3
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 +4 -0
- package/README.md +11 -3
- package/index.js +2 -2
- package/package.json +5 -4
- package/test/integration/test_add_peer.js +26 -20
- package/test/integration/test_delete_pending_channel.js +5 -2
- package/test/integration/test_get_closed_channels.js +0 -2
- package/test/integration/test_get_failed_payments.js +123 -119
- package/test/integration/test_get_invoice.js +0 -1
- package/test/integration/test_get_node.js +65 -49
- package/test/integration/test_get_peers.js +32 -21
- package/test/integration/test_get_pending_force.js +1 -1
- package/test/integration/test_get_wallet_info.js +35 -18
- package/test/integration/test_open_channels.js +22 -15
- package/test/integration/test_pay.js +0 -1
- package/test/integration/test_pay_private_invoice.js +0 -1
- package/test/integration/test_propose_channel.js +438 -421
- package/test/integration/test_remove_peer.js +13 -9
- package/test/integration/test_send_message_to_peer.js +39 -28
- package/test/integration/test_subscribe_to_channels.js +1 -2
- package/test/integration/test_subscribe_to_invoices.js +80 -78
- package/test/integration/test_subscribe_to_peer_messages.js +81 -73
- package/test/integration/test_subscribe_to_peers.js +23 -19
- package/test/invoicesrpc-integration/test_get_sweep_transactions.js +0 -2
- package/test/invoicesrpc-integration/test_subscribe_cancel_invoice.js +0 -1
- package/test/macros/wait_for_channel.js +1 -1
- package/test/routerrpc-integration/test_delete_forwarding_reputations.js +61 -27
- package/test/routerrpc-integration/test_get_forwarding_reputations.js +74 -42
- package/test/routerrpc-integration/test_get_route_confidence.js +38 -34
- package/test/routerrpc-integration/test_get_route_through_hops.js +45 -17
- package/test/routerrpc-integration/test_multipath_payment.js +0 -1
- package/test/routerrpc-integration/test_pay_via_payment_details.js +118 -111
- package/test/routerrpc-integration/test_pay_via_payment_request.js +92 -80
- package/test/routerrpc-integration/test_pay_via_routes.js +19 -1
- package/test/routerrpc-integration/test_probe_for_route.js +78 -74
- package/test/routerrpc-integration/test_subscribe_to_forward_requests.js +2 -3
- package/test/routerrpc-integration/test_subscribe_to_forwards.js +518 -505
- package/test/routerrpc-integration/test_subscribe_to_past_payments.js +0 -3
- package/test/tower_clientrpc-integration/test_get_connected_watchtowers.js +0 -3
- package/test/walletrpc-integration/test_fund_psbt.js +113 -1
- package/test/walletrpc-integration/test_partially_sign_psbt.js +12 -5
- package/test/walletrpc-integration/test_sign_psbt.js +4 -1
|
@@ -2,11 +2,8 @@ const asyncRetry = require('async/retry');
|
|
|
2
2
|
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
3
3
|
const {test} = require('@alexbosworth/tap');
|
|
4
4
|
|
|
5
|
-
const {addPeer} = require('./../../');
|
|
6
5
|
const {createInvoice} = require('./../../');
|
|
7
6
|
const {delay} = require('./../macros');
|
|
8
|
-
const {getChannels} = require('./../../');
|
|
9
|
-
const {getHeight} = require('./../../');
|
|
10
7
|
const {getPayment} = require('./../../');
|
|
11
8
|
const {payViaPaymentRequest} = require('./../../');
|
|
12
9
|
const {setupChannel} = require('./../macros');
|
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
const {test} = require('@alexbosworth/tap');
|
|
2
2
|
|
|
3
|
-
const {closeChannel} = require('./../../');
|
|
4
3
|
const {connectWatchtower} = require('./../../');
|
|
5
|
-
const {createInvoice} = require('./../../');
|
|
6
4
|
const {createCluster} = require('./../macros');
|
|
7
5
|
const {delay} = require('./../macros');
|
|
8
6
|
const {disconnectWatchtower} = require('./../../');
|
|
9
|
-
const {getChannels} = require('./../../');
|
|
10
7
|
const {getConnectedWatchtowers} = require('./../../');
|
|
11
8
|
const {getTowerServerInfo} = require('./../../');
|
|
12
9
|
const {openChannel} = require('./../../');
|
|
@@ -1,29 +1,55 @@
|
|
|
1
1
|
const asyncRetry = require('async/retry');
|
|
2
2
|
const {address} = require('bitcoinjs-lib');
|
|
3
|
+
const {createPsbt} = require('psbt');
|
|
4
|
+
const {crypto} = require('bitcoinjs-lib');
|
|
3
5
|
const {decodePsbt} = require('psbt');
|
|
6
|
+
const {networks} = require('bitcoinjs-lib');
|
|
7
|
+
const {script} = require('bitcoinjs-lib');
|
|
4
8
|
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
5
9
|
const {test} = require('@alexbosworth/tap');
|
|
10
|
+
const tinysecp = require('tiny-secp256k1');
|
|
11
|
+
const {Transaction} = require('bitcoinjs-lib');
|
|
6
12
|
|
|
13
|
+
const {broadcastChainTransaction} = require('./../../');
|
|
7
14
|
const {createChainAddress} = require('./../../');
|
|
8
15
|
const {fundPsbt} = require('./../../');
|
|
9
16
|
const {getChainBalance} = require('./../../');
|
|
10
17
|
const {getChainTransactions} = require('./../../');
|
|
11
18
|
const {getUtxos} = require('./../../');
|
|
12
19
|
const {sendToChainAddress} = require('./../../');
|
|
20
|
+
const {signPsbt} = require('./../../');
|
|
13
21
|
|
|
14
22
|
const chainAddressRowType = 'chain_address';
|
|
23
|
+
const {compile} = script;
|
|
15
24
|
const confirmationCount = 6;
|
|
16
25
|
const count = 100;
|
|
17
26
|
const description = 'description';
|
|
27
|
+
const extra = Buffer.alloc(32);
|
|
18
28
|
const {fromBech32} = address;
|
|
29
|
+
const {fromHex} = Transaction;
|
|
30
|
+
const {fromOutputScript} = address;
|
|
31
|
+
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
|
|
19
32
|
const interval = retryCount => 10 * Math.pow(2, retryCount);
|
|
33
|
+
const isLowPublicKey = keyPair => keyPair.publicKey[0] === 2;
|
|
34
|
+
const makeTaprootKey = (k, h) => tinysecp.xOnlyPointAddTweak(k, h).xOnlyPubkey;
|
|
35
|
+
const nLess1 = 'fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364140';
|
|
36
|
+
const one256BitBigEndian = '0000000000000000000000000000000000000000000000000000000000000001';
|
|
37
|
+
const OP_1 = 81;
|
|
38
|
+
const {privateAdd} = tinysecp;
|
|
39
|
+
const {privateSub} = tinysecp;
|
|
20
40
|
const regtestBech32AddressHrp = 'bcrt';
|
|
41
|
+
const shortKey = keyPair => keyPair.publicKey.slice(1, 33);
|
|
42
|
+
const {signSchnorr} = tinysecp;
|
|
43
|
+
const smallTokens = 2e5;
|
|
44
|
+
const tapHash = k => crypto.taggedHash('TapTweak', k.publicKey.slice(1, 33));
|
|
21
45
|
const times = 20;
|
|
46
|
+
const {toOutputScript} = address;
|
|
22
47
|
const tokens = 1e6;
|
|
23
48
|
const txIdHexByteLength = 64;
|
|
24
49
|
|
|
25
50
|
// Funding a transaction should result in a funded PSBT
|
|
26
51
|
test(`Fund PSBT`, async ({end, equal}) => {
|
|
52
|
+
const ecp = (await import('ecpair')).ECPairFactory(tinysecp);
|
|
27
53
|
const {kill, nodes} = await spawnLightningCluster({});
|
|
28
54
|
|
|
29
55
|
const [{generate, lnd}] = nodes;
|
|
@@ -86,7 +112,7 @@ test(`Fund PSBT`, async ({end, equal}) => {
|
|
|
86
112
|
|
|
87
113
|
equal(output.output_script, expectedOutput, 'Got expected output script');
|
|
88
114
|
|
|
89
|
-
const decoded = decodePsbt({psbt: funded.psbt});
|
|
115
|
+
const decoded = decodePsbt({ecp, psbt: funded.psbt});
|
|
90
116
|
|
|
91
117
|
const [decodedInput] = decoded.inputs;
|
|
92
118
|
|
|
@@ -94,6 +120,92 @@ test(`Fund PSBT`, async ({end, equal}) => {
|
|
|
94
120
|
equal(!!decodedInput.witness_utxo.script_pub, true, 'PSBT input address');
|
|
95
121
|
equal(decodedInput.witness_utxo.tokens, 5000000000, 'PSBT has input tokens');
|
|
96
122
|
|
|
123
|
+
// A Taproot output should be funded
|
|
124
|
+
try {
|
|
125
|
+
await generate({count});
|
|
126
|
+
|
|
127
|
+
const keyPair = ecp.makeRandom({network: networks.regtest});
|
|
128
|
+
|
|
129
|
+
const outputKey = makeTaprootKey(shortKey(keyPair), tapHash(keyPair));
|
|
130
|
+
const tweakHash = tapHash(keyPair);
|
|
131
|
+
|
|
132
|
+
const outputScript = compile([OP_1, Buffer.from(outputKey)]);
|
|
133
|
+
|
|
134
|
+
const [utxo] = (await getUtxos({lnd})).utxos.reverse();
|
|
135
|
+
|
|
136
|
+
// Make a PSBT paying to the Taproot output
|
|
137
|
+
const {psbt} = createPsbt({
|
|
138
|
+
outputs: [{tokens, script: outputScript.toString('hex')}],
|
|
139
|
+
utxos: [{id: utxo.transaction_id, vout: utxo.transaction_vout}],
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
// Sign the PSBT
|
|
143
|
+
const signed = await signPsbt({
|
|
144
|
+
lnd,
|
|
145
|
+
psbt: (await fundPsbt({lnd, psbt})).psbt,
|
|
146
|
+
});
|
|
147
|
+
|
|
148
|
+
// Send the tx to the chain
|
|
149
|
+
await broadcastChainTransaction({lnd, transaction: signed.transaction});
|
|
150
|
+
|
|
151
|
+
// Make a new tx that will spend the output back into the wallet
|
|
152
|
+
const tx = new Transaction();
|
|
153
|
+
|
|
154
|
+
// The new tx spends the Taproot output
|
|
155
|
+
tx.addInput(
|
|
156
|
+
fromHex(signed.transaction).getHash(),
|
|
157
|
+
fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
// Make an output to pay back into the wallet
|
|
161
|
+
const chainOutput = toOutputScript(
|
|
162
|
+
(await createChainAddress({lnd})).address,
|
|
163
|
+
networks.regtest
|
|
164
|
+
);
|
|
165
|
+
|
|
166
|
+
// Add output to the pay back transaction
|
|
167
|
+
tx.addOutput(chainOutput, smallTokens);
|
|
168
|
+
|
|
169
|
+
const [hashToSign] = tx.ins.map((input, i) => {
|
|
170
|
+
return tx.hashForWitnessV1(
|
|
171
|
+
i,
|
|
172
|
+
[outputScript],
|
|
173
|
+
[tokens],
|
|
174
|
+
Transaction.SIGHASH_DEFAULT,
|
|
175
|
+
);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const isLow = isLowPublicKey(keyPair);
|
|
179
|
+
const ONE = hexAsBuffer(one256BitBigEndian);
|
|
180
|
+
const subtract = privateSub(hexAsBuffer(nLess1), keyPair.privateKey);
|
|
181
|
+
|
|
182
|
+
const privateKey = isLow ? keyPair.privateKey : privateAdd(subtract, ONE);
|
|
183
|
+
|
|
184
|
+
// Only low keys are allowed to save a leading byte on the public key
|
|
185
|
+
const lowPrivateKey = privateAdd(privateKey, tweakHash);
|
|
186
|
+
|
|
187
|
+
const signature = signSchnorr(hashToSign, lowPrivateKey, extra);
|
|
188
|
+
|
|
189
|
+
// Add the signature to the input
|
|
190
|
+
tx.ins.forEach((input, i) => tx.setWitness(i, [Buffer.from(signature)]));
|
|
191
|
+
|
|
192
|
+
await broadcastChainTransaction({lnd, transaction: tx.toHex()});
|
|
193
|
+
|
|
194
|
+
await asyncRetry({interval, times}, async () => {
|
|
195
|
+
await generate({});
|
|
196
|
+
|
|
197
|
+
const {utxos} = await getUtxos({lnd});
|
|
198
|
+
|
|
199
|
+
const utxo = utxos.find(n => n.transaction_id === tx.getId());
|
|
200
|
+
|
|
201
|
+
if (!utxo || !utxo.confirmation_count) {
|
|
202
|
+
throw new Error('ExpectedReceivedTaprootSpend');
|
|
203
|
+
}
|
|
204
|
+
});
|
|
205
|
+
} catch (err) {
|
|
206
|
+
equal(err, null, 'Expected no error');
|
|
207
|
+
}
|
|
208
|
+
|
|
97
209
|
await kill({});
|
|
98
210
|
|
|
99
211
|
return end();
|
|
@@ -8,6 +8,7 @@ const {extractTransaction} = require('psbt');
|
|
|
8
8
|
const {finalizePsbt} = require('psbt');
|
|
9
9
|
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
10
10
|
const {test} = require('@alexbosworth/tap');
|
|
11
|
+
const tinysecp = require('tiny-secp256k1');
|
|
11
12
|
const {Transaction} = require('bitcoinjs-lib');
|
|
12
13
|
const {updatePsbt} = require('psbt');
|
|
13
14
|
|
|
@@ -30,6 +31,8 @@ const tokens = 1e6;
|
|
|
30
31
|
|
|
31
32
|
// Partially signing a PSBT should result in a partially signed PSBT
|
|
32
33
|
test(`Partially sign PSBT`, async ({end, equal, strictSame}) => {
|
|
34
|
+
const ecp = (await import('ecpair')).ECPairFactory(tinysecp);
|
|
35
|
+
|
|
33
36
|
const {kill, nodes} = await spawnLightningCluster({size});
|
|
34
37
|
|
|
35
38
|
const [control, target, remote] = nodes;
|
|
@@ -125,9 +128,9 @@ test(`Partially sign PSBT`, async ({end, equal, strictSame}) => {
|
|
|
125
128
|
});
|
|
126
129
|
|
|
127
130
|
// Decode the PSBTs to get signing key details
|
|
128
|
-
const controlDecoded = decodePsbt({psbt: controlFund.psbt});
|
|
129
|
-
const targetDecoded = decodePsbt({psbt: targetFund.psbt});
|
|
130
|
-
const remoteDecoded = decodePsbt({psbt: remoteFund.psbt});
|
|
131
|
+
const controlDecoded = decodePsbt({ecp, psbt: controlFund.psbt});
|
|
132
|
+
const targetDecoded = decodePsbt({ecp, psbt: targetFund.psbt});
|
|
133
|
+
const remoteDecoded = decodePsbt({ecp, psbt: remoteFund.psbt});
|
|
131
134
|
|
|
132
135
|
// Collect all the BIP32 derivations
|
|
133
136
|
const controlBip32Derivations = controlDecoded.inputs
|
|
@@ -157,6 +160,7 @@ test(`Partially sign PSBT`, async ({end, equal, strictSame}) => {
|
|
|
157
160
|
|
|
158
161
|
// Update the PSBT so that it has the consolidated details
|
|
159
162
|
const updated = updatePsbt({
|
|
163
|
+
ecp,
|
|
160
164
|
bip32_derivations: bip32Derivations,
|
|
161
165
|
psbt: base.psbt,
|
|
162
166
|
sighashes: inputs.map(input => ({
|
|
@@ -175,10 +179,13 @@ test(`Partially sign PSBT`, async ({end, equal, strictSame}) => {
|
|
|
175
179
|
});
|
|
176
180
|
|
|
177
181
|
// Finalize the signatures
|
|
178
|
-
const finalize = finalizePsbt({
|
|
182
|
+
const finalize = finalizePsbt({
|
|
183
|
+
ecp,
|
|
184
|
+
psbt: combinePsbts({ecp, psbts}).psbt,
|
|
185
|
+
});
|
|
179
186
|
|
|
180
187
|
// Pull out the transaction
|
|
181
|
-
const {transaction} = extractTransaction({psbt: finalize.psbt});
|
|
188
|
+
const {transaction} = extractTransaction({ecp, psbt: finalize.psbt});
|
|
182
189
|
|
|
183
190
|
// Publish the transaction
|
|
184
191
|
await broadcastChainTransaction({lnd: control.lnd, transaction});
|
|
@@ -3,6 +3,7 @@ const {address} = require('bitcoinjs-lib');
|
|
|
3
3
|
const {decodePsbt} = require('psbt');
|
|
4
4
|
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
5
5
|
const {test} = require('@alexbosworth/tap');
|
|
6
|
+
const tinysecp = require('tiny-secp256k1');
|
|
6
7
|
const {Transaction} = require('bitcoinjs-lib');
|
|
7
8
|
|
|
8
9
|
const {broadcastChainTransaction} = require('./../../');
|
|
@@ -29,6 +30,8 @@ const txIdHexByteLength = 64;
|
|
|
29
30
|
|
|
30
31
|
// Signing a PSBT should result in a finalized PSBT
|
|
31
32
|
test(`Sign PSBT`, async ({end, equal}) => {
|
|
33
|
+
const ecp = (await import('ecpair')).ECPairFactory(tinysecp);
|
|
34
|
+
|
|
32
35
|
const {kill, nodes} = await spawnLightningCluster({size});
|
|
33
36
|
|
|
34
37
|
const [control, target] = nodes;
|
|
@@ -72,7 +75,7 @@ test(`Sign PSBT`, async ({end, equal}) => {
|
|
|
72
75
|
|
|
73
76
|
const tx = Transaction.fromHex(finalized.transaction);
|
|
74
77
|
|
|
75
|
-
const decoded = decodePsbt({psbt: finalized.psbt});
|
|
78
|
+
const decoded = decodePsbt({ecp, psbt: finalized.psbt});
|
|
76
79
|
|
|
77
80
|
equal(!!decoded, true, 'Got a finalized PSBT');
|
|
78
81
|
equal(!!tx, true, 'Got a raw signed transaction');
|