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.
Files changed (42) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +11 -3
  3. package/index.js +2 -2
  4. package/package.json +5 -4
  5. package/test/integration/test_add_peer.js +26 -20
  6. package/test/integration/test_delete_pending_channel.js +5 -2
  7. package/test/integration/test_get_closed_channels.js +0 -2
  8. package/test/integration/test_get_failed_payments.js +123 -119
  9. package/test/integration/test_get_invoice.js +0 -1
  10. package/test/integration/test_get_node.js +65 -49
  11. package/test/integration/test_get_peers.js +32 -21
  12. package/test/integration/test_get_pending_force.js +1 -1
  13. package/test/integration/test_get_wallet_info.js +35 -18
  14. package/test/integration/test_open_channels.js +22 -15
  15. package/test/integration/test_pay.js +0 -1
  16. package/test/integration/test_pay_private_invoice.js +0 -1
  17. package/test/integration/test_propose_channel.js +438 -421
  18. package/test/integration/test_remove_peer.js +13 -9
  19. package/test/integration/test_send_message_to_peer.js +39 -28
  20. package/test/integration/test_subscribe_to_channels.js +1 -2
  21. package/test/integration/test_subscribe_to_invoices.js +80 -78
  22. package/test/integration/test_subscribe_to_peer_messages.js +81 -73
  23. package/test/integration/test_subscribe_to_peers.js +23 -19
  24. package/test/invoicesrpc-integration/test_get_sweep_transactions.js +0 -2
  25. package/test/invoicesrpc-integration/test_subscribe_cancel_invoice.js +0 -1
  26. package/test/macros/wait_for_channel.js +1 -1
  27. package/test/routerrpc-integration/test_delete_forwarding_reputations.js +61 -27
  28. package/test/routerrpc-integration/test_get_forwarding_reputations.js +74 -42
  29. package/test/routerrpc-integration/test_get_route_confidence.js +38 -34
  30. package/test/routerrpc-integration/test_get_route_through_hops.js +45 -17
  31. package/test/routerrpc-integration/test_multipath_payment.js +0 -1
  32. package/test/routerrpc-integration/test_pay_via_payment_details.js +118 -111
  33. package/test/routerrpc-integration/test_pay_via_payment_request.js +92 -80
  34. package/test/routerrpc-integration/test_pay_via_routes.js +19 -1
  35. package/test/routerrpc-integration/test_probe_for_route.js +78 -74
  36. package/test/routerrpc-integration/test_subscribe_to_forward_requests.js +2 -3
  37. package/test/routerrpc-integration/test_subscribe_to_forwards.js +518 -505
  38. package/test/routerrpc-integration/test_subscribe_to_past_payments.js +0 -3
  39. package/test/tower_clientrpc-integration/test_get_connected_watchtowers.js +0 -3
  40. package/test/walletrpc-integration/test_fund_psbt.js +113 -1
  41. package/test/walletrpc-integration/test_partially_sign_psbt.js +12 -5
  42. 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({psbt: combinePsbts({psbts}).psbt});
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');