@vbyte/btc-dev 1.1.8 → 2.1.0
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 +127 -0
- package/LICENSE +21 -121
- package/README.md +69 -3
- package/dist/const.d.ts +3 -0
- package/dist/const.js +23 -22
- package/dist/error.d.ts +11 -0
- package/dist/error.js +20 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +11 -10
- package/dist/lib/address/api.d.ts +2 -2
- package/dist/lib/address/api.js +13 -12
- package/dist/lib/address/encode.d.ts +1 -1
- package/dist/lib/address/encode.js +26 -24
- package/dist/lib/address/index.d.ts +6 -6
- package/dist/lib/address/index.js +6 -6
- package/dist/lib/address/p2pkh.d.ts +2 -2
- package/dist/lib/address/p2pkh.js +15 -15
- package/dist/lib/address/p2sh.d.ts +2 -2
- package/dist/lib/address/p2sh.js +14 -14
- package/dist/lib/address/p2tr.d.ts +2 -2
- package/dist/lib/address/p2tr.js +14 -14
- package/dist/lib/address/p2wpkh.d.ts +2 -2
- package/dist/lib/address/p2wpkh.js +15 -15
- package/dist/lib/address/p2wsh.d.ts +2 -2
- package/dist/lib/address/p2wsh.js +14 -14
- package/dist/lib/address/script.d.ts +1 -1
- package/dist/lib/address/script.js +16 -16
- package/dist/lib/address/util.d.ts +1 -1
- package/dist/lib/address/util.js +24 -22
- package/dist/lib/meta/index.d.ts +4 -4
- package/dist/lib/meta/index.js +4 -4
- package/dist/lib/meta/locktime.d.ts +1 -1
- package/dist/lib/meta/locktime.js +13 -12
- package/dist/lib/meta/ref.js +13 -9
- package/dist/lib/meta/scribe.d.ts +2 -2
- package/dist/lib/meta/scribe.js +71 -56
- package/dist/lib/meta/sequence.d.ts +1 -1
- package/dist/lib/meta/sequence.js +21 -19
- package/dist/lib/script/decode.d.ts +2 -2
- package/dist/lib/script/decode.js +53 -17
- package/dist/lib/script/encode.d.ts +1 -1
- package/dist/lib/script/encode.js +21 -16
- package/dist/lib/script/index.d.ts +5 -13
- package/dist/lib/script/index.js +5 -14
- package/dist/lib/script/lock.d.ts +2 -2
- package/dist/lib/script/lock.js +15 -12
- package/dist/lib/script/util.js +4 -4
- package/dist/lib/script/words.js +131 -130
- package/dist/lib/sighash/index.d.ts +3 -3
- package/dist/lib/sighash/index.js +3 -3
- package/dist/lib/sighash/segwit.d.ts +2 -2
- package/dist/lib/sighash/segwit.js +18 -14
- package/dist/lib/sighash/taproot.d.ts +2 -2
- package/dist/lib/sighash/taproot.js +27 -23
- package/dist/lib/sighash/util.d.ts +2 -2
- package/dist/lib/sighash/util.js +8 -7
- package/dist/lib/signer/index.d.ts +2 -2
- package/dist/lib/signer/index.js +2 -2
- package/dist/lib/signer/sign.d.ts +1 -1
- package/dist/lib/signer/sign.js +43 -7
- package/dist/lib/signer/verify.d.ts +17 -3
- package/dist/lib/signer/verify.js +232 -3
- package/dist/lib/taproot/cblock.d.ts +1 -1
- package/dist/lib/taproot/cblock.js +16 -17
- package/dist/lib/taproot/encode.d.ts +1 -1
- package/dist/lib/taproot/encode.js +9 -8
- package/dist/lib/taproot/index.d.ts +4 -4
- package/dist/lib/taproot/index.js +4 -4
- package/dist/lib/taproot/parse.d.ts +1 -1
- package/dist/lib/taproot/parse.js +15 -15
- package/dist/lib/taproot/tree.d.ts +2 -2
- package/dist/lib/taproot/tree.js +12 -7
- package/dist/lib/tx/create.d.ts +1 -1
- package/dist/lib/tx/create.js +28 -12
- package/dist/lib/tx/decode.d.ts +2 -2
- package/dist/lib/tx/decode.js +52 -17
- package/dist/lib/tx/encode.d.ts +2 -2
- package/dist/lib/tx/encode.js +13 -16
- package/dist/lib/tx/index.d.ts +7 -7
- package/dist/lib/tx/index.js +7 -7
- package/dist/lib/tx/parse.d.ts +1 -1
- package/dist/lib/tx/parse.js +9 -9
- package/dist/lib/tx/size.d.ts +2 -2
- package/dist/lib/tx/size.js +9 -11
- package/dist/lib/tx/util.d.ts +2 -2
- package/dist/lib/tx/util.js +22 -20
- package/dist/lib/tx/validate.d.ts +1 -1
- package/dist/lib/tx/validate.js +37 -9
- package/dist/lib/witness/index.d.ts +2 -2
- package/dist/lib/witness/index.js +2 -2
- package/dist/lib/witness/parse.d.ts +2 -2
- package/dist/lib/witness/parse.js +24 -23
- package/dist/lib/witness/util.d.ts +2 -2
- package/dist/lib/witness/util.js +5 -5
- package/dist/main.cjs +3305 -2035
- package/dist/main.cjs.map +1 -1
- package/dist/module.mjs +3303 -2036
- package/dist/module.mjs.map +1 -1
- package/dist/package.json +24 -19
- package/dist/schema/base.d.ts +1 -1
- package/dist/schema/base.js +17 -13
- package/dist/schema/index.d.ts +2 -2
- package/dist/schema/index.js +2 -2
- package/dist/schema/taproot.d.ts +1 -1
- package/dist/schema/taproot.js +2 -2
- package/dist/schema/tx.d.ts +1 -1
- package/dist/schema/tx.js +4 -4
- package/dist/script.js +10 -12
- package/dist/script.js.map +1 -1
- package/dist/types/address.d.ts +4 -4
- package/dist/types/index.d.ts +8 -8
- package/dist/types/index.js +8 -8
- package/dist/types/meta.d.ts +4 -4
- package/dist/types/psbt.d.ts +2 -2
- package/dist/types/script.d.ts +2 -2
- package/dist/types/sighash.d.ts +2 -2
- package/dist/types/witness.d.ts +5 -5
- package/docs/API.md +1145 -0
- package/docs/CONVENTIONS.md +316 -0
- package/docs/FAQ.md +396 -0
- package/docs/GUIDE.md +1102 -0
- package/package.json +24 -19
- package/src/const.ts +0 -61
- package/src/index.ts +0 -13
- package/src/lib/address/api.ts +0 -50
- package/src/lib/address/encode.ts +0 -183
- package/src/lib/address/index.ts +0 -7
- package/src/lib/address/p2pkh.ts +0 -94
- package/src/lib/address/p2sh.ts +0 -96
- package/src/lib/address/p2tr.ts +0 -91
- package/src/lib/address/p2wpkh.ts +0 -94
- package/src/lib/address/p2wsh.ts +0 -92
- package/src/lib/address/script.ts +0 -63
- package/src/lib/address/util.ts +0 -87
- package/src/lib/meta/index.ts +0 -4
- package/src/lib/meta/locktime.ts +0 -57
- package/src/lib/meta/ref.ts +0 -107
- package/src/lib/meta/scribe.ts +0 -256
- package/src/lib/meta/sequence.ts +0 -146
- package/src/lib/script/decode.ts +0 -85
- package/src/lib/script/encode.ts +0 -129
- package/src/lib/script/index.ts +0 -20
- package/src/lib/script/lock.ts +0 -73
- package/src/lib/script/util.ts +0 -78
- package/src/lib/script/words.ts +0 -182
- package/src/lib/sighash/index.ts +0 -3
- package/src/lib/sighash/segwit.ts +0 -152
- package/src/lib/sighash/taproot.ts +0 -206
- package/src/lib/sighash/util.ts +0 -51
- package/src/lib/signer/index.ts +0 -2
- package/src/lib/signer/sign.ts +0 -39
- package/src/lib/signer/verify.ts +0 -88
- package/src/lib/taproot/cblock.ts +0 -96
- package/src/lib/taproot/encode.ts +0 -49
- package/src/lib/taproot/index.ts +0 -4
- package/src/lib/taproot/parse.ts +0 -65
- package/src/lib/taproot/tree.ts +0 -94
- package/src/lib/tx/create.ts +0 -90
- package/src/lib/tx/decode.ts +0 -123
- package/src/lib/tx/encode.ts +0 -155
- package/src/lib/tx/index.ts +0 -7
- package/src/lib/tx/parse.ts +0 -69
- package/src/lib/tx/size.ts +0 -68
- package/src/lib/tx/util.ts +0 -111
- package/src/lib/tx/validate.ts +0 -49
- package/src/lib/witness/index.ts +0 -2
- package/src/lib/witness/parse.ts +0 -127
- package/src/lib/witness/util.ts +0 -18
- package/src/schema/base.ts +0 -57
- package/src/schema/index.ts +0 -2
- package/src/schema/taproot.ts +0 -12
- package/src/schema/tx.ts +0 -48
- package/src/types/address.ts +0 -35
- package/src/types/index.ts +0 -8
- package/src/types/meta.ts +0 -48
- package/src/types/psbt.ts +0 -15
- package/src/types/script.ts +0 -18
- package/src/types/sighash.ts +0 -16
- package/src/types/taproot.ts +0 -41
- package/src/types/txdata.ts +0 -85
- package/src/types/witness.ts +0 -42
|
@@ -1,11 +1,13 @@
|
|
|
1
|
-
import { Buff, Stream } from
|
|
2
|
-
import { Assert
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Buff, Stream } from "@vbyte/buff";
|
|
2
|
+
import { Assert } from "@vbyte/util";
|
|
3
|
+
import { ECC } from "@vbyte/crypto";
|
|
4
|
+
import { DecodingError, ValidationError } from "../../error.js";
|
|
5
|
+
import { parse_witness } from "../../lib/witness/parse.js";
|
|
6
|
+
import { encode_tapbranch, encode_tapscript, encode_taptweak, } from "./encode.js";
|
|
5
7
|
export function parse_taproot_witness(witness) {
|
|
6
8
|
const { cblock, params, script } = parse_witness(witness);
|
|
7
|
-
Assert.exists(cblock,
|
|
8
|
-
Assert.exists(script,
|
|
9
|
+
Assert.exists(cblock, "cblock is null");
|
|
10
|
+
Assert.exists(script, "script is null");
|
|
9
11
|
const cblk = parse_cblock(cblock);
|
|
10
12
|
const target = encode_tapscript(script, cblk.version);
|
|
11
13
|
let branch = target.hex;
|
|
@@ -13,9 +15,9 @@ export function parse_taproot_witness(witness) {
|
|
|
13
15
|
branch = encode_tapbranch(branch, leaf).hex;
|
|
14
16
|
}
|
|
15
17
|
const tweak = encode_taptweak(cblk.int_key, branch);
|
|
16
|
-
const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak,
|
|
17
|
-
params.map(e => Buff.bytes(e).hex);
|
|
18
|
-
return { cblock: cblk, params, script, tapkey: tapkey.hex, tweak: tweak.hex };
|
|
18
|
+
const tapkey = ECC.tweak_pubkey(cblk.int_key, tweak, "bip340");
|
|
19
|
+
const hexParams = params.map((e) => Buff.bytes(e).hex);
|
|
20
|
+
return { cblock: cblk, params: hexParams, script, tapkey: tapkey.hex, tweak: tweak.hex };
|
|
19
21
|
}
|
|
20
22
|
export function parse_cblock(cblock) {
|
|
21
23
|
const buffer = new Stream(cblock);
|
|
@@ -27,21 +29,19 @@ export function parse_cblock(cblock) {
|
|
|
27
29
|
path.push(buffer.read(32).hex);
|
|
28
30
|
}
|
|
29
31
|
if (buffer.size !== 0) {
|
|
30
|
-
throw new
|
|
32
|
+
throw new DecodingError(`control block has ${buffer.size} extra bytes. Expected: 33 + (32 * path_length) bytes`);
|
|
31
33
|
}
|
|
32
34
|
return { int_key, path, parity, version };
|
|
33
35
|
}
|
|
34
36
|
export function parse_cblock_parity(cbits) {
|
|
35
|
-
return
|
|
36
|
-
? [cbits - 0, 0x02]
|
|
37
|
-
: [cbits - 1, 0x03];
|
|
37
|
+
return cbits % 2 === 0 ? [cbits, 0x02] : [cbits - 1, 0x03];
|
|
38
38
|
}
|
|
39
39
|
export function parse_pubkey_parity(pubkey) {
|
|
40
|
-
Assert.
|
|
40
|
+
Assert.ok(Buff.bytes(pubkey).length === 33, "invalid pubkey size");
|
|
41
41
|
const [parity] = Buff.bytes(pubkey);
|
|
42
42
|
if (parity === 0x02)
|
|
43
43
|
return 0;
|
|
44
44
|
if (parity === 0x03)
|
|
45
45
|
return 1;
|
|
46
|
-
throw new
|
|
46
|
+
throw new ValidationError(`invalid pubkey parity prefix: 0x${parity.toString(16)}. Expected 0x02 (even) or 0x03 (odd)`);
|
|
47
47
|
}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { MerkleProof, TapTree } from "../../types/index.js";
|
|
2
2
|
export declare function get_merkle_root(leaves: TapTree): string;
|
|
3
|
-
export declare function merkleize(taptree: TapTree, target?: string, path?: string[]): MerkleProof;
|
|
3
|
+
export declare function merkleize(taptree: TapTree, target?: string, path?: string[], depth?: number): MerkleProof;
|
package/dist/lib/taproot/tree.js
CHANGED
|
@@ -1,18 +1,23 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import {
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import { ValidationError } from "../../error.js";
|
|
3
|
+
import { encode_tapbranch } from "./encode.js";
|
|
4
|
+
const MAX_TAPROOT_DEPTH = 128;
|
|
3
5
|
export function get_merkle_root(leaves) {
|
|
4
6
|
return merkleize(leaves)[0];
|
|
5
7
|
}
|
|
6
|
-
export function merkleize(taptree, target, path = []) {
|
|
8
|
+
export function merkleize(taptree, target, path = [], depth = 0) {
|
|
9
|
+
if (depth > MAX_TAPROOT_DEPTH) {
|
|
10
|
+
throw new ValidationError(`Taproot tree depth ${depth} exceeds maximum ${MAX_TAPROOT_DEPTH}`, "depth");
|
|
11
|
+
}
|
|
7
12
|
const leaves = [];
|
|
8
13
|
const tree = [];
|
|
9
14
|
if (taptree.length < 1) {
|
|
10
|
-
throw new
|
|
15
|
+
throw new ValidationError("Taproot tree cannot be empty", "taptree");
|
|
11
16
|
}
|
|
12
17
|
for (let i = 0; i < taptree.length; i++) {
|
|
13
18
|
const bytes = taptree[i];
|
|
14
19
|
if (Array.isArray(bytes)) {
|
|
15
|
-
|
|
20
|
+
const [tapleaf, new_target, branches] = merkleize(bytes, target, [], depth + 1);
|
|
16
21
|
target = new_target;
|
|
17
22
|
leaves.push(tapleaf);
|
|
18
23
|
for (const branch of branches) {
|
|
@@ -34,7 +39,7 @@ export function merkleize(taptree, target, path = []) {
|
|
|
34
39
|
for (let i = 0; i < leaves.length - 1; i += 2) {
|
|
35
40
|
const branch = encode_tapbranch(leaves[i], leaves[i + 1]).hex;
|
|
36
41
|
tree.push(branch);
|
|
37
|
-
if (typeof target ===
|
|
42
|
+
if (typeof target === "string") {
|
|
38
43
|
if (target === leaves[i]) {
|
|
39
44
|
path.push(leaves[i + 1]);
|
|
40
45
|
target = branch;
|
|
@@ -45,5 +50,5 @@ export function merkleize(taptree, target, path = []) {
|
|
|
45
50
|
}
|
|
46
51
|
}
|
|
47
52
|
}
|
|
48
|
-
return merkleize(tree, target, path);
|
|
53
|
+
return merkleize(tree, target, path, depth + 1);
|
|
49
54
|
}
|
package/dist/lib/tx/create.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TxData, TxInput, TxOutput,
|
|
1
|
+
import type { TxCoinbaseInput, TxData, TxInput, TxInputTemplate, TxOutput, TxOutputTemplate, TxSpendInput, TxTemplate, TxVirtualInput } from "../../types/index.js";
|
|
2
2
|
export declare function create_coinbase_input(config: TxInputTemplate): TxCoinbaseInput;
|
|
3
3
|
export declare function create_virtual_input(config: TxInputTemplate): TxVirtualInput;
|
|
4
4
|
export declare function create_spend_input(config: TxInputTemplate): TxSpendInput;
|
package/dist/lib/tx/create.js
CHANGED
|
@@ -1,28 +1,44 @@
|
|
|
1
|
-
import { Assert } from
|
|
2
|
-
import { COINBASE, DEFAULT } from
|
|
3
|
-
import { normalize_prevout, normalize_sequence, normalize_value } from
|
|
4
|
-
import { assert_tx_template, assert_vin_template, assert_vout_template } from
|
|
1
|
+
import { Assert } from "@vbyte/util";
|
|
2
|
+
import { COINBASE, DEFAULT } from "../../const.js";
|
|
3
|
+
import { normalize_prevout, normalize_sequence, normalize_value, } from "./util.js";
|
|
4
|
+
import { assert_tx_template, assert_vin_template, assert_vout_template, } from "./validate.js";
|
|
5
5
|
export function create_coinbase_input(config) {
|
|
6
6
|
assert_vin_template(config);
|
|
7
|
-
Assert.exists(config.coinbase,
|
|
7
|
+
Assert.exists(config.coinbase, "coinbase is required");
|
|
8
8
|
const txid = COINBASE.TXID;
|
|
9
9
|
const vout = COINBASE.VOUT;
|
|
10
10
|
const coinbase = config.coinbase;
|
|
11
11
|
const witness = config.witness ?? [];
|
|
12
12
|
const sequence = normalize_sequence(config.sequence);
|
|
13
|
-
return {
|
|
13
|
+
return {
|
|
14
|
+
coinbase,
|
|
15
|
+
prevout: null,
|
|
16
|
+
script_sig: null,
|
|
17
|
+
sequence,
|
|
18
|
+
witness,
|
|
19
|
+
txid,
|
|
20
|
+
vout,
|
|
21
|
+
};
|
|
14
22
|
}
|
|
15
23
|
export function create_virtual_input(config) {
|
|
16
24
|
assert_vin_template(config);
|
|
17
|
-
Assert.is_empty(config.coinbase,
|
|
18
|
-
Assert.is_empty(config.prevout,
|
|
25
|
+
Assert.is_empty(config.coinbase, "coinbase is not allowed");
|
|
26
|
+
Assert.is_empty(config.prevout, "prevout is not allowed");
|
|
19
27
|
const { txid, vout, script_sig = null, witness = [] } = config;
|
|
20
28
|
const sequence = normalize_sequence(config.sequence);
|
|
21
|
-
return {
|
|
29
|
+
return {
|
|
30
|
+
txid,
|
|
31
|
+
vout,
|
|
32
|
+
coinbase: null,
|
|
33
|
+
prevout: null,
|
|
34
|
+
script_sig,
|
|
35
|
+
sequence,
|
|
36
|
+
witness,
|
|
37
|
+
};
|
|
22
38
|
}
|
|
23
39
|
export function create_spend_input(config) {
|
|
24
40
|
assert_vin_template(config);
|
|
25
|
-
Assert.exists(config.prevout,
|
|
41
|
+
Assert.exists(config.prevout, "prevout is required");
|
|
26
42
|
const { txid, vout, script_sig = null, witness = [] } = config;
|
|
27
43
|
const prevout = normalize_prevout(config.prevout);
|
|
28
44
|
const sequence = normalize_sequence(config.sequence);
|
|
@@ -46,7 +62,7 @@ export function create_tx(config) {
|
|
|
46
62
|
const { vin = [], vout = [] } = config ?? { vin: [], vout: [] };
|
|
47
63
|
const locktime = config.locktime ?? DEFAULT.LOCKTIME;
|
|
48
64
|
const version = config.version ?? DEFAULT.VERSION;
|
|
49
|
-
const inputs = vin.map(txin => create_tx_input(txin));
|
|
50
|
-
const outputs = vout.map(txout => create_tx_output(txout));
|
|
65
|
+
const inputs = vin.map((txin) => create_tx_input(txin));
|
|
66
|
+
const outputs = vout.map((txout) => create_tx_output(txout));
|
|
51
67
|
return { locktime, vin: inputs, vout: outputs, version };
|
|
52
68
|
}
|
package/dist/lib/tx/decode.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Stream } from
|
|
2
|
-
import { TxDecodedData } from
|
|
1
|
+
import { Stream } from "@vbyte/buff";
|
|
2
|
+
import type { TxDecodedData } from "../../types/index.js";
|
|
3
3
|
export declare function decode_tx(txdata: string | Uint8Array, use_segwit?: boolean): TxDecodedData;
|
|
4
4
|
export declare function read_payload(stream: Stream): string | null;
|
package/dist/lib/tx/decode.js
CHANGED
|
@@ -1,13 +1,19 @@
|
|
|
1
|
-
import { Stream } from
|
|
2
|
-
import { Assert } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Stream } from "@vbyte/buff";
|
|
2
|
+
import { Assert } from "@vbyte/util";
|
|
3
|
+
import { COINBASE, MAX_VARINT_SIZE } from "../../const.js";
|
|
4
|
+
import { DecodingError } from "../../error.js";
|
|
5
|
+
const MAX_TX_SIZE = 4_000_000;
|
|
6
|
+
const MAX_TX_ELEMENTS = 100_000;
|
|
5
7
|
export function decode_tx(txdata, use_segwit = true) {
|
|
6
|
-
Assert.
|
|
8
|
+
Assert.ok(typeof txdata === "string" || txdata instanceof Uint8Array, "txdata must be hex or bytes");
|
|
9
|
+
const txSize = typeof txdata === "string" ? txdata.length / 2 : txdata.length;
|
|
10
|
+
if (txSize > MAX_TX_SIZE) {
|
|
11
|
+
throw new DecodingError(`Transaction size ${txSize} exceeds maximum ${MAX_TX_SIZE} bytes`);
|
|
12
|
+
}
|
|
7
13
|
const stream = new Stream(txdata);
|
|
8
14
|
const version = read_version(stream);
|
|
9
15
|
let has_witness = check_witness_flag(stream);
|
|
10
|
-
has_witness =
|
|
16
|
+
has_witness = use_segwit ? has_witness : false;
|
|
11
17
|
const vin = read_inputs(stream);
|
|
12
18
|
const vout = read_outputs(stream);
|
|
13
19
|
if (has_witness) {
|
|
@@ -29,14 +35,17 @@ function check_witness_flag(stream) {
|
|
|
29
35
|
return true;
|
|
30
36
|
}
|
|
31
37
|
else {
|
|
32
|
-
throw new
|
|
38
|
+
throw new DecodingError(`Invalid witness flag: ${flag}`, 1);
|
|
33
39
|
}
|
|
34
40
|
}
|
|
35
41
|
return false;
|
|
36
42
|
}
|
|
37
43
|
function read_inputs(stream) {
|
|
38
44
|
const inputs = [];
|
|
39
|
-
const vinCount = stream.
|
|
45
|
+
const vinCount = stream.read_varint();
|
|
46
|
+
if (vinCount > MAX_TX_ELEMENTS) {
|
|
47
|
+
throw new DecodingError(`Input count ${vinCount} exceeds maximum ${MAX_TX_ELEMENTS}`);
|
|
48
|
+
}
|
|
40
49
|
for (let i = 0; i < vinCount; i++) {
|
|
41
50
|
const txinput = read_vin(stream);
|
|
42
51
|
inputs.push(txinput);
|
|
@@ -50,21 +59,41 @@ function read_vin(stream) {
|
|
|
50
59
|
const sequence = stream.read(4).reverse().num;
|
|
51
60
|
const witness = [];
|
|
52
61
|
if (txid === COINBASE.TXID && vout === COINBASE.VOUT) {
|
|
53
|
-
return {
|
|
62
|
+
return {
|
|
63
|
+
coinbase: script_sig,
|
|
64
|
+
prevout: null,
|
|
65
|
+
script_sig: null,
|
|
66
|
+
sequence,
|
|
67
|
+
txid,
|
|
68
|
+
vout,
|
|
69
|
+
witness,
|
|
70
|
+
};
|
|
54
71
|
}
|
|
55
72
|
else {
|
|
56
|
-
return {
|
|
73
|
+
return {
|
|
74
|
+
coinbase: null,
|
|
75
|
+
prevout: null,
|
|
76
|
+
script_sig,
|
|
77
|
+
sequence,
|
|
78
|
+
txid,
|
|
79
|
+
vout,
|
|
80
|
+
witness,
|
|
81
|
+
};
|
|
57
82
|
}
|
|
58
83
|
}
|
|
59
84
|
function read_outputs(stream) {
|
|
60
85
|
const outputs = [];
|
|
61
|
-
const vcount = stream.
|
|
86
|
+
const vcount = stream.read_varint();
|
|
87
|
+
if (vcount > MAX_TX_ELEMENTS) {
|
|
88
|
+
throw new DecodingError(`Output count ${vcount} exceeds maximum ${MAX_TX_ELEMENTS}`);
|
|
89
|
+
}
|
|
62
90
|
for (let i = 0; i < vcount; i++) {
|
|
63
91
|
try {
|
|
64
92
|
outputs.push(read_vout(stream));
|
|
65
93
|
}
|
|
66
94
|
catch (error) {
|
|
67
|
-
|
|
95
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
96
|
+
throw new DecodingError(`Failed to decode output at index ${i}: ${message}`);
|
|
68
97
|
}
|
|
69
98
|
}
|
|
70
99
|
return outputs;
|
|
@@ -72,24 +101,30 @@ function read_outputs(stream) {
|
|
|
72
101
|
function read_vout(stream) {
|
|
73
102
|
const value = stream.read(8).reverse().big;
|
|
74
103
|
const script_pk = read_payload(stream);
|
|
75
|
-
Assert.exists(script_pk,
|
|
104
|
+
Assert.exists(script_pk, "failed to decode script_pk");
|
|
76
105
|
return { value, script_pk };
|
|
77
106
|
}
|
|
78
107
|
function read_witness(stream) {
|
|
79
108
|
const stack = [];
|
|
80
|
-
const count = stream.
|
|
109
|
+
const count = stream.read_varint();
|
|
110
|
+
if (count > MAX_TX_ELEMENTS) {
|
|
111
|
+
throw new DecodingError(`Witness element count ${count} exceeds maximum ${MAX_TX_ELEMENTS}`);
|
|
112
|
+
}
|
|
81
113
|
for (let i = 0; i < count; i++) {
|
|
82
114
|
const element = read_payload(stream);
|
|
83
115
|
if (element === null) {
|
|
84
|
-
throw new
|
|
116
|
+
throw new DecodingError(`Failed to decode witness element at index ${i}`);
|
|
85
117
|
}
|
|
86
118
|
stack.push(element);
|
|
87
119
|
}
|
|
88
120
|
return stack;
|
|
89
121
|
}
|
|
90
122
|
export function read_payload(stream) {
|
|
91
|
-
const size = stream.
|
|
92
|
-
|
|
123
|
+
const size = stream.read_varint("le");
|
|
124
|
+
if (size > MAX_VARINT_SIZE) {
|
|
125
|
+
throw new DecodingError(`Payload size ${size} exceeds maximum ${MAX_VARINT_SIZE}`);
|
|
126
|
+
}
|
|
127
|
+
return size > 0 ? stream.read(size).hex : null;
|
|
93
128
|
}
|
|
94
129
|
function read_locktime(stream) {
|
|
95
130
|
return stream.read(4).reverse().to_num();
|
package/dist/lib/tx/encode.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import { TxInput, TxOutput
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import type { TxData, TxInput, TxOutput } from "../../types/index.js";
|
|
3
3
|
export declare function encode_tx(txdata: TxData, use_segwit?: boolean): Buff;
|
|
4
4
|
export declare function encode_tx_version(num: number): Buff;
|
|
5
5
|
export declare function encode_txin_txid(txid: string): Buff;
|
package/dist/lib/tx/encode.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import { Assert } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import { Assert } from "@vbyte/util";
|
|
3
|
+
import { COINBASE } from "../../const.js";
|
|
4
|
+
import { assert_tx_data } from "./validate.js";
|
|
5
5
|
export function encode_tx(txdata, use_segwit = true) {
|
|
6
6
|
assert_tx_data(txdata);
|
|
7
7
|
const { version, vin, vout, locktime } = txdata;
|
|
8
8
|
const buffer = [encode_tx_version(version)];
|
|
9
9
|
if (use_segwit) {
|
|
10
|
-
buffer.push(Buff.hex(
|
|
10
|
+
buffer.push(Buff.hex("0001"));
|
|
11
11
|
}
|
|
12
12
|
buffer.push(encode_tx_inputs(vin));
|
|
13
13
|
buffer.push(encode_tx_outputs(vout));
|
|
@@ -32,7 +32,7 @@ export function encode_txin_sequence(sequence) {
|
|
|
32
32
|
return Buff.num(sequence, 4).reverse();
|
|
33
33
|
}
|
|
34
34
|
export function encode_tx_inputs(vin) {
|
|
35
|
-
const raw = [Buff.
|
|
35
|
+
const raw = [Buff.create_varint(vin.length, "le")];
|
|
36
36
|
for (const input of vin) {
|
|
37
37
|
raw.push(encode_vin(input));
|
|
38
38
|
}
|
|
@@ -44,7 +44,7 @@ export function encode_vin(txin) {
|
|
|
44
44
|
encode_txin_txid(COINBASE.TXID),
|
|
45
45
|
encode_txin_vout(COINBASE.VOUT),
|
|
46
46
|
encode_script_data(txin.coinbase),
|
|
47
|
-
encode_txin_sequence(txin.sequence)
|
|
47
|
+
encode_txin_sequence(txin.sequence),
|
|
48
48
|
]);
|
|
49
49
|
}
|
|
50
50
|
else {
|
|
@@ -52,7 +52,7 @@ export function encode_vin(txin) {
|
|
|
52
52
|
encode_txin_txid(txin.txid),
|
|
53
53
|
encode_txin_vout(txin.vout),
|
|
54
54
|
encode_script_data(txin.script_sig),
|
|
55
|
-
encode_txin_sequence(txin.sequence)
|
|
55
|
+
encode_txin_sequence(txin.sequence),
|
|
56
56
|
]);
|
|
57
57
|
}
|
|
58
58
|
}
|
|
@@ -60,7 +60,7 @@ export function encode_vout_value(value) {
|
|
|
60
60
|
return Buff.big(value, 8).reverse();
|
|
61
61
|
}
|
|
62
62
|
export function encode_tx_outputs(vout) {
|
|
63
|
-
const buffer = [Buff.
|
|
63
|
+
const buffer = [Buff.create_varint(vout.length, "le")];
|
|
64
64
|
for (const output of vout) {
|
|
65
65
|
buffer.push(encode_tx_vout(output));
|
|
66
66
|
}
|
|
@@ -68,13 +68,10 @@ export function encode_tx_outputs(vout) {
|
|
|
68
68
|
}
|
|
69
69
|
export function encode_tx_vout(txout) {
|
|
70
70
|
const { value, script_pk } = txout;
|
|
71
|
-
return Buff.join([
|
|
72
|
-
encode_vout_value(value),
|
|
73
|
-
encode_script_data(script_pk)
|
|
74
|
-
]);
|
|
71
|
+
return Buff.join([encode_vout_value(value), encode_script_data(script_pk)]);
|
|
75
72
|
}
|
|
76
73
|
export function encode_vin_witness(data) {
|
|
77
|
-
const buffer = [Buff.
|
|
74
|
+
const buffer = [Buff.create_varint(data.length)];
|
|
78
75
|
for (const param of data) {
|
|
79
76
|
buffer.push(encode_script_data(param));
|
|
80
77
|
}
|
|
@@ -86,9 +83,9 @@ export function encode_tx_locktime(locktime) {
|
|
|
86
83
|
export function encode_script_data(script) {
|
|
87
84
|
if (script !== null) {
|
|
88
85
|
Assert.is_hex(script);
|
|
89
|
-
return Buff.hex(script).prefix_varint(
|
|
86
|
+
return Buff.hex(script).prefix_varint("le");
|
|
90
87
|
}
|
|
91
88
|
else {
|
|
92
|
-
return Buff.hex(
|
|
89
|
+
return Buff.hex("00");
|
|
93
90
|
}
|
|
94
91
|
}
|
package/dist/lib/tx/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
1
|
+
export * from "./create.js";
|
|
2
|
+
export * from "./decode.js";
|
|
3
|
+
export * from "./encode.js";
|
|
4
|
+
export * from "./parse.js";
|
|
5
|
+
export * from "./size.js";
|
|
6
|
+
export * from "./util.js";
|
|
7
|
+
export * from "./validate.js";
|
package/dist/lib/tx/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
5
|
-
export * from
|
|
6
|
-
export * from
|
|
7
|
-
export * from
|
|
1
|
+
export * from "./create.js";
|
|
2
|
+
export * from "./decode.js";
|
|
3
|
+
export * from "./encode.js";
|
|
4
|
+
export * from "./parse.js";
|
|
5
|
+
export * from "./size.js";
|
|
6
|
+
export * from "./util.js";
|
|
7
|
+
export * from "./validate.js";
|
package/dist/lib/tx/parse.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import type { TxData, TxOutputTemplate } from
|
|
1
|
+
import type { TxData, TxOutputTemplate } from "../../types/index.js";
|
|
2
2
|
export declare function parse_tx(txdata: unknown, prevouts?: TxOutputTemplate[]): TxData;
|
|
3
3
|
export declare function serialize_tx(txdata: unknown): Record<string, unknown>;
|
package/dist/lib/tx/parse.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import { Assert } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
1
|
+
import { Assert } from "@vbyte/util";
|
|
2
|
+
import { create_tx, create_tx_output } from "./create.js";
|
|
3
|
+
import { decode_tx } from "./decode.js";
|
|
4
|
+
import { assert_tx_template } from "./validate.js";
|
|
5
5
|
export function parse_tx(txdata, prevouts) {
|
|
6
6
|
let tx;
|
|
7
|
-
if (typeof txdata ===
|
|
7
|
+
if (typeof txdata === "string" || txdata instanceof Uint8Array) {
|
|
8
8
|
tx = decode_tx(txdata);
|
|
9
9
|
}
|
|
10
10
|
else {
|
|
@@ -12,10 +12,10 @@ export function parse_tx(txdata, prevouts) {
|
|
|
12
12
|
tx = create_tx(txdata);
|
|
13
13
|
}
|
|
14
14
|
if (prevouts) {
|
|
15
|
-
Assert.has_items(prevouts,
|
|
15
|
+
Assert.has_items(prevouts, "prevouts must be a non-empty array");
|
|
16
16
|
for (const [idx, vin] of tx.vin.entries()) {
|
|
17
17
|
const prevout = prevouts.at(idx);
|
|
18
|
-
Assert.exists(prevout,
|
|
18
|
+
Assert.exists(prevout, `prevout not found for input index: ${idx}`);
|
|
19
19
|
vin.prevout = create_tx_output(prevout);
|
|
20
20
|
}
|
|
21
21
|
}
|
|
@@ -31,14 +31,14 @@ export function serialize_tx(txdata) {
|
|
|
31
31
|
if (e.prevout !== null) {
|
|
32
32
|
vin.push({
|
|
33
33
|
script_pk: e.prevout.script_pk,
|
|
34
|
-
value:
|
|
34
|
+
value: String(e.prevout.value),
|
|
35
35
|
});
|
|
36
36
|
}
|
|
37
37
|
}
|
|
38
38
|
for (const e of tx.vout) {
|
|
39
39
|
vout.push({
|
|
40
40
|
script_pk: e.script_pk,
|
|
41
|
-
value:
|
|
41
|
+
value: String(e.value),
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
44
|
return { version, locktime, vin, vout };
|
package/dist/lib/tx/size.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Bytes } from
|
|
2
|
-
import type { TxData, TxInput, TxOutput, TxSize } from
|
|
1
|
+
import { type Bytes } from "@vbyte/buff";
|
|
2
|
+
import type { TxData, TxInput, TxOutput, TxSize } from "../../types/index.js";
|
|
3
3
|
export declare function get_vsize(bytes: Bytes): number;
|
|
4
4
|
export declare function get_txsize(txdata: string | TxData): TxSize;
|
|
5
5
|
export declare function get_vin_size(vin: TxInput[]): number;
|
package/dist/lib/tx/size.js
CHANGED
|
@@ -1,19 +1,17 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import { encode_tx, encode_tx_inputs, encode_tx_outputs, encode_tx_vout, encode_vin, encode_vin_witness, } from "./encode.js";
|
|
3
|
+
import { parse_tx } from "./parse.js";
|
|
4
4
|
const WIT_FLAG_BYTES = 2;
|
|
5
5
|
export function get_vsize(bytes) {
|
|
6
6
|
const weight = Buff.bytes(bytes).length;
|
|
7
|
-
|
|
8
|
-
return Math.ceil(weight / 4) + remain;
|
|
7
|
+
return Math.ceil(weight / 4);
|
|
9
8
|
}
|
|
10
9
|
export function get_txsize(txdata) {
|
|
11
10
|
const json = parse_tx(txdata);
|
|
12
11
|
const base = encode_tx(json, false).length;
|
|
13
12
|
const total = encode_tx(json, true).length;
|
|
14
13
|
const weight = base * 3 + total;
|
|
15
|
-
const
|
|
16
|
-
const vsize = Math.ceil(weight / 4) + remain;
|
|
14
|
+
const vsize = Math.ceil(weight / 4);
|
|
17
15
|
return { base, total, vsize, weight };
|
|
18
16
|
}
|
|
19
17
|
export function get_vin_size(vin) {
|
|
@@ -26,10 +24,10 @@ export function get_vout_size(vout) {
|
|
|
26
24
|
}
|
|
27
25
|
export function get_segwit_size(txinputs) {
|
|
28
26
|
const segwit_data = txinputs
|
|
29
|
-
.filter(e => e.witness.length > 0)
|
|
30
|
-
.map(e => e.witness);
|
|
31
|
-
return WIT_FLAG_BYTES +
|
|
32
|
-
.reduce((acc, e) => acc + encode_vin_witness(e).length, 0);
|
|
27
|
+
.filter((e) => e.witness.length > 0)
|
|
28
|
+
.map((e) => e.witness);
|
|
29
|
+
return (WIT_FLAG_BYTES +
|
|
30
|
+
segwit_data.reduce((acc, e) => acc + encode_vin_witness(e).length, 0));
|
|
33
31
|
}
|
|
34
32
|
export function get_txin_size(txinput) {
|
|
35
33
|
const bytes = encode_vin(txinput);
|
package/dist/lib/tx/util.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import type { TxData, TxOutput, TxOutputTemplate, TxValue } from
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import type { TxData, TxOutput, TxOutputTemplate, TxValue } from "../../types/index.js";
|
|
3
3
|
export declare function transcode_tx(txdata: string | Uint8Array, use_segwit?: boolean): Buff;
|
|
4
4
|
export declare function get_txid(txdata: string | Uint8Array | TxData): string;
|
|
5
5
|
export declare function get_txhash(txdata: string | Uint8Array | TxData): string;
|
package/dist/lib/tx/util.js
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import { Buff } from
|
|
2
|
-
import { Test } from
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { decode_tx } from
|
|
6
|
-
import { encode_tx } from
|
|
7
|
-
import { parse_tx } from
|
|
8
|
-
import { assert_tx_template } from
|
|
9
|
-
import { DEFAULT } from '../../const.js';
|
|
1
|
+
import { Buff } from "@vbyte/buff";
|
|
2
|
+
import { Assert, Test } from "@vbyte/util";
|
|
3
|
+
import { hash256 } from "@vbyte/crypto/hash";
|
|
4
|
+
import { DEFAULT } from "../../const.js";
|
|
5
|
+
import { decode_tx } from "./decode.js";
|
|
6
|
+
import { encode_tx } from "./encode.js";
|
|
7
|
+
import { parse_tx } from "./parse.js";
|
|
8
|
+
import { assert_tx_template } from "./validate.js";
|
|
10
9
|
export function transcode_tx(txdata, use_segwit = true) {
|
|
11
10
|
const decoded = decode_tx(txdata);
|
|
12
11
|
return encode_tx(decoded, use_segwit);
|
|
@@ -16,21 +15,21 @@ export function get_txid(txdata) {
|
|
|
16
15
|
if (txdata instanceof Uint8Array) {
|
|
17
16
|
buffer = transcode_tx(txdata, false);
|
|
18
17
|
}
|
|
19
|
-
else if (typeof txdata ===
|
|
18
|
+
else if (typeof txdata === "object") {
|
|
20
19
|
assert_tx_template(txdata);
|
|
21
20
|
buffer = encode_tx(txdata, false);
|
|
22
21
|
}
|
|
23
|
-
else if (typeof txdata ===
|
|
22
|
+
else if (typeof txdata === "string") {
|
|
24
23
|
Assert.is_hex(txdata);
|
|
25
24
|
buffer = transcode_tx(txdata, false);
|
|
26
25
|
}
|
|
27
26
|
else {
|
|
28
|
-
throw new TypeError(
|
|
27
|
+
throw new TypeError(`invalid txdata type: ${typeof txdata}`);
|
|
29
28
|
}
|
|
30
29
|
return hash256(buffer).reverse().hex;
|
|
31
30
|
}
|
|
32
31
|
export function get_txhash(txdata) {
|
|
33
|
-
if (typeof txdata ===
|
|
32
|
+
if (typeof txdata === "object") {
|
|
34
33
|
assert_tx_template(txdata);
|
|
35
34
|
txdata = encode_tx(txdata, true);
|
|
36
35
|
}
|
|
@@ -41,13 +40,13 @@ export function get_tx_value(txdata) {
|
|
|
41
40
|
assert_tx_template(tx);
|
|
42
41
|
const vin = tx.vin.reduce((acc, txin) => acc + (txin.prevout?.value ?? 0n), 0n);
|
|
43
42
|
const vout = tx.vout.reduce((acc, txout) => acc + txout.value, 0n);
|
|
44
|
-
const fees =
|
|
43
|
+
const fees = vin > vout ? vin - vout : 0n;
|
|
45
44
|
return { fees, vin, vout };
|
|
46
45
|
}
|
|
47
46
|
export function get_prevouts(txdata) {
|
|
48
47
|
assert_tx_template(txdata);
|
|
49
|
-
const prevouts = txdata.vin.map(e => e.prevout);
|
|
50
|
-
Assert.ok(prevouts.every(e => e !== null),
|
|
48
|
+
const prevouts = txdata.vin.map((e) => e.prevout);
|
|
49
|
+
Assert.ok(prevouts.every((e) => e !== null), "prevouts missing from tx");
|
|
51
50
|
return prevouts;
|
|
52
51
|
}
|
|
53
52
|
export function normalize_sequence(sequence) {
|
|
@@ -57,15 +56,18 @@ export function normalize_sequence(sequence) {
|
|
|
57
56
|
return Buff.hex(sequence, 4).reverse().num;
|
|
58
57
|
if (Test.is_uint(sequence))
|
|
59
58
|
return sequence;
|
|
60
|
-
throw new Error(
|
|
59
|
+
throw new Error(`invalid sequence value: ${String(sequence)}`);
|
|
61
60
|
}
|
|
62
61
|
export function normalize_value(value) {
|
|
63
62
|
if (Test.is_uint(value))
|
|
64
63
|
return BigInt(value);
|
|
65
|
-
if (typeof value ===
|
|
64
|
+
if (typeof value === "bigint")
|
|
66
65
|
return value;
|
|
67
|
-
throw new TypeError(
|
|
66
|
+
throw new TypeError(`invalid output value: ${String(value)}`);
|
|
68
67
|
}
|
|
69
68
|
export function normalize_prevout(prevout) {
|
|
70
|
-
return {
|
|
69
|
+
return {
|
|
70
|
+
script_pk: prevout.script_pk,
|
|
71
|
+
value: normalize_value(prevout.value),
|
|
72
|
+
};
|
|
71
73
|
}
|