ln-service 59.3.2 → 59.3.4

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,16 +2,17 @@ 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 {networks} = require('bitcoinjs-lib');
10
- const {script} = require('bitcoinjs-lib');
10
+ const {idForTransaction} = require('@alexbosworth/blockchain');
11
+ const {p2wpkhOutputScript} = require('@alexbosworth/blockchain');
11
12
  const {scriptElementsAsScript} = require('@alexbosworth/blockchain');
12
13
  const {spawnLightningCluster} = require('ln-docker-daemons');
13
14
  const tinysecp = require('tiny-secp256k1');
14
- const {Transaction} = require('bitcoinjs-lib');
15
+ const {transactionFromComponents} = require('@alexbosworth/blockchain');
15
16
  const {v1OutputScript} = require('p2tr');
16
17
 
17
18
  const {beginGroupSigningSession} = require('./../../');
@@ -23,17 +24,24 @@ const {getUtxos} = require('./../../');
23
24
  const {signPsbt} = require('./../../');
24
25
  const {signTransaction} = require('./../../');
25
26
 
27
+ const bufferAsHex = buffer => buffer.toString('hex');
26
28
  const compile = elements => scriptElementsAsScript({elements}).script;
29
+ const componentsOfTx = tx => componentsOfTransaction({transaction: tx});
27
30
  const count = 100;
28
31
  const defaultInternalKey = '0350929b74c1a04954b78b4b6035e97a5e078a5a0f28ec96d547bfee9ace803ac0';
29
- const {fromHex} = Transaction;
32
+ const defaultLocktime = 0;
33
+ const defaultSequence = 0xffffffff;
34
+ const defaultTxVersion = 1;
35
+ const emptyScriptSig = '';
30
36
  const hexAsBuffer = hex => Buffer.from(hex, 'hex');
37
+ const idForTx = transaction => idForTransaction({transaction}).id;
31
38
  const interval = retryCount => 10 * Math.pow(2, retryCount);
32
39
  const OP_CHECKSIG = 172;
40
+ const p2wpkh = hash => p2wpkhOutputScript({hash}).script;
33
41
  const smallTokens = 2e5;
34
42
  const times = 20;
35
- const {toOutputScript} = address;
36
43
  const tokens = 1e6;
44
+ const transactionSighashDefault = 0;
37
45
 
38
46
  // Signing a taproot transaction should result in a valid signature
39
47
  test(`Sign a taproot transaction`, async () => {
@@ -119,23 +127,34 @@ test(`Sign a taproot transaction`, async () => {
119
127
  // Send the tx to the chain
120
128
  await broadcastChainTransaction({lnd, transaction: signed.transaction});
121
129
 
122
- // Make a new tx that will spend the output back into the wallet
123
- const tx = new Transaction();
130
+ const spends = componentsOfTx(signed.transaction).outputs;
124
131
 
125
132
  // The new tx spends the Taproot output
126
- tx.addInput(
127
- fromHex(signed.transaction).getHash(),
128
- fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
129
- );
133
+ const inputs = [{
134
+ id: idForTx(signed.transaction),
135
+ script: emptyScriptSig,
136
+ sequence: defaultSequence,
137
+ vout: spends.findIndex(n => n.tokens === tokens),
138
+ }];
130
139
 
131
140
  // Make an output to pay back into the wallet
132
- const chainOutput = toOutputScript(
133
- (await createChainAddress({lnd})).address,
134
- networks.regtest
135
- );
141
+ const chainAddress = await createChainAddress({lnd});
142
+
143
+ const {program} = decodeBech32Address({address: chainAddress.address});
136
144
 
137
145
  // Add output to the pay back transaction
138
- tx.addOutput(chainOutput, smallTokens);
146
+ const outputs = [{
147
+ script: bufferAsHex(p2wpkh(program)),
148
+ tokens: smallTokens,
149
+ }];
150
+
151
+ // Make a new tx that will spend the output back into the wallet
152
+ const unsigned = transactionFromComponents({
153
+ inputs,
154
+ outputs,
155
+ locktime: defaultLocktime,
156
+ version: defaultTxVersion,
157
+ });
139
158
 
140
159
  const {signatures} = await signTransaction({
141
160
  lnd,
@@ -145,14 +164,14 @@ test(`Sign a taproot transaction`, async () => {
145
164
  output_script: output.script,
146
165
  output_tokens: tokens,
147
166
  root_hash: hash,
148
- sighash: Transaction.SIGHASH_DEFAULT,
167
+ sighash: transactionSighashDefault,
149
168
  vin: 0,
150
169
  witness_script: witnessScript,
151
170
  }],
152
- transaction: tx.toHex(),
171
+ transaction: unsigned.transaction,
153
172
  });
154
173
 
155
- const [signature] = signatures.map(hexAsBuffer);
174
+ const [signature] = signatures;
156
175
 
157
176
  const {block} = controlBlock({
158
177
  external_key: output.external_key,
@@ -160,23 +179,28 @@ test(`Sign a taproot transaction`, async () => {
160
179
  script_branches: branches,
161
180
  });
162
181
 
163
- // Add the signature to the input
164
- tx.ins.forEach((input, i) => {
165
- return tx.setWitness(i, [
166
- signature,
167
- hexAsBuffer(witnessScript),
168
- hexAsBuffer(block),
169
- ]);
182
+ // Add the signature to the input and serialize the signed transaction
183
+ const {transaction} = transactionFromComponents({
184
+ outputs,
185
+ inputs: inputs.map(input => ({
186
+ id: input.id,
187
+ script: input.script,
188
+ sequence: input.sequence,
189
+ vout: input.vout,
190
+ witness: [signature, witnessScript, block],
191
+ })),
192
+ locktime: defaultLocktime,
193
+ version: defaultTxVersion,
170
194
  });
171
195
 
172
- await broadcastChainTransaction({lnd, transaction: tx.toHex()});
196
+ await broadcastChainTransaction({lnd, transaction});
173
197
 
174
198
  await asyncRetry({interval, times}, async () => {
175
199
  await generate({});
176
200
 
177
201
  const {utxos} = await getUtxos({lnd});
178
202
 
179
- const utxo = utxos.find(n => n.transaction_id === tx.getId());
203
+ const utxo = utxos.find(n => n.transaction_id === idForTx(transaction));
180
204
 
181
205
  if (!utxo || !utxo.confirmation_count) {
182
206
  throw new Error('ExpectedReceivedTaprootSpend');
@@ -192,7 +216,7 @@ test(`Sign a taproot transaction`, async () => {
192
216
 
193
217
  const topLevelKey = await getPublicKey({lnd, family: 805});
194
218
 
195
- const unusedKey = ecp.makeRandom({network: networks.regtest});
219
+ const unusedKey = ecp.makeRandom({});
196
220
 
197
221
  const witnessScript = compile([
198
222
  Buffer.from(unusedKey.publicKey).slice(1),
@@ -225,23 +249,34 @@ test(`Sign a taproot transaction`, async () => {
225
249
  // Send the tx to the chain
226
250
  await broadcastChainTransaction({lnd, transaction: signed.transaction});
227
251
 
228
- // Make a new tx that will spend the output back into the wallet
229
- const tx = new Transaction();
252
+ const spends = componentsOfTx(signed.transaction).outputs;
230
253
 
231
254
  // The new tx spends the Taproot output
232
- tx.addInput(
233
- fromHex(signed.transaction).getHash(),
234
- fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
235
- );
255
+ const inputs = [{
256
+ id: idForTx(signed.transaction),
257
+ script: emptyScriptSig,
258
+ sequence: defaultSequence,
259
+ vout: spends.findIndex(n => n.tokens === tokens),
260
+ }];
236
261
 
237
262
  // Make an output to pay back into the wallet
238
- const chainOutput = toOutputScript(
239
- (await createChainAddress({lnd})).address,
240
- networks.regtest
241
- );
263
+ const chainAddress = await createChainAddress({lnd});
264
+
265
+ const {program} = decodeBech32Address({address: chainAddress.address});
242
266
 
243
267
  // Add output to the pay back transaction
244
- tx.addOutput(chainOutput, smallTokens);
268
+ const outputs = [{
269
+ script: bufferAsHex(p2wpkh(program)),
270
+ tokens: smallTokens,
271
+ }];
272
+
273
+ // Make a new tx that will spend the output back into the wallet
274
+ const unsigned = transactionFromComponents({
275
+ inputs,
276
+ outputs,
277
+ locktime: defaultLocktime,
278
+ version: defaultTxVersion,
279
+ });
245
280
 
246
281
  const {signatures} = await signTransaction({
247
282
  lnd,
@@ -251,25 +286,36 @@ test(`Sign a taproot transaction`, async () => {
251
286
  output_script: output.script,
252
287
  output_tokens: tokens,
253
288
  root_hash: hash,
254
- sighash: Transaction.SIGHASH_DEFAULT,
289
+ sighash: transactionSighashDefault,
255
290
  vin: 0,
256
291
  }],
257
- transaction: tx.toHex(),
292
+ transaction: unsigned.transaction,
258
293
  });
259
294
 
260
- const [signature] = signatures.map(hexAsBuffer);
261
-
262
- // Add the signature to the input
263
- tx.ins.forEach((input, i) => tx.setWitness(i, [signature]));
295
+ const [signature] = signatures;
296
+
297
+ // Add the signature to the input and serialize the signed transaction
298
+ const {transaction} = transactionFromComponents({
299
+ outputs,
300
+ inputs: inputs.map(input => ({
301
+ id: input.id,
302
+ script: input.script,
303
+ sequence: input.sequence,
304
+ vout: input.vout,
305
+ witness: [signature],
306
+ })),
307
+ locktime: defaultLocktime,
308
+ version: defaultTxVersion,
309
+ });
264
310
 
265
- await broadcastChainTransaction({lnd, transaction: tx.toHex()});
311
+ await broadcastChainTransaction({lnd, transaction});
266
312
 
267
313
  await asyncRetry({interval, times}, async () => {
268
314
  await generate({});
269
315
 
270
316
  const {utxos} = await getUtxos({lnd});
271
317
 
272
- const utxo = utxos.find(n => n.transaction_id === tx.getId());
318
+ const utxo = utxos.find(n => n.transaction_id === idForTx(transaction));
273
319
 
274
320
  if (!utxo || !utxo.confirmation_count) {
275
321
  throw new Error('ExpectedReceivedTaprootSpend');
@@ -309,23 +355,34 @@ test(`Sign a taproot transaction`, async () => {
309
355
  // Send the tx to the chain
310
356
  await broadcastChainTransaction({lnd, transaction: signed.transaction});
311
357
 
312
- // Make a new tx that will spend the output back into the wallet
313
- const tx = new Transaction();
358
+ const spends = componentsOfTx(signed.transaction).outputs;
314
359
 
315
360
  // The new tx spends the Taproot output
316
- tx.addInput(
317
- fromHex(signed.transaction).getHash(),
318
- fromHex(signed.transaction).outs.findIndex(n => n.value === tokens)
319
- );
361
+ const inputs = [{
362
+ id: idForTx(signed.transaction),
363
+ script: emptyScriptSig,
364
+ sequence: defaultSequence,
365
+ vout: spends.findIndex(n => n.tokens === tokens),
366
+ }];
320
367
 
321
368
  // Make an output to pay back into the wallet
322
- const chainOutput = toOutputScript(
323
- (await createChainAddress({lnd})).address,
324
- networks.regtest
325
- );
369
+ const chainAddress = await createChainAddress({lnd});
370
+
371
+ const {program} = decodeBech32Address({address: chainAddress.address});
326
372
 
327
373
  // Add output to the pay back transaction
328
- tx.addOutput(chainOutput, smallTokens);
374
+ const outputs = [{
375
+ script: bufferAsHex(p2wpkh(program)),
376
+ tokens: smallTokens,
377
+ }];
378
+
379
+ // Make a new tx that will spend the output back into the wallet
380
+ const unsigned = transactionFromComponents({
381
+ inputs,
382
+ outputs,
383
+ locktime: defaultLocktime,
384
+ version: defaultTxVersion,
385
+ });
329
386
 
330
387
  const {signatures} = await signTransaction({
331
388
  lnd,
@@ -334,25 +391,36 @@ test(`Sign a taproot transaction`, async () => {
334
391
  key_index: topLevelKey.index,
335
392
  output_script: output.script,
336
393
  output_tokens: tokens,
337
- sighash: Transaction.SIGHASH_DEFAULT,
394
+ sighash: transactionSighashDefault,
338
395
  vin: 0,
339
396
  }],
340
- transaction: tx.toHex(),
397
+ transaction: unsigned.transaction,
341
398
  });
342
399
 
343
- const [signature] = signatures.map(hexAsBuffer);
344
-
345
- // Add the signature to the input
346
- tx.ins.forEach((input, i) => tx.setWitness(i, [signature]));
400
+ const [signature] = signatures;
401
+
402
+ // Add the signature to the input and serialize the signed transaction
403
+ const {transaction} = transactionFromComponents({
404
+ outputs,
405
+ inputs: inputs.map(input => ({
406
+ id: input.id,
407
+ script: input.script,
408
+ sequence: input.sequence,
409
+ vout: input.vout,
410
+ witness: [signature],
411
+ })),
412
+ locktime: defaultLocktime,
413
+ version: defaultTxVersion,
414
+ });
347
415
 
348
- await broadcastChainTransaction({lnd, transaction: tx.toHex()});
416
+ await broadcastChainTransaction({lnd, transaction});
349
417
 
350
418
  await asyncRetry({interval, times}, async () => {
351
419
  await generate({});
352
420
 
353
421
  const {utxos} = await getUtxos({lnd});
354
422
 
355
- const utxo = utxos.find(n => n.transaction_id === tx.getId());
423
+ const utxo = utxos.find(n => n.transaction_id === idForTx(transaction));
356
424
 
357
425
  if (!utxo || !utxo.confirmation_count) {
358
426
  throw new Error('ExpectedReceivedTaprootSpend');