ln-service 59.3.1 → 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.
@@ -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 {address} = require('bitcoinjs-lib');
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 {leafHash} = require('p2tr');
10
- const {networks} = require('bitcoinjs-lib');
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 {Transaction} = require('bitcoinjs-lib');
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 {from} = Buffer;
30
- const {fromHex} = Transaction;
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 = Buffer.concat([
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: script.toString('hex')}],
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
- // Make a new tx that will spend the output back into the wallet
115
- const tx = new Transaction();
120
+ const spends = componentsOfTx(signed.transaction).outputs;
116
121
 
117
122
  // The new tx spends the Taproot output
118
- tx.addInput(
119
- fromHex(signed.transaction).getHash(),
120
- fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
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 chainOutput = toOutputScript(
125
- (await createChainAddress({lnd})).address,
126
- networks.regtest
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
- tx.addOutput(chainOutput, smallTokens);
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] = tx.ins.map((input, i) => {
133
- return tx.hashForWitnessV1(
134
- i,
135
- [script],
136
- [tokens],
137
- Transaction.SIGHASH_DEFAULT,
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.toString('hex'),
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.toString('hex'),
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
- tx.ins.forEach((input, i) => tx.setWitness(i, [hexAsBuffer(signature)]));
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: tx.toHex()});
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 === tx.getId());
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 = Buffer.concat([
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: script.toString('hex')}],
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
- // Make a new tx that will spend the output back into the wallet
242
- const tx = new Transaction();
265
+ const spends = componentsOfTx(signed.transaction).outputs;
243
266
 
244
267
  // The new tx spends the Taproot output
245
- tx.addInput(
246
- fromHex(signed.transaction).getHash(),
247
- fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
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 chainOutput = toOutputScript(
252
- (await createChainAddress({lnd})).address,
253
- networks.regtest
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
- tx.addOutput(chainOutput, smallTokens);
281
+ const outputs = [{
282
+ script: bufferAsHex(p2wpkh(program)),
283
+ tokens: smallTokens,
284
+ }];
258
285
 
259
- const [hashToSign] = tx.ins.map((input, i) => {
260
- return tx.hashForWitnessV1(
261
- i,
262
- [script],
263
- [tokens],
264
- Transaction.SIGHASH_DEFAULT,
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.toString('hex'),
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.toString('hex'),
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
- tx.ins.forEach((input, i) => tx.setWitness(i, [hexAsBuffer(signature)]));
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: tx.toHex()});
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 === tx.getId());
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
- // Make a new tx that will spend the output back into the wallet
359
- const tx = new Transaction();
404
+ const spends = componentsOfTx(signed.transaction).outputs;
360
405
 
361
406
  // The new tx spends the Taproot output
362
- tx.addInput(
363
- fromHex(signed.transaction).getHash(),
364
- fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
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 chainOutput = toOutputScript(
369
- (await createChainAddress({lnd})).address,
370
- networks.regtest
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
- tx.addOutput(chainOutput, smallTokens);
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] = tx.ins.map((input, i) => {
377
- return tx.hashForWitnessV1(
378
- i,
379
- [hexAsBuffer(output.script)],
380
- [tokens],
381
- Transaction.SIGHASH_DEFAULT,
382
- hexAsBuffer(leafHash({script: witnessScript}).hash),
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.toString('hex'),
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.toString('hex'),
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
- tx.ins.forEach((input, i) => {
416
- return tx.setWitness(i, [
417
- hexAsBuffer(signature),
418
- hexAsBuffer(witnessScript),
419
- hexAsBuffer(block),
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: tx.toHex()});
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 === tx.getId());
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');