@btc-vision/bitcoin 7.0.0-beta.0 → 7.0.0-beta.1
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/README.md +112 -13
- package/benchmark-compare/BENCHMARK.md +74 -59
- package/benchmark-compare/compare.bench.ts +249 -96
- package/benchmark-compare/harness.ts +23 -25
- package/benchmark-compare/package.json +1 -0
- package/browser/address.d.ts +4 -4
- package/browser/address.d.ts.map +1 -1
- package/browser/chunks/{psbt-parallel-B-dfm5GZ.js → psbt-parallel-jZ6QcCnM.js} +3128 -2731
- package/browser/index.d.ts +1 -1
- package/browser/index.d.ts.map +1 -1
- package/browser/index.js +603 -585
- package/browser/io/base58check.d.ts +1 -25
- package/browser/io/base58check.d.ts.map +1 -1
- package/browser/io/base64.d.ts.map +1 -1
- package/browser/networks.d.ts +1 -0
- package/browser/networks.d.ts.map +1 -1
- package/browser/payments/bip341.d.ts +17 -0
- package/browser/payments/bip341.d.ts.map +1 -1
- package/browser/payments/index.d.ts +3 -2
- package/browser/payments/index.d.ts.map +1 -1
- package/browser/payments/p2mr.d.ts +169 -0
- package/browser/payments/p2mr.d.ts.map +1 -0
- package/browser/payments/types.d.ts +11 -1
- package/browser/payments/types.d.ts.map +1 -1
- package/browser/psbt/bip371.d.ts +30 -0
- package/browser/psbt/bip371.d.ts.map +1 -1
- package/browser/psbt/psbtutils.d.ts +1 -0
- package/browser/psbt/psbtutils.d.ts.map +1 -1
- package/browser/psbt.d.ts.map +1 -1
- package/browser/workers/index.js +9 -9
- package/build/address.d.ts +4 -4
- package/build/address.d.ts.map +1 -1
- package/build/address.js +11 -1
- package/build/address.js.map +1 -1
- package/build/index.d.ts +1 -1
- package/build/index.d.ts.map +1 -1
- package/build/index.js.map +1 -1
- package/build/io/base58check.d.ts +1 -25
- package/build/io/base58check.d.ts.map +1 -1
- package/build/io/base58check.js +1 -31
- package/build/io/base58check.js.map +1 -1
- package/build/io/base64.d.ts.map +1 -1
- package/build/io/base64.js +3 -0
- package/build/io/base64.js.map +1 -1
- package/build/networks.d.ts +1 -0
- package/build/networks.d.ts.map +1 -1
- package/build/networks.js +12 -0
- package/build/networks.js.map +1 -1
- package/build/payments/bip341.d.ts +17 -0
- package/build/payments/bip341.d.ts.map +1 -1
- package/build/payments/bip341.js +32 -1
- package/build/payments/bip341.js.map +1 -1
- package/build/payments/index.d.ts +3 -2
- package/build/payments/index.d.ts.map +1 -1
- package/build/payments/index.js +2 -1
- package/build/payments/index.js.map +1 -1
- package/build/payments/p2mr.d.ts +178 -0
- package/build/payments/p2mr.d.ts.map +1 -0
- package/build/payments/p2mr.js +555 -0
- package/build/payments/p2mr.js.map +1 -0
- package/build/payments/types.d.ts +11 -1
- package/build/payments/types.d.ts.map +1 -1
- package/build/payments/types.js +1 -0
- package/build/payments/types.js.map +1 -1
- package/build/psbt/bip371.d.ts +30 -0
- package/build/psbt/bip371.d.ts.map +1 -1
- package/build/psbt/bip371.js +80 -15
- package/build/psbt/bip371.js.map +1 -1
- package/build/psbt/psbtutils.d.ts +1 -0
- package/build/psbt/psbtutils.d.ts.map +1 -1
- package/build/psbt/psbtutils.js +2 -0
- package/build/psbt/psbtutils.js.map +1 -1
- package/build/psbt.d.ts.map +1 -1
- package/build/psbt.js +3 -2
- package/build/psbt.js.map +1 -1
- package/build/pubkey.js +1 -1
- package/build/pubkey.js.map +1 -1
- package/build/tsconfig.build.tsbuildinfo +1 -1
- package/documentation/README.md +122 -0
- package/documentation/address.md +820 -0
- package/documentation/block.md +679 -0
- package/documentation/crypto.md +461 -0
- package/documentation/ecc.md +584 -0
- package/documentation/errors.md +656 -0
- package/documentation/io.md +942 -0
- package/documentation/networks.md +625 -0
- package/documentation/p2mr.md +380 -0
- package/documentation/payments.md +1485 -0
- package/documentation/psbt.md +1400 -0
- package/documentation/script.md +730 -0
- package/documentation/taproot.md +670 -0
- package/documentation/transaction.md +943 -0
- package/documentation/types.md +587 -0
- package/documentation/workers.md +1007 -0
- package/eslint.config.js +3 -0
- package/package.json +17 -14
- package/src/address.ts +22 -10
- package/src/index.ts +1 -0
- package/src/io/base58check.ts +1 -35
- package/src/io/base64.ts +5 -0
- package/src/networks.ts +13 -0
- package/src/payments/bip341.ts +36 -1
- package/src/payments/index.ts +4 -0
- package/src/payments/p2mr.ts +660 -0
- package/src/payments/types.ts +12 -0
- package/src/psbt/bip371.ts +84 -13
- package/src/psbt/psbtutils.ts +2 -0
- package/src/psbt.ts +4 -2
- package/src/pubkey.ts +1 -1
- package/test/bitcoin.core.spec.ts +1 -1
- package/test/fixtures/p2mr.json +270 -0
- package/test/integration/taproot.spec.ts +7 -3
- package/test/opnetTestnet.spec.ts +302 -0
- package/test/payments.spec.ts +3 -1
- package/test/psbt.spec.ts +297 -2
- package/test/tsconfig.json +2 -2
package/src/psbt/bip371.ts
CHANGED
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
LEAF_VERSION_TAPSCRIPT,
|
|
12
12
|
MAX_TAPTREE_DEPTH,
|
|
13
13
|
rootHashFromPath,
|
|
14
|
+
rootHashFromPathP2MR,
|
|
14
15
|
tapleafHash,
|
|
15
16
|
tweakKey,
|
|
16
17
|
} from '../payments/bip341.js';
|
|
@@ -20,6 +21,7 @@ import type { Bytes32, Tapleaf, Taptree, XOnlyPublicKey } from '../types.js';
|
|
|
20
21
|
import { isTapleaf, isTaptree } from '../types.js';
|
|
21
22
|
import { concat, equals } from '../io/index.js';
|
|
22
23
|
import {
|
|
24
|
+
isP2MR,
|
|
23
25
|
isP2TR,
|
|
24
26
|
pubkeyPositionInScript,
|
|
25
27
|
signatureBlocksAction,
|
|
@@ -55,16 +57,31 @@ export function tapScriptFinalizer(
|
|
|
55
57
|
.concat(new Uint8Array(tapLeaf.controlBlock));
|
|
56
58
|
return { finalScriptWitness: witnessStackToScriptWitness(witness) };
|
|
57
59
|
} catch (err) {
|
|
58
|
-
throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}
|
|
60
|
+
throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`, { cause: err });
|
|
59
61
|
}
|
|
60
62
|
}
|
|
61
63
|
|
|
64
|
+
/**
|
|
65
|
+
* Serializes a taproot (Schnorr) signature, optionally appending the sighash type byte.
|
|
66
|
+
* If sighashType is SIGHASH_DEFAULT (0x00) or not provided, no byte is appended (per BIP 341).
|
|
67
|
+
* Used for both P2TR key-path/script-path and P2MR script-path signatures.
|
|
68
|
+
* @param sig - The 64-byte Schnorr signature.
|
|
69
|
+
* @param sighashType - Optional sighash type. Omit or pass 0 for SIGHASH_DEFAULT.
|
|
70
|
+
* @returns The serialized signature (64 or 65 bytes).
|
|
71
|
+
*/
|
|
62
72
|
export function serializeTaprootSignature(sig: Uint8Array, sighashType?: number): Uint8Array {
|
|
63
73
|
const sighashTypeByte = sighashType ? new Uint8Array([sighashType]) : new Uint8Array(0);
|
|
64
74
|
|
|
65
75
|
return concat([sig, sighashTypeByte]);
|
|
66
76
|
}
|
|
67
77
|
|
|
78
|
+
/**
|
|
79
|
+
* Determines whether a PSBT input should be handled as a taproot-style input.
|
|
80
|
+
* Returns true for both P2TR (SegWit v1, BIP 341) and P2MR (SegWit v2, BIP 360) inputs.
|
|
81
|
+
* This is the gateway check that routes inputs to taproot signing and finalization logic.
|
|
82
|
+
* @param input - The PSBT input to check.
|
|
83
|
+
* @returns True if the input has taproot/P2MR fields or a P2TR/P2MR witnessUtxo script.
|
|
84
|
+
*/
|
|
68
85
|
export function isTaprootInput(input: PsbtInput): boolean {
|
|
69
86
|
return (
|
|
70
87
|
input &&
|
|
@@ -73,11 +90,31 @@ export function isTaprootInput(input: PsbtInput): boolean {
|
|
|
73
90
|
input.tapMerkleRoot ||
|
|
74
91
|
(input.tapLeafScript && input.tapLeafScript.length) ||
|
|
75
92
|
(input.tapBip32Derivation && input.tapBip32Derivation.length) ||
|
|
76
|
-
(input.witnessUtxo &&
|
|
93
|
+
(input.witnessUtxo &&
|
|
94
|
+
(isP2TR(new Uint8Array(input.witnessUtxo.script)) ||
|
|
95
|
+
isP2MR(new Uint8Array(input.witnessUtxo.script))))
|
|
77
96
|
)
|
|
78
97
|
);
|
|
79
98
|
}
|
|
80
99
|
|
|
100
|
+
/**
|
|
101
|
+
* Checks if the input is spending a P2MR (Pay-to-Merkle-Root, BIP 360) output.
|
|
102
|
+
* Requires `witnessUtxo` to be set on the input; returns false otherwise.
|
|
103
|
+
* P2MR uses SegWit version 2 with scriptPubKey: `OP_2 <32-byte merkle_root>`.
|
|
104
|
+
* @param input - The PSBT input to check.
|
|
105
|
+
* @returns True if the witnessUtxo script is a valid P2MR output.
|
|
106
|
+
*/
|
|
107
|
+
export function isP2MRInput(input: PsbtInput): boolean {
|
|
108
|
+
return !!(input.witnessUtxo && isP2MR(new Uint8Array(input.witnessUtxo.script)));
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/**
|
|
112
|
+
* Determines whether a PSBT output should be handled as a taproot-style output.
|
|
113
|
+
* Returns true for both P2TR (BIP 341) and P2MR (BIP 360) outputs.
|
|
114
|
+
* @param output - The PSBT output to check.
|
|
115
|
+
* @param script - Optional output script to test against P2TR/P2MR patterns.
|
|
116
|
+
* @returns True if the output has taproot fields or a P2TR/P2MR script.
|
|
117
|
+
*/
|
|
81
118
|
export function isTaprootOutput(output: PsbtOutput, script?: Uint8Array): boolean {
|
|
82
119
|
return (
|
|
83
120
|
output &&
|
|
@@ -85,7 +122,7 @@ export function isTaprootOutput(output: PsbtOutput, script?: Uint8Array): boolea
|
|
|
85
122
|
output.tapInternalKey ||
|
|
86
123
|
output.tapTree ||
|
|
87
124
|
(output.tapBip32Derivation && output.tapBip32Derivation.length) ||
|
|
88
|
-
(script && isP2TR(script))
|
|
125
|
+
(script && (isP2TR(script) || isP2MR(script)))
|
|
89
126
|
)
|
|
90
127
|
);
|
|
91
128
|
}
|
|
@@ -324,20 +361,21 @@ function checkMixedTaprootAndNonTaprootOutputFields(
|
|
|
324
361
|
* @throws {Error} - If the tap leaf is not part of the tap tree.
|
|
325
362
|
*/
|
|
326
363
|
function checkIfTapLeafInTree(inputData: PsbtInput, newInputData: PsbtInput, action: string): void {
|
|
364
|
+
const p2mrInput = isP2MRInput(inputData) || isP2MRInput(newInputData);
|
|
327
365
|
if (newInputData.tapMerkleRoot) {
|
|
328
366
|
const merkleRoot = new Uint8Array(newInputData.tapMerkleRoot);
|
|
329
367
|
const newLeafsInTree = (newInputData.tapLeafScript || []).every((l) =>
|
|
330
|
-
isTapLeafInTree(l, merkleRoot),
|
|
368
|
+
isTapLeafInTree(l, merkleRoot, p2mrInput),
|
|
331
369
|
);
|
|
332
370
|
const oldLeafsInTree = (inputData.tapLeafScript || []).every((l) =>
|
|
333
|
-
isTapLeafInTree(l, merkleRoot),
|
|
371
|
+
isTapLeafInTree(l, merkleRoot, p2mrInput),
|
|
334
372
|
);
|
|
335
373
|
if (!newLeafsInTree || !oldLeafsInTree)
|
|
336
374
|
throw new Error(`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`);
|
|
337
375
|
} else if (inputData.tapMerkleRoot) {
|
|
338
376
|
const merkleRoot = new Uint8Array(inputData.tapMerkleRoot);
|
|
339
377
|
const newLeafsInTree = (newInputData.tapLeafScript || []).every((l) =>
|
|
340
|
-
isTapLeafInTree(l, merkleRoot),
|
|
378
|
+
isTapLeafInTree(l, merkleRoot, p2mrInput),
|
|
341
379
|
);
|
|
342
380
|
if (!newLeafsInTree)
|
|
343
381
|
throw new Error(`Invalid arguments for Psbt.${action}. Tapleaf not part of taptree.`);
|
|
@@ -345,12 +383,24 @@ function checkIfTapLeafInTree(inputData: PsbtInput, newInputData: PsbtInput, act
|
|
|
345
383
|
}
|
|
346
384
|
|
|
347
385
|
/**
|
|
348
|
-
* Checks if a TapLeafScript is present in a Merkle tree
|
|
349
|
-
*
|
|
350
|
-
*
|
|
351
|
-
*
|
|
386
|
+
* Checks if a TapLeafScript is present in a Merkle tree by recomputing the root
|
|
387
|
+
* from the control block's merkle path.
|
|
388
|
+
*
|
|
389
|
+
* Handles both P2TR and P2MR control block formats:
|
|
390
|
+
* - P2TR: 33 + 32*m bytes (1 control byte + 32-byte internal pubkey + merkle path)
|
|
391
|
+
* - P2MR: 1 + 32*m bytes (1 control byte + merkle path, no internal pubkey)
|
|
392
|
+
*
|
|
393
|
+
* When `p2mr` is explicitly true, only the P2MR format is tried. When false and
|
|
394
|
+
* the input type is unknown (witnessUtxo not yet set), both formats are tried as
|
|
395
|
+
* their lengths overlap at 33, 65, 97... bytes. The merkle root is used to
|
|
396
|
+
* disambiguate which interpretation is correct.
|
|
397
|
+
*
|
|
398
|
+
* @param tapLeaf - The TapLeafScript to check (includes script, leafVersion, controlBlock).
|
|
399
|
+
* @param merkleRoot - The expected Merkle root. If not provided, returns true (no validation).
|
|
400
|
+
* @param p2mr - If true, use P2MR control block format exclusively.
|
|
401
|
+
* @returns True if the leaf's control block produces the expected merkle root.
|
|
352
402
|
*/
|
|
353
|
-
function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Uint8Array): boolean {
|
|
403
|
+
function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Uint8Array, p2mr = false): boolean {
|
|
354
404
|
if (!merkleRoot) return true;
|
|
355
405
|
|
|
356
406
|
const leafHash = tapleafHash({
|
|
@@ -358,8 +408,29 @@ function isTapLeafInTree(tapLeaf: TapLeafScript, merkleRoot?: Uint8Array): boole
|
|
|
358
408
|
version: tapLeaf.leafVersion,
|
|
359
409
|
});
|
|
360
410
|
|
|
361
|
-
const
|
|
362
|
-
|
|
411
|
+
const controlBlock = new Uint8Array(tapLeaf.controlBlock);
|
|
412
|
+
|
|
413
|
+
if (p2mr) {
|
|
414
|
+
return equals(rootHashFromPathP2MR(controlBlock, leafHash), merkleRoot);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
// When the input type isn't known yet (witnessUtxo not set), try P2TR first,
|
|
418
|
+
// then fall back to P2MR. Control block lengths overlap (33, 65, ...) between
|
|
419
|
+
// P2TR (33 + 32*m) and P2MR (1 + 32*m), so we verify against the merkle root.
|
|
420
|
+
const isValidP2TRLength = controlBlock.length >= 33 && (controlBlock.length - 33) % 32 === 0;
|
|
421
|
+
const isValidP2MRLength = controlBlock.length >= 1 && (controlBlock.length - 1) % 32 === 0;
|
|
422
|
+
|
|
423
|
+
if (isValidP2TRLength) {
|
|
424
|
+
const rootHash = rootHashFromPath(controlBlock, leafHash);
|
|
425
|
+
if (equals(rootHash, merkleRoot)) return true;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (isValidP2MRLength) {
|
|
429
|
+
const rootHash = rootHashFromPathP2MR(controlBlock, leafHash);
|
|
430
|
+
if (equals(rootHash, merkleRoot)) return true;
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
return false;
|
|
363
434
|
}
|
|
364
435
|
|
|
365
436
|
/**
|
package/src/psbt/psbtutils.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { p2ms } from '../payments/p2ms.js';
|
|
|
5
5
|
import { p2pk } from '../payments/p2pk.js';
|
|
6
6
|
import { p2pkh } from '../payments/p2pkh.js';
|
|
7
7
|
import { p2sh } from '../payments/p2sh.js';
|
|
8
|
+
import { p2mr } from '../payments/p2mr.js';
|
|
8
9
|
import { p2tr } from '../payments/p2tr.js';
|
|
9
10
|
import { p2wpkh } from '../payments/p2wpkh.js';
|
|
10
11
|
import { p2wsh } from '../payments/p2wsh.js';
|
|
@@ -34,6 +35,7 @@ export const isP2WPKH = isPaymentFactory(p2wpkh);
|
|
|
34
35
|
export const isP2WSHScript = isPaymentFactory(p2wsh);
|
|
35
36
|
export const isP2SHScript = isPaymentFactory(p2sh);
|
|
36
37
|
export const isP2TR = isPaymentFactory(p2tr);
|
|
38
|
+
export const isP2MR = isPaymentFactory(p2mr);
|
|
37
39
|
export const isP2OP = isPaymentFactory(p2op);
|
|
38
40
|
export const isP2A = (script: Uint8Array): boolean => {
|
|
39
41
|
return (
|
package/src/psbt.ts
CHANGED
|
@@ -17,6 +17,7 @@ import * as payments from './payments/index.js';
|
|
|
17
17
|
import {
|
|
18
18
|
checkTaprootInputFields,
|
|
19
19
|
checkTaprootOutputFields,
|
|
20
|
+
isP2MRInput,
|
|
20
21
|
isTaprootInput,
|
|
21
22
|
serializeTaprootSignature,
|
|
22
23
|
tapScriptFinalizer,
|
|
@@ -420,7 +421,7 @@ export class Psbt {
|
|
|
420
421
|
if (hasAddress) {
|
|
421
422
|
const { address } = outputData as PsbtOutputExtendedAddress;
|
|
422
423
|
const { network } = this.#opts;
|
|
423
|
-
const script = toOutputScript(address, network)
|
|
424
|
+
const script = toOutputScript(address, network);
|
|
424
425
|
outputData = Object.assign({}, outputData, { script });
|
|
425
426
|
}
|
|
426
427
|
checkTaprootOutputFields(outputData, outputData, 'addOutput');
|
|
@@ -921,7 +922,8 @@ export class Psbt {
|
|
|
921
922
|
if (!input.witnessUtxo)
|
|
922
923
|
throw new Error(`Cannot finalize input #${inputIndex}. Missing witness utxo.`);
|
|
923
924
|
|
|
924
|
-
|
|
925
|
+
// P2MR has no key-path spend — always use script-path finalization
|
|
926
|
+
if (input.tapKeySig && !isP2MRInput(input)) {
|
|
925
927
|
const payment = payments.p2tr({
|
|
926
928
|
output: input.witnessUtxo.script as Script,
|
|
927
929
|
signature: input.tapKeySig as SchnorrSignature,
|
package/src/pubkey.ts
CHANGED
|
@@ -55,7 +55,7 @@ export function decompressPublicKey(realPubKey: PublicKey): UncompressedPublicKe
|
|
|
55
55
|
try {
|
|
56
56
|
point = Point.fromHex(toHex(realPubKey));
|
|
57
57
|
} catch (err) {
|
|
58
|
-
throw new Error('Invalid secp256k1 public key bytes. Cannot parse.');
|
|
58
|
+
throw new Error('Invalid secp256k1 public key bytes. Cannot parse.', { cause: err });
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
const xBuf = bigIntTo32Bytes(point.x);
|
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
{
|
|
2
|
+
"valid": [
|
|
3
|
+
{
|
|
4
|
+
"description": "output and hash from address",
|
|
5
|
+
"arguments": {
|
|
6
|
+
"address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq"
|
|
7
|
+
},
|
|
8
|
+
"options": {},
|
|
9
|
+
"expected": {
|
|
10
|
+
"name": "p2mr",
|
|
11
|
+
"hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
|
|
12
|
+
"output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
|
|
13
|
+
"input": null,
|
|
14
|
+
"witness": null
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
"description": "address and hash from output",
|
|
19
|
+
"arguments": {
|
|
20
|
+
"output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5"
|
|
21
|
+
},
|
|
22
|
+
"options": {},
|
|
23
|
+
"expected": {
|
|
24
|
+
"name": "p2mr",
|
|
25
|
+
"address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq",
|
|
26
|
+
"hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
|
|
27
|
+
"input": null,
|
|
28
|
+
"witness": null
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"description": "address and output from hash",
|
|
33
|
+
"arguments": {
|
|
34
|
+
"hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5"
|
|
35
|
+
},
|
|
36
|
+
"options": {},
|
|
37
|
+
"expected": {
|
|
38
|
+
"name": "p2mr",
|
|
39
|
+
"address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq",
|
|
40
|
+
"output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
|
|
41
|
+
"input": null,
|
|
42
|
+
"witness": null
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
{
|
|
46
|
+
"description": "hash, output and address from single-leaf scriptTree",
|
|
47
|
+
"arguments": {
|
|
48
|
+
"scriptTree": {
|
|
49
|
+
"output": "OP_1"
|
|
50
|
+
}
|
|
51
|
+
},
|
|
52
|
+
"options": {},
|
|
53
|
+
"expected": {
|
|
54
|
+
"name": "p2mr",
|
|
55
|
+
"hash": "a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
|
|
56
|
+
"output": "OP_2 a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
|
|
57
|
+
"address": "bc1z4pdjzplhjxex4p88tpkz3nk8edsjqtkn6qv5fkpj2q8nvduz6e6sy82nl4",
|
|
58
|
+
"input": null,
|
|
59
|
+
"witness": null
|
|
60
|
+
}
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"description": "hash, address, output and witness from single-leaf scriptTree with redeem",
|
|
64
|
+
"arguments": {
|
|
65
|
+
"scriptTree": {
|
|
66
|
+
"output": "OP_1"
|
|
67
|
+
},
|
|
68
|
+
"redeem": {
|
|
69
|
+
"output": "OP_1"
|
|
70
|
+
}
|
|
71
|
+
},
|
|
72
|
+
"options": {},
|
|
73
|
+
"expected": {
|
|
74
|
+
"name": "p2mr",
|
|
75
|
+
"hash": "a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
|
|
76
|
+
"output": "OP_2 a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675",
|
|
77
|
+
"address": "bc1z4pdjzplhjxex4p88tpkz3nk8edsjqtkn6qv5fkpj2q8nvduz6e6sy82nl4",
|
|
78
|
+
"input": null,
|
|
79
|
+
"witness": [
|
|
80
|
+
"51",
|
|
81
|
+
"c1"
|
|
82
|
+
]
|
|
83
|
+
}
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"description": "hash, address, output from two-leaf scriptTree",
|
|
87
|
+
"arguments": {
|
|
88
|
+
"scriptTree": [
|
|
89
|
+
{
|
|
90
|
+
"output": "OP_1"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"output": "OP_0 OP_1"
|
|
94
|
+
}
|
|
95
|
+
]
|
|
96
|
+
},
|
|
97
|
+
"options": {},
|
|
98
|
+
"expected": {
|
|
99
|
+
"name": "p2mr",
|
|
100
|
+
"hash": "9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
|
|
101
|
+
"output": "OP_2 9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
|
|
102
|
+
"address": "bc1zn0yvalynq9793rkxghf9d5slz6yh5vlr6yr5qtwt2zrg6mjhqxnq2qq9vy",
|
|
103
|
+
"input": null,
|
|
104
|
+
"witness": null
|
|
105
|
+
}
|
|
106
|
+
},
|
|
107
|
+
{
|
|
108
|
+
"description": "witness from two-leaf scriptTree spending second leaf",
|
|
109
|
+
"arguments": {
|
|
110
|
+
"scriptTree": [
|
|
111
|
+
{
|
|
112
|
+
"output": "OP_1"
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
"output": "OP_0 OP_1"
|
|
116
|
+
}
|
|
117
|
+
],
|
|
118
|
+
"redeem": {
|
|
119
|
+
"output": "OP_0 OP_1"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"options": {},
|
|
123
|
+
"expected": {
|
|
124
|
+
"name": "p2mr",
|
|
125
|
+
"hash": "9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
|
|
126
|
+
"output": "OP_2 9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
|
|
127
|
+
"address": "bc1zn0yvalynq9793rkxghf9d5slz6yh5vlr6yr5qtwt2zrg6mjhqxnq2qq9vy",
|
|
128
|
+
"input": null,
|
|
129
|
+
"witness": [
|
|
130
|
+
"0051",
|
|
131
|
+
"c1a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675"
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"description": "hash, output and address from witness (script-path spend)",
|
|
137
|
+
"arguments": {
|
|
138
|
+
"witness": [
|
|
139
|
+
"0051",
|
|
140
|
+
"c1a85b2107f791b26a84e7586c28cec7cb61202ed3d01944d832500f363782d675"
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
"options": {},
|
|
144
|
+
"expected": {
|
|
145
|
+
"name": "p2mr",
|
|
146
|
+
"hash": "9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
|
|
147
|
+
"output": "OP_2 9bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6",
|
|
148
|
+
"address": "bc1zn0yvalynq9793rkxghf9d5slz6yh5vlr6yr5qtwt2zrg6mjhqxnq2qq9vy",
|
|
149
|
+
"input": null
|
|
150
|
+
}
|
|
151
|
+
},
|
|
152
|
+
{
|
|
153
|
+
"description": "three-leaf tree spending leaf C",
|
|
154
|
+
"arguments": {
|
|
155
|
+
"scriptTree": [
|
|
156
|
+
[
|
|
157
|
+
{
|
|
158
|
+
"output": "OP_1"
|
|
159
|
+
},
|
|
160
|
+
{
|
|
161
|
+
"output": "OP_0 OP_1"
|
|
162
|
+
}
|
|
163
|
+
],
|
|
164
|
+
{
|
|
165
|
+
"output": "OP_2 OP_ADD"
|
|
166
|
+
}
|
|
167
|
+
],
|
|
168
|
+
"redeem": {
|
|
169
|
+
"output": "OP_2 OP_ADD"
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
"options": {},
|
|
173
|
+
"expected": {
|
|
174
|
+
"name": "p2mr",
|
|
175
|
+
"hash": "51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
|
|
176
|
+
"output": "OP_2 51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
|
|
177
|
+
"address": "bc1z2ycg56tcxacr35ntngj2nlfkmjnkxqrtveah437n8g772yldrxkq3620s4",
|
|
178
|
+
"input": null,
|
|
179
|
+
"witness": [
|
|
180
|
+
"5293",
|
|
181
|
+
"c19bc8cefc93017c588ec645d256d21f16897a33e3d107402dcb50868d6e5701a6"
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
"description": "three-leaf tree spending leaf A (deeper path)",
|
|
187
|
+
"arguments": {
|
|
188
|
+
"scriptTree": [
|
|
189
|
+
[
|
|
190
|
+
{
|
|
191
|
+
"output": "OP_1"
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
"output": "OP_0 OP_1"
|
|
195
|
+
}
|
|
196
|
+
],
|
|
197
|
+
{
|
|
198
|
+
"output": "OP_2 OP_ADD"
|
|
199
|
+
}
|
|
200
|
+
],
|
|
201
|
+
"redeem": {
|
|
202
|
+
"output": "OP_1"
|
|
203
|
+
}
|
|
204
|
+
},
|
|
205
|
+
"options": {},
|
|
206
|
+
"expected": {
|
|
207
|
+
"name": "p2mr",
|
|
208
|
+
"hash": "51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
|
|
209
|
+
"output": "OP_2 51308a6978377038d26b9a24a9fd36dca763006b667b7ac7d33a3de513ed19ac",
|
|
210
|
+
"address": "bc1z2ycg56tcxacr35ntngj2nlfkmjnkxqrtveah437n8g772yldrxkq3620s4",
|
|
211
|
+
"input": null,
|
|
212
|
+
"witness": [
|
|
213
|
+
"51",
|
|
214
|
+
"c16a44dcd1309c36cb52f2cd8797d947b9b06dddf666fb9b8c6e8d8fb0bc41cd1b3173603d1ef3328ba80b0ba7d35aba099b2f96674473d80cab75944befa3daec"
|
|
215
|
+
]
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
"description": "single leaf with non-default version (0xfa)",
|
|
220
|
+
"arguments": {
|
|
221
|
+
"scriptTree": {
|
|
222
|
+
"output": "OP_1",
|
|
223
|
+
"version": 250
|
|
224
|
+
},
|
|
225
|
+
"redeem": {
|
|
226
|
+
"output": "OP_1"
|
|
227
|
+
},
|
|
228
|
+
"redeemVersion": 250
|
|
229
|
+
},
|
|
230
|
+
"options": {},
|
|
231
|
+
"expected": {
|
|
232
|
+
"name": "p2mr",
|
|
233
|
+
"hash": "eb0c727d7160a3e717c3ec0cb3e7a2da50e62926a04f2f369eadb91c0f7fd825",
|
|
234
|
+
"output": "OP_2 eb0c727d7160a3e717c3ec0cb3e7a2da50e62926a04f2f369eadb91c0f7fd825",
|
|
235
|
+
"address": "bc1zavx8ylt3vz37w97rasxt8eazmfgwv2fx5p8j7d574ku3crmlmqjsgtmlz6",
|
|
236
|
+
"input": null,
|
|
237
|
+
"redeemVersion": 250,
|
|
238
|
+
"witness": [
|
|
239
|
+
"51",
|
|
240
|
+
"fb"
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
],
|
|
245
|
+
"invalid": [],
|
|
246
|
+
"dynamic": {
|
|
247
|
+
"depends": {
|
|
248
|
+
"output": [
|
|
249
|
+
"hash",
|
|
250
|
+
"address"
|
|
251
|
+
],
|
|
252
|
+
"address": [
|
|
253
|
+
"hash",
|
|
254
|
+
"output"
|
|
255
|
+
],
|
|
256
|
+
"hash": [
|
|
257
|
+
"output",
|
|
258
|
+
"address"
|
|
259
|
+
]
|
|
260
|
+
},
|
|
261
|
+
"details": [
|
|
262
|
+
{
|
|
263
|
+
"description": "p2mr round-trip",
|
|
264
|
+
"hash": "a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
|
|
265
|
+
"output": "OP_2 a8d3e8f07cd01a41b0ae8cc054c5ae07c1bce2b06ba4f8df26e7a7e1f9b6cde5",
|
|
266
|
+
"address": "bc1z4rf73uru6qdyrv9w3nq9f3dwqlqmec4sdwj03hexu7n7r7dkehjs592djq"
|
|
267
|
+
}
|
|
268
|
+
]
|
|
269
|
+
}
|
|
270
|
+
}
|
|
@@ -423,10 +423,12 @@ describe('bitcoinjs-lib (transaction with taproot)', () => {
|
|
|
423
423
|
await regtestUtils.broadcast(hex);
|
|
424
424
|
throw new Error('Broadcast should fail.');
|
|
425
425
|
} catch (err) {
|
|
426
|
-
if ((err as
|
|
426
|
+
if ((err as Error).message !== 'non-BIP68-final') {
|
|
427
427
|
throw new Error(
|
|
428
|
-
|
|
428
|
+
`Expected OP_CHECKSEQUENCEVERIFY validation to fail. But it faild with: ${err}`,
|
|
429
|
+
{ cause: err },
|
|
429
430
|
);
|
|
431
|
+
}
|
|
430
432
|
}
|
|
431
433
|
await regtestUtils.mine(10);
|
|
432
434
|
await regtestUtils.broadcast(hex);
|
|
@@ -672,7 +674,9 @@ function buildLeafIndexFinalizer(
|
|
|
672
674
|
];
|
|
673
675
|
return { finalScriptWitness: witnessStackToScriptWitness(witness) };
|
|
674
676
|
} catch (err) {
|
|
675
|
-
throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}
|
|
677
|
+
throw new Error(`Can not finalize taproot input #${inputIndex}: ${err}`, {
|
|
678
|
+
cause: err,
|
|
679
|
+
});
|
|
676
680
|
}
|
|
677
681
|
};
|
|
678
682
|
}
|