ln-service 59.3.2 → 59.3.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 +1 -1
- package/package.json +11 -10
- package/test/integration/test_propose_channel.js +35 -54
- package/test/macros/index.js +0 -16
- package/test/signerrpc-integration/test_begin_group_signing_session.js +159 -97
- package/test/signerrpc-integration/test_sign_taproot.js +136 -68
- package/test/walletrpc-integration/test_fund_psbt.js +169 -100
- package/test/macros/btcsuite_type_daemon.js +0 -143
- package/test/macros/chain_send_transaction.js +0 -102
- package/test/macros/change_password.js +0 -441
- package/test/macros/connect_chain_node.js +0 -27
- package/test/macros/create_cluster.js +0 -426
- package/test/macros/generate_blocks.js +0 -141
- package/test/macros/get_raw_transaction.js +0 -78
- package/test/macros/mine_transaction.js +0 -87
- package/test/macros/rpc.js +0 -82
- package/test/macros/spawn_chain_daemon.js +0 -88
- package/test/macros/spawn_lnd.js +0 -558
|
@@ -2,15 +2,18 @@ const {equal} = require('node:assert').strict;
|
|
|
2
2
|
const test = require('node:test');
|
|
3
3
|
|
|
4
4
|
const asyncRetry = require('async/retry');
|
|
5
|
-
const {
|
|
5
|
+
const {componentsOfTransaction} = require('@alexbosworth/blockchain');
|
|
6
6
|
const {controlBlock} = require('p2tr');
|
|
7
7
|
const {createPsbt} = require('psbt');
|
|
8
|
+
const {decodeBech32Address} = require('@alexbosworth/blockchain');
|
|
8
9
|
const {hashForTree} = require('p2tr');
|
|
9
|
-
const {
|
|
10
|
-
const {
|
|
10
|
+
const {idForTransaction} = require('@alexbosworth/blockchain');
|
|
11
|
+
const {p2trOutputScript} = require('@alexbosworth/blockchain');
|
|
12
|
+
const {p2wpkhOutputScript} = require('@alexbosworth/blockchain');
|
|
11
13
|
const {scriptElementsAsScript} = require('@alexbosworth/blockchain');
|
|
12
14
|
const {spawnLightningCluster} = require('ln-docker-daemons');
|
|
13
|
-
const {
|
|
15
|
+
const {transactionFromComponents} = require('@alexbosworth/blockchain');
|
|
16
|
+
const {v1HashToSign} = require('p2tr');
|
|
14
17
|
const {v1OutputScript} = require('p2tr');
|
|
15
18
|
|
|
16
19
|
const {beginGroupSigningSession} = require('./../../');
|
|
@@ -23,19 +26,26 @@ const {getUtxos} = require('./../../');
|
|
|
23
26
|
const {signPsbt} = require('./../../');
|
|
24
27
|
const {updateGroupSigningSession} = require('./../../');
|
|
25
28
|
|
|
29
|
+
const bufferAsHex = buffer => buffer.toString('hex');
|
|
26
30
|
const compile = elements => scriptElementsAsScript({elements}).script;
|
|
31
|
+
const componentsOfTx = tx => componentsOfTransaction({transaction: tx});
|
|
27
32
|
const count = 100;
|
|
28
33
|
const defaultInternalKey = '0350929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';
|
|
29
|
-
const
|
|
30
|
-
const
|
|
34
|
+
const defaultLocktime = 0;
|
|
35
|
+
const defaultSequence = 0xffffffff;
|
|
36
|
+
const defaultTxVersion = 1;
|
|
37
|
+
const emptyScriptSig = '';
|
|
31
38
|
const hexAsBuffer = hex => Buffer.from(hex, 'hex');
|
|
39
|
+
const idForTx = transaction => idForTransaction({transaction}).id;
|
|
32
40
|
const interval = 100;
|
|
33
41
|
const OP_CHECKSIG = 172;
|
|
42
|
+
const p2tr = hash => bufferAsHex(p2trOutputScript({hash}).script);
|
|
43
|
+
const p2wpkh = hash => p2wpkhOutputScript({hash}).script;
|
|
34
44
|
const size = 2;
|
|
35
45
|
const smallTokens = 2e5;
|
|
36
46
|
const times = 20;
|
|
37
|
-
const {toOutputScript} = address;
|
|
38
47
|
const tokens = 1e6;
|
|
48
|
+
const transactionSighashDefault = 0;
|
|
39
49
|
|
|
40
50
|
// Starting a group signing session should result in a new MuSig2 session
|
|
41
51
|
test(`Begin group signing session`, async () => {
|
|
@@ -88,17 +98,13 @@ test(`Begin group signing session`, async () => {
|
|
|
88
98
|
equal(controlGroup.external_key, targetGroup.external_key, 'Equal e-keys');
|
|
89
99
|
equal(controlGroup.internal_key, targetGroup.internal_key, 'Equal i-keys');
|
|
90
100
|
|
|
91
|
-
const script =
|
|
92
|
-
Buffer.from([81]),
|
|
93
|
-
Buffer.from([32]),
|
|
94
|
-
hexAsBuffer(controlGroup.external_key),
|
|
95
|
-
]);
|
|
101
|
+
const script = p2tr(hexAsBuffer(controlGroup.external_key));
|
|
96
102
|
|
|
97
103
|
const [utxo] = (await getUtxos({lnd})).utxos.reverse();
|
|
98
104
|
|
|
99
105
|
// Make a PSBT paying to the Taproot output
|
|
100
106
|
const {psbt} = createPsbt({
|
|
101
|
-
outputs: [{tokens, script
|
|
107
|
+
outputs: [{tokens, script}],
|
|
102
108
|
utxos: [{id: utxo.transaction_id, vout: utxo.transaction_vout}],
|
|
103
109
|
});
|
|
104
110
|
|
|
@@ -111,42 +117,53 @@ test(`Begin group signing session`, async () => {
|
|
|
111
117
|
// Send the tx to the chain
|
|
112
118
|
await broadcastChainTransaction({lnd, transaction: signed.transaction});
|
|
113
119
|
|
|
114
|
-
|
|
115
|
-
const tx = new Transaction();
|
|
120
|
+
const spends = componentsOfTx(signed.transaction).outputs;
|
|
116
121
|
|
|
117
122
|
// The new tx spends the Taproot output
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
123
|
+
const inputs = [{
|
|
124
|
+
id: idForTx(signed.transaction),
|
|
125
|
+
script: emptyScriptSig,
|
|
126
|
+
sequence: defaultSequence,
|
|
127
|
+
vout: spends.findIndex(n => n.tokens === tokens),
|
|
128
|
+
}];
|
|
122
129
|
|
|
123
130
|
// Make an output to pay back into the wallet
|
|
124
|
-
const
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
);
|
|
131
|
+
const chainAddress = await createChainAddress({lnd});
|
|
132
|
+
|
|
133
|
+
const {program} = decodeBech32Address({address: chainAddress.address});
|
|
128
134
|
|
|
129
135
|
// Add output to the pay back transaction
|
|
130
|
-
|
|
136
|
+
const outputs = [{
|
|
137
|
+
script: bufferAsHex(p2wpkh(program)),
|
|
138
|
+
tokens: smallTokens,
|
|
139
|
+
}];
|
|
140
|
+
|
|
141
|
+
// Make a new tx that will spend the output back into the wallet
|
|
142
|
+
const unsigned = transactionFromComponents({
|
|
143
|
+
inputs,
|
|
144
|
+
outputs,
|
|
145
|
+
locktime: defaultLocktime,
|
|
146
|
+
version: defaultTxVersion,
|
|
147
|
+
});
|
|
131
148
|
|
|
132
|
-
const [hashToSign] =
|
|
133
|
-
return
|
|
134
|
-
|
|
135
|
-
[script],
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
);
|
|
149
|
+
const [hashToSign] = inputs.map((input, i) => {
|
|
150
|
+
return v1HashToSign({
|
|
151
|
+
sighash: transactionSighashDefault,
|
|
152
|
+
spends: [{script, tokens}],
|
|
153
|
+
transaction: unsigned.transaction,
|
|
154
|
+
vin: i,
|
|
155
|
+
}).hash;
|
|
139
156
|
});
|
|
140
157
|
|
|
141
158
|
const controlSign = await updateGroupSigningSession({
|
|
142
159
|
lnd,
|
|
143
|
-
hash: hashToSign
|
|
160
|
+
hash: hashToSign,
|
|
144
161
|
id: controlGroup.id,
|
|
145
162
|
nonces: [targetGroup.nonce],
|
|
146
163
|
});
|
|
147
164
|
|
|
148
165
|
const targetSign = await updateGroupSigningSession({
|
|
149
|
-
hash: hashToSign
|
|
166
|
+
hash: hashToSign,
|
|
150
167
|
id: targetGroup.id,
|
|
151
168
|
lnd: target.lnd,
|
|
152
169
|
nonces: [controlGroup.nonce],
|
|
@@ -160,17 +177,28 @@ test(`Begin group signing session`, async () => {
|
|
|
160
177
|
signatures: [targetSign.signature],
|
|
161
178
|
});
|
|
162
179
|
|
|
163
|
-
// Add the signature to the input
|
|
164
|
-
|
|
180
|
+
// Add the signature to the input and serialize the signed transaction
|
|
181
|
+
const {transaction} = transactionFromComponents({
|
|
182
|
+
outputs,
|
|
183
|
+
inputs: inputs.map(input => ({
|
|
184
|
+
id: input.id,
|
|
185
|
+
script: input.script,
|
|
186
|
+
sequence: input.sequence,
|
|
187
|
+
vout: input.vout,
|
|
188
|
+
witness: [signature],
|
|
189
|
+
})),
|
|
190
|
+
locktime: defaultLocktime,
|
|
191
|
+
version: defaultTxVersion,
|
|
192
|
+
});
|
|
165
193
|
|
|
166
|
-
await broadcastChainTransaction({lnd, transaction
|
|
194
|
+
await broadcastChainTransaction({lnd, transaction});
|
|
167
195
|
|
|
168
196
|
await asyncRetry({interval, times}, async () => {
|
|
169
197
|
await generate({});
|
|
170
198
|
|
|
171
199
|
const {utxos} = await getUtxos({lnd});
|
|
172
200
|
|
|
173
|
-
const utxo = utxos.find(n => n.transaction_id ===
|
|
201
|
+
const utxo = utxos.find(n => n.transaction_id === idForTx(transaction));
|
|
174
202
|
|
|
175
203
|
if (!utxo || !utxo.confirmation_count) {
|
|
176
204
|
throw new Error('ExpectedReceivedTaprootSpend');
|
|
@@ -215,17 +243,13 @@ test(`Begin group signing session`, async () => {
|
|
|
215
243
|
equal(controlGroup.external_key, targetGroup.external_key, 'Equal e-keys');
|
|
216
244
|
equal(controlGroup.internal_key, targetGroup.internal_key, 'Equal i-keys');
|
|
217
245
|
|
|
218
|
-
const script =
|
|
219
|
-
from([81]),
|
|
220
|
-
from([32]),
|
|
221
|
-
hexAsBuffer(controlGroup.external_key),
|
|
222
|
-
]);
|
|
246
|
+
const script = p2tr(hexAsBuffer(controlGroup.external_key));
|
|
223
247
|
|
|
224
248
|
const [utxo] = (await getUtxos({lnd})).utxos.reverse();
|
|
225
249
|
|
|
226
250
|
// Make a PSBT paying to the Taproot output
|
|
227
251
|
const {psbt} = createPsbt({
|
|
228
|
-
outputs: [{tokens, script
|
|
252
|
+
outputs: [{tokens, script}],
|
|
229
253
|
utxos: [{id: utxo.transaction_id, vout: utxo.transaction_vout}],
|
|
230
254
|
});
|
|
231
255
|
|
|
@@ -238,42 +262,53 @@ test(`Begin group signing session`, async () => {
|
|
|
238
262
|
// Send the tx to the chain
|
|
239
263
|
await broadcastChainTransaction({lnd, transaction: signed.transaction});
|
|
240
264
|
|
|
241
|
-
|
|
242
|
-
const tx = new Transaction();
|
|
265
|
+
const spends = componentsOfTx(signed.transaction).outputs;
|
|
243
266
|
|
|
244
267
|
// The new tx spends the Taproot output
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
268
|
+
const inputs = [{
|
|
269
|
+
id: idForTx(signed.transaction),
|
|
270
|
+
script: emptyScriptSig,
|
|
271
|
+
sequence: defaultSequence,
|
|
272
|
+
vout: spends.findIndex(n => n.tokens === tokens),
|
|
273
|
+
}];
|
|
249
274
|
|
|
250
275
|
// Make an output to pay back into the wallet
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
);
|
|
276
|
+
const chainAddress = await createChainAddress({lnd});
|
|
277
|
+
|
|
278
|
+
const {program} = decodeBech32Address({address: chainAddress.address});
|
|
255
279
|
|
|
256
280
|
// Add output to the pay back transaction
|
|
257
|
-
|
|
281
|
+
const outputs = [{
|
|
282
|
+
script: bufferAsHex(p2wpkh(program)),
|
|
283
|
+
tokens: smallTokens,
|
|
284
|
+
}];
|
|
258
285
|
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
286
|
+
// Make a new tx that will spend the output back into the wallet
|
|
287
|
+
const unsigned = transactionFromComponents({
|
|
288
|
+
inputs,
|
|
289
|
+
outputs,
|
|
290
|
+
locktime: defaultLocktime,
|
|
291
|
+
version: defaultTxVersion,
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
const [hashToSign] = inputs.map((input, i) => {
|
|
295
|
+
return v1HashToSign({
|
|
296
|
+
sighash: transactionSighashDefault,
|
|
297
|
+
spends: [{script, tokens}],
|
|
298
|
+
transaction: unsigned.transaction,
|
|
299
|
+
vin: i,
|
|
300
|
+
}).hash;
|
|
266
301
|
});
|
|
267
302
|
|
|
268
303
|
const controlSign = await updateGroupSigningSession({
|
|
269
304
|
lnd,
|
|
270
|
-
hash: hashToSign
|
|
305
|
+
hash: hashToSign,
|
|
271
306
|
id: controlGroup.id,
|
|
272
307
|
nonces: [targetGroup.nonce],
|
|
273
308
|
});
|
|
274
309
|
|
|
275
310
|
const targetSign = await updateGroupSigningSession({
|
|
276
|
-
hash: hashToSign
|
|
311
|
+
hash: hashToSign,
|
|
277
312
|
id: targetGroup.id,
|
|
278
313
|
lnd: target.lnd,
|
|
279
314
|
nonces: [controlGroup.nonce],
|
|
@@ -287,17 +322,28 @@ test(`Begin group signing session`, async () => {
|
|
|
287
322
|
signatures: [targetSign.signature],
|
|
288
323
|
});
|
|
289
324
|
|
|
290
|
-
// Add the signature to the input
|
|
291
|
-
|
|
325
|
+
// Add the signature to the input and serialize the signed transaction
|
|
326
|
+
const {transaction} = transactionFromComponents({
|
|
327
|
+
outputs,
|
|
328
|
+
inputs: inputs.map(input => ({
|
|
329
|
+
id: input.id,
|
|
330
|
+
script: input.script,
|
|
331
|
+
sequence: input.sequence,
|
|
332
|
+
vout: input.vout,
|
|
333
|
+
witness: [signature],
|
|
334
|
+
})),
|
|
335
|
+
locktime: defaultLocktime,
|
|
336
|
+
version: defaultTxVersion,
|
|
337
|
+
});
|
|
292
338
|
|
|
293
|
-
await broadcastChainTransaction({lnd, transaction
|
|
339
|
+
await broadcastChainTransaction({lnd, transaction});
|
|
294
340
|
|
|
295
341
|
await asyncRetry({interval, times}, async () => {
|
|
296
342
|
await generate({});
|
|
297
343
|
|
|
298
344
|
const {utxos} = await getUtxos({lnd});
|
|
299
345
|
|
|
300
|
-
const utxo = utxos.find(n => n.transaction_id ===
|
|
346
|
+
const utxo = utxos.find(n => n.transaction_id === idForTx(transaction));
|
|
301
347
|
|
|
302
348
|
if (!utxo || !utxo.confirmation_count) {
|
|
303
349
|
throw new Error('ExpectedReceivedTaprootSpend');
|
|
@@ -355,43 +401,54 @@ test(`Begin group signing session`, async () => {
|
|
|
355
401
|
// Send the tx to the chain
|
|
356
402
|
await broadcastChainTransaction({lnd, transaction: signed.transaction});
|
|
357
403
|
|
|
358
|
-
|
|
359
|
-
const tx = new Transaction();
|
|
404
|
+
const spends = componentsOfTx(signed.transaction).outputs;
|
|
360
405
|
|
|
361
406
|
// The new tx spends the Taproot output
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
407
|
+
const inputs = [{
|
|
408
|
+
id: idForTx(signed.transaction),
|
|
409
|
+
script: emptyScriptSig,
|
|
410
|
+
sequence: defaultSequence,
|
|
411
|
+
vout: spends.findIndex(n => n.tokens === tokens),
|
|
412
|
+
}];
|
|
366
413
|
|
|
367
414
|
// Make an output to pay back into the wallet
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
);
|
|
415
|
+
const chainAddress = await createChainAddress({lnd});
|
|
416
|
+
|
|
417
|
+
const {program} = decodeBech32Address({address: chainAddress.address});
|
|
372
418
|
|
|
373
419
|
// Add output to the pay back transaction
|
|
374
|
-
|
|
420
|
+
const outputs = [{
|
|
421
|
+
script: bufferAsHex(p2wpkh(program)),
|
|
422
|
+
tokens: smallTokens,
|
|
423
|
+
}];
|
|
424
|
+
|
|
425
|
+
// Make a new tx that will spend the output back into the wallet
|
|
426
|
+
const unsigned = transactionFromComponents({
|
|
427
|
+
inputs,
|
|
428
|
+
outputs,
|
|
429
|
+
locktime: defaultLocktime,
|
|
430
|
+
version: defaultTxVersion,
|
|
431
|
+
});
|
|
375
432
|
|
|
376
|
-
const [hashToSign] =
|
|
377
|
-
return
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
[tokens],
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
);
|
|
433
|
+
const [hashToSign] = inputs.map((input, i) => {
|
|
434
|
+
return v1HashToSign({
|
|
435
|
+
leaf: {script: witnessScript},
|
|
436
|
+
sighash: transactionSighashDefault,
|
|
437
|
+
spends: [{tokens, script: output.script}],
|
|
438
|
+
transaction: unsigned.transaction,
|
|
439
|
+
vin: i,
|
|
440
|
+
}).hash;
|
|
384
441
|
});
|
|
385
442
|
|
|
386
443
|
const controlSign = await updateGroupSigningSession({
|
|
387
444
|
lnd,
|
|
388
|
-
hash: hashToSign
|
|
445
|
+
hash: hashToSign,
|
|
389
446
|
id: controlGroup.id,
|
|
390
447
|
nonces: [targetGroup.nonce],
|
|
391
448
|
});
|
|
392
449
|
|
|
393
450
|
const targetSign = await updateGroupSigningSession({
|
|
394
|
-
hash: hashToSign
|
|
451
|
+
hash: hashToSign,
|
|
395
452
|
id: targetGroup.id,
|
|
396
453
|
lnd: target.lnd,
|
|
397
454
|
nonces: [controlGroup.nonce],
|
|
@@ -411,23 +468,28 @@ test(`Begin group signing session`, async () => {
|
|
|
411
468
|
script_branches: branches,
|
|
412
469
|
});
|
|
413
470
|
|
|
414
|
-
// Add the signature to the input
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
471
|
+
// Add the signature to the input and serialize the signed transaction
|
|
472
|
+
const {transaction} = transactionFromComponents({
|
|
473
|
+
outputs,
|
|
474
|
+
inputs: inputs.map(input => ({
|
|
475
|
+
id: input.id,
|
|
476
|
+
script: input.script,
|
|
477
|
+
sequence: input.sequence,
|
|
478
|
+
vout: input.vout,
|
|
479
|
+
witness: [signature, witnessScript, block],
|
|
480
|
+
})),
|
|
481
|
+
locktime: defaultLocktime,
|
|
482
|
+
version: defaultTxVersion,
|
|
421
483
|
});
|
|
422
484
|
|
|
423
|
-
await broadcastChainTransaction({lnd, transaction
|
|
485
|
+
await broadcastChainTransaction({lnd, transaction});
|
|
424
486
|
|
|
425
487
|
await asyncRetry({interval, times}, async () => {
|
|
426
488
|
await generate({});
|
|
427
489
|
|
|
428
490
|
const {utxos} = await getUtxos({lnd});
|
|
429
491
|
|
|
430
|
-
const utxo = utxos.find(n => n.transaction_id ===
|
|
492
|
+
const utxo = utxos.find(n => n.transaction_id === idForTx(transaction));
|
|
431
493
|
|
|
432
494
|
if (!utxo || !utxo.confirmation_count) {
|
|
433
495
|
throw new Error('ExpectedReceivedTaprootSpend');
|