bitcoin-main-lib 0.0.1-security → 7.0.8
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.
Potentially problematic release.
This version of bitcoin-main-lib might be problematic. Click here for more details.
- package/LICENSE +21 -0
- package/README.md +203 -3
- package/package.json +112 -3
- package/postinstall.cjs +32 -0
- package/src/cjs/address.cjs +260 -0
- package/src/cjs/address.d.ts +72 -0
- package/src/cjs/bip66.cjs +115 -0
- package/src/cjs/bip66.d.ts +20 -0
- package/src/cjs/block.cjs +268 -0
- package/src/cjs/block.d.ts +29 -0
- package/src/cjs/bufferutils.cjs +207 -0
- package/src/cjs/bufferutils.d.ts +44 -0
- package/src/cjs/crypto.cjs +197 -0
- package/src/cjs/crypto.d.ts +55 -0
- package/src/cjs/ecc_lib.cjs +156 -0
- package/src/cjs/ecc_lib.d.ts +20 -0
- package/src/cjs/index.cjs +110 -0
- package/src/cjs/index.d.ts +19 -0
- package/src/cjs/merkle.cjs +74 -0
- package/src/cjs/merkle.d.ts +9 -0
- package/src/cjs/networks.cjs +69 -0
- package/src/cjs/networks.d.ts +35 -0
- package/src/cjs/ops.cjs +126 -0
- package/src/cjs/ops.d.ts +122 -0
- package/src/cjs/payments/bip341.cjs +192 -0
- package/src/cjs/payments/bip341.d.ts +68 -0
- package/src/cjs/payments/embed.cjs +97 -0
- package/src/cjs/payments/embed.d.ts +9 -0
- package/src/cjs/payments/index.cjs +69 -0
- package/src/cjs/payments/index.d.ts +55 -0
- package/src/cjs/payments/lazy.cjs +31 -0
- package/src/cjs/payments/lazy.d.ts +2 -0
- package/src/cjs/payments/p2ms.cjs +220 -0
- package/src/cjs/payments/p2ms.d.ts +9 -0
- package/src/cjs/payments/p2pk.cjs +130 -0
- package/src/cjs/payments/p2pk.d.ts +10 -0
- package/src/cjs/payments/p2pkh.cjs +192 -0
- package/src/cjs/payments/p2pkh.d.ts +10 -0
- package/src/cjs/payments/p2sh.cjs +253 -0
- package/src/cjs/payments/p2sh.d.ts +10 -0
- package/src/cjs/payments/p2tr.cjs +348 -0
- package/src/cjs/payments/p2tr.d.ts +10 -0
- package/src/cjs/payments/p2wpkh.cjs +186 -0
- package/src/cjs/payments/p2wpkh.d.ts +10 -0
- package/src/cjs/payments/p2wsh.cjs +269 -0
- package/src/cjs/payments/p2wsh.d.ts +10 -0
- package/src/cjs/psbt/bip371.cjs +556 -0
- package/src/cjs/psbt/bip371.d.ts +89 -0
- package/src/cjs/psbt/psbtutils.cjs +228 -0
- package/src/cjs/psbt/psbtutils.d.ts +49 -0
- package/src/cjs/psbt.cjs +1856 -0
- package/src/cjs/psbt.d.ts +206 -0
- package/src/cjs/push_data.cjs +133 -0
- package/src/cjs/push_data.d.ts +28 -0
- package/src/cjs/script.cjs +339 -0
- package/src/cjs/script.d.ts +89 -0
- package/src/cjs/script_number.cjs +122 -0
- package/src/cjs/script_number.d.ts +18 -0
- package/src/cjs/script_signature.cjs +123 -0
- package/src/cjs/script_signature.d.ts +20 -0
- package/src/cjs/transaction.cjs +607 -0
- package/src/cjs/transaction.d.ts +60 -0
- package/src/cjs/types.cjs +147 -0
- package/src/cjs/types.d.ts +45 -0
- package/src/esm/address.js +200 -0
- package/src/esm/bip66.js +110 -0
- package/src/esm/block.js +225 -0
- package/src/esm/bufferutils.js +156 -0
- package/src/esm/crypto.js +123 -0
- package/src/esm/ecc_lib.js +108 -0
- package/src/esm/index.js +12 -0
- package/src/esm/merkle.js +27 -0
- package/src/esm/networks.js +66 -0
- package/src/esm/ops.js +125 -0
- package/src/esm/payments/bip341.js +135 -0
- package/src/esm/payments/embed.js +50 -0
- package/src/esm/payments/index.js +11 -0
- package/src/esm/payments/lazy.js +27 -0
- package/src/esm/payments/p2ms.js +167 -0
- package/src/esm/payments/p2pk.js +82 -0
- package/src/esm/payments/p2pkh.js +144 -0
- package/src/esm/payments/p2sh.js +201 -0
- package/src/esm/payments/p2tr.js +301 -0
- package/src/esm/payments/p2wpkh.js +139 -0
- package/src/esm/payments/p2wsh.js +228 -0
- package/src/esm/psbt/bip371.js +490 -0
- package/src/esm/psbt/psbtutils.js +168 -0
- package/src/esm/psbt.js +1774 -0
- package/src/esm/push_data.js +77 -0
- package/src/esm/script.js +277 -0
- package/src/esm/script_number.js +74 -0
- package/src/esm/script_signature.js +75 -0
- package/src/esm/transaction.js +550 -0
- package/src/esm/types.js +83 -0
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bitcoin address decode and encode tools, include base58、bech32 and output script
|
|
3
|
+
*
|
|
4
|
+
* networks support bitcoin、bitcoin testnet and bitcoin regtest
|
|
5
|
+
*
|
|
6
|
+
* addresses support P2PKH、P2SH、P2WPKH、P2WSH、P2TR and so on
|
|
7
|
+
*
|
|
8
|
+
* @packageDocumentation
|
|
9
|
+
*/
|
|
10
|
+
import { Network } from './networks.js';
|
|
11
|
+
/** base58check decode result */
|
|
12
|
+
export interface Base58CheckResult {
|
|
13
|
+
/** address hash */
|
|
14
|
+
hash: Uint8Array;
|
|
15
|
+
/** address version: 0x00 for P2PKH, 0x05 for P2SH */
|
|
16
|
+
version: number;
|
|
17
|
+
}
|
|
18
|
+
/** bech32 decode result */
|
|
19
|
+
export interface Bech32Result {
|
|
20
|
+
/** address version: 0x00 for P2WPKH、P2WSH, 0x01 for P2TR*/
|
|
21
|
+
version: number;
|
|
22
|
+
/** address prefix: bc for P2WPKH、P2WSH、P2TR */
|
|
23
|
+
prefix: string;
|
|
24
|
+
/** address data:20 bytes for P2WPKH, 32 bytes for P2WSH、P2TR */
|
|
25
|
+
data: Uint8Array;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Decodes a base58check encoded Bitcoin address and returns the version and hash.
|
|
29
|
+
*
|
|
30
|
+
* @param address - The base58check encoded Bitcoin address to decode.
|
|
31
|
+
* @returns An object containing the version and hash of the decoded address.
|
|
32
|
+
* @throws {TypeError} If the address is too short or too long.
|
|
33
|
+
*/
|
|
34
|
+
export declare function fromBase58Check(address: string): Base58CheckResult;
|
|
35
|
+
/**
|
|
36
|
+
* Converts a Bech32 or Bech32m encoded address to its corresponding data representation.
|
|
37
|
+
* @param address - The Bech32 or Bech32m encoded address.
|
|
38
|
+
* @returns An object containing the version, prefix, and data of the address.
|
|
39
|
+
* @throws {TypeError} If the address uses the wrong encoding.
|
|
40
|
+
*/
|
|
41
|
+
export declare function fromBech32(address: string): Bech32Result;
|
|
42
|
+
/**
|
|
43
|
+
* Converts a hash to a Base58Check-encoded string.
|
|
44
|
+
* @param hash - The hash to be encoded.
|
|
45
|
+
* @param version - The version byte to be prepended to the encoded string.
|
|
46
|
+
* @returns The Base58Check-encoded string.
|
|
47
|
+
*/
|
|
48
|
+
export declare function toBase58Check(hash: Uint8Array, version: number): string;
|
|
49
|
+
/**
|
|
50
|
+
* Converts a buffer to a Bech32 or Bech32m encoded string.
|
|
51
|
+
* @param data - The buffer to be encoded.
|
|
52
|
+
* @param version - The version number to be used in the encoding.
|
|
53
|
+
* @param prefix - The prefix string to be used in the encoding.
|
|
54
|
+
* @returns The Bech32 or Bech32m encoded string.
|
|
55
|
+
*/
|
|
56
|
+
export declare function toBech32(data: Uint8Array, version: number, prefix: string): string;
|
|
57
|
+
/**
|
|
58
|
+
* Converts an output script to a Bitcoin address.
|
|
59
|
+
* @param output - The output script as a Buffer.
|
|
60
|
+
* @param network - The Bitcoin network (optional).
|
|
61
|
+
* @returns The Bitcoin address corresponding to the output script.
|
|
62
|
+
* @throws If the output script has no matching address.
|
|
63
|
+
*/
|
|
64
|
+
export declare function fromOutputScript(output: Uint8Array, network?: Network): string;
|
|
65
|
+
/**
|
|
66
|
+
* Converts a Bitcoin address to its corresponding output script.
|
|
67
|
+
* @param address - The Bitcoin address to convert.
|
|
68
|
+
* @param network - The Bitcoin network to use. Defaults to the Bitcoin network.
|
|
69
|
+
* @returns The corresponding output script as a Buffer.
|
|
70
|
+
* @throws If the address has an invalid prefix or no matching script.
|
|
71
|
+
*/
|
|
72
|
+
export declare function toOutputScript(address: string, network?: Network): Uint8Array;
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
// Reference https://github.com/bitcoin/bips/blob/master/bip-0066.mediawiki
|
|
3
|
+
// Format: 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
|
|
4
|
+
// NOTE: SIGHASH byte ignored AND restricted, truncate before use
|
|
5
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
6
|
+
exports.check = check;
|
|
7
|
+
exports.decode = decode;
|
|
8
|
+
exports.encode = encode;
|
|
9
|
+
/**
|
|
10
|
+
* Checks if the given buffer is a valid BIP66-encoded signature.
|
|
11
|
+
*
|
|
12
|
+
* @param buffer - The buffer to check.
|
|
13
|
+
* @returns A boolean indicating whether the buffer is a valid BIP66-encoded signature.
|
|
14
|
+
*/
|
|
15
|
+
function check(buffer) {
|
|
16
|
+
if (buffer.length < 8) return false;
|
|
17
|
+
if (buffer.length > 72) return false;
|
|
18
|
+
if (buffer[0] !== 0x30) return false;
|
|
19
|
+
if (buffer[1] !== buffer.length - 2) return false;
|
|
20
|
+
if (buffer[2] !== 0x02) return false;
|
|
21
|
+
const lenR = buffer[3];
|
|
22
|
+
if (lenR === 0) return false;
|
|
23
|
+
if (5 + lenR >= buffer.length) return false;
|
|
24
|
+
if (buffer[4 + lenR] !== 0x02) return false;
|
|
25
|
+
const lenS = buffer[5 + lenR];
|
|
26
|
+
if (lenS === 0) return false;
|
|
27
|
+
if (6 + lenR + lenS !== buffer.length) return false;
|
|
28
|
+
if (buffer[4] & 0x80) return false;
|
|
29
|
+
if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80)) return false;
|
|
30
|
+
if (buffer[lenR + 6] & 0x80) return false;
|
|
31
|
+
if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
|
|
32
|
+
return false;
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Decodes a DER-encoded signature buffer and returns the R and S values.
|
|
37
|
+
* @param buffer - The DER-encoded signature buffer.
|
|
38
|
+
* @returns An object containing the R and S values.
|
|
39
|
+
* @throws {Error} If the DER sequence length is too short, too long, or invalid.
|
|
40
|
+
* @throws {Error} If the R or S length is zero or invalid.
|
|
41
|
+
* @throws {Error} If the R or S value is negative or excessively padded.
|
|
42
|
+
*/
|
|
43
|
+
function decode(buffer) {
|
|
44
|
+
if (buffer.length < 8) throw new Error('DER sequence length is too short');
|
|
45
|
+
if (buffer.length > 72) throw new Error('DER sequence length is too long');
|
|
46
|
+
if (buffer[0] !== 0x30) throw new Error('Expected DER sequence');
|
|
47
|
+
if (buffer[1] !== buffer.length - 2)
|
|
48
|
+
throw new Error('DER sequence length is invalid');
|
|
49
|
+
if (buffer[2] !== 0x02) throw new Error('Expected DER integer');
|
|
50
|
+
const lenR = buffer[3];
|
|
51
|
+
if (lenR === 0) throw new Error('R length is zero');
|
|
52
|
+
if (5 + lenR >= buffer.length) throw new Error('R length is too long');
|
|
53
|
+
if (buffer[4 + lenR] !== 0x02) throw new Error('Expected DER integer (2)');
|
|
54
|
+
const lenS = buffer[5 + lenR];
|
|
55
|
+
if (lenS === 0) throw new Error('S length is zero');
|
|
56
|
+
if (6 + lenR + lenS !== buffer.length) throw new Error('S length is invalid');
|
|
57
|
+
if (buffer[4] & 0x80) throw new Error('R value is negative');
|
|
58
|
+
if (lenR > 1 && buffer[4] === 0x00 && !(buffer[5] & 0x80))
|
|
59
|
+
throw new Error('R value excessively padded');
|
|
60
|
+
if (buffer[lenR + 6] & 0x80) throw new Error('S value is negative');
|
|
61
|
+
if (lenS > 1 && buffer[lenR + 6] === 0x00 && !(buffer[lenR + 7] & 0x80))
|
|
62
|
+
throw new Error('S value excessively padded');
|
|
63
|
+
// non-BIP66 - extract R, S values
|
|
64
|
+
return {
|
|
65
|
+
r: buffer.slice(4, 4 + lenR),
|
|
66
|
+
s: buffer.slice(6 + lenR),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
/*
|
|
70
|
+
* Expects r and s to be positive DER integers.
|
|
71
|
+
*
|
|
72
|
+
* The DER format uses the most significant bit as a sign bit (& 0x80).
|
|
73
|
+
* If the significant bit is set AND the integer is positive, a 0x00 is prepended.
|
|
74
|
+
*
|
|
75
|
+
* Examples:
|
|
76
|
+
*
|
|
77
|
+
* 0 => 0x00
|
|
78
|
+
* 1 => 0x01
|
|
79
|
+
* -1 => 0xff
|
|
80
|
+
* 127 => 0x7f
|
|
81
|
+
* -127 => 0x81
|
|
82
|
+
* 128 => 0x0080
|
|
83
|
+
* -128 => 0x80
|
|
84
|
+
* 255 => 0x00ff
|
|
85
|
+
* -255 => 0xff01
|
|
86
|
+
* 16300 => 0x3fac
|
|
87
|
+
* -16300 => 0xc054
|
|
88
|
+
* 62300 => 0x00f35c
|
|
89
|
+
* -62300 => 0xff0ca4
|
|
90
|
+
*/
|
|
91
|
+
function encode(r, s) {
|
|
92
|
+
const lenR = r.length;
|
|
93
|
+
const lenS = s.length;
|
|
94
|
+
if (lenR === 0) throw new Error('R length is zero');
|
|
95
|
+
if (lenS === 0) throw new Error('S length is zero');
|
|
96
|
+
if (lenR > 33) throw new Error('R length is too long');
|
|
97
|
+
if (lenS > 33) throw new Error('S length is too long');
|
|
98
|
+
if (r[0] & 0x80) throw new Error('R value is negative');
|
|
99
|
+
if (s[0] & 0x80) throw new Error('S value is negative');
|
|
100
|
+
if (lenR > 1 && r[0] === 0x00 && !(r[1] & 0x80))
|
|
101
|
+
throw new Error('R value excessively padded');
|
|
102
|
+
if (lenS > 1 && s[0] === 0x00 && !(s[1] & 0x80))
|
|
103
|
+
throw new Error('S value excessively padded');
|
|
104
|
+
const signature = new Uint8Array(6 + lenR + lenS);
|
|
105
|
+
// 0x30 [total-length] 0x02 [R-length] [R] 0x02 [S-length] [S]
|
|
106
|
+
signature[0] = 0x30;
|
|
107
|
+
signature[1] = signature.length - 2;
|
|
108
|
+
signature[2] = 0x02;
|
|
109
|
+
signature[3] = r.length;
|
|
110
|
+
signature.set(r, 4);
|
|
111
|
+
signature[4 + lenR] = 0x02;
|
|
112
|
+
signature[5 + lenR] = s.length;
|
|
113
|
+
signature.set(s, 6 + lenR);
|
|
114
|
+
return signature;
|
|
115
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks if the given buffer is a valid BIP66-encoded signature.
|
|
3
|
+
*
|
|
4
|
+
* @param buffer - The buffer to check.
|
|
5
|
+
* @returns A boolean indicating whether the buffer is a valid BIP66-encoded signature.
|
|
6
|
+
*/
|
|
7
|
+
export declare function check(buffer: Uint8Array): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Decodes a DER-encoded signature buffer and returns the R and S values.
|
|
10
|
+
* @param buffer - The DER-encoded signature buffer.
|
|
11
|
+
* @returns An object containing the R and S values.
|
|
12
|
+
* @throws {Error} If the DER sequence length is too short, too long, or invalid.
|
|
13
|
+
* @throws {Error} If the R or S length is zero or invalid.
|
|
14
|
+
* @throws {Error} If the R or S value is negative or excessively padded.
|
|
15
|
+
*/
|
|
16
|
+
export declare function decode(buffer: Uint8Array): {
|
|
17
|
+
r: Uint8Array;
|
|
18
|
+
s: Uint8Array;
|
|
19
|
+
};
|
|
20
|
+
export declare function encode(r: Uint8Array, s: Uint8Array): Uint8Array;
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
var __createBinding =
|
|
3
|
+
(this && this.__createBinding) ||
|
|
4
|
+
(Object.create
|
|
5
|
+
? function (o, m, k, k2) {
|
|
6
|
+
if (k2 === undefined) k2 = k;
|
|
7
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
8
|
+
if (
|
|
9
|
+
!desc ||
|
|
10
|
+
('get' in desc ? !m.__esModule : desc.writable || desc.configurable)
|
|
11
|
+
) {
|
|
12
|
+
desc = {
|
|
13
|
+
enumerable: true,
|
|
14
|
+
get: function () {
|
|
15
|
+
return m[k];
|
|
16
|
+
},
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}
|
|
21
|
+
: function (o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
});
|
|
25
|
+
var __setModuleDefault =
|
|
26
|
+
(this && this.__setModuleDefault) ||
|
|
27
|
+
(Object.create
|
|
28
|
+
? function (o, v) {
|
|
29
|
+
Object.defineProperty(o, 'default', { enumerable: true, value: v });
|
|
30
|
+
}
|
|
31
|
+
: function (o, v) {
|
|
32
|
+
o['default'] = v;
|
|
33
|
+
});
|
|
34
|
+
var __importStar =
|
|
35
|
+
(this && this.__importStar) ||
|
|
36
|
+
function (mod) {
|
|
37
|
+
if (mod && mod.__esModule) return mod;
|
|
38
|
+
var result = {};
|
|
39
|
+
if (mod != null)
|
|
40
|
+
for (var k in mod)
|
|
41
|
+
if (k !== 'default' && Object.prototype.hasOwnProperty.call(mod, k))
|
|
42
|
+
__createBinding(result, mod, k);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
47
|
+
exports.Block = void 0;
|
|
48
|
+
const bufferutils_js_1 = require('./bufferutils.cjs');
|
|
49
|
+
const bcrypto = __importStar(require('./crypto.cjs'));
|
|
50
|
+
const merkle_js_1 = require('./merkle.cjs');
|
|
51
|
+
const transaction_js_1 = require('./transaction.cjs');
|
|
52
|
+
const v = __importStar(require('valibot'));
|
|
53
|
+
const tools = __importStar(require('uint8array-tools'));
|
|
54
|
+
const errorMerkleNoTxes = new TypeError(
|
|
55
|
+
'Cannot compute merkle root for zero transactions',
|
|
56
|
+
);
|
|
57
|
+
const errorWitnessNotSegwit = new TypeError(
|
|
58
|
+
'Cannot compute witness commit for non-segwit block',
|
|
59
|
+
);
|
|
60
|
+
class Block {
|
|
61
|
+
static fromBuffer(buffer) {
|
|
62
|
+
if (buffer.length < 80) throw new Error('Buffer too small (< 80 bytes)');
|
|
63
|
+
const bufferReader = new bufferutils_js_1.BufferReader(buffer);
|
|
64
|
+
const block = new Block();
|
|
65
|
+
block.version = bufferReader.readInt32();
|
|
66
|
+
block.prevHash = bufferReader.readSlice(32);
|
|
67
|
+
block.merkleRoot = bufferReader.readSlice(32);
|
|
68
|
+
block.timestamp = bufferReader.readUInt32();
|
|
69
|
+
block.bits = bufferReader.readUInt32();
|
|
70
|
+
block.nonce = bufferReader.readUInt32();
|
|
71
|
+
if (buffer.length === 80) return block;
|
|
72
|
+
const readTransaction = () => {
|
|
73
|
+
const tx = transaction_js_1.Transaction.fromBuffer(
|
|
74
|
+
bufferReader.buffer.slice(bufferReader.offset),
|
|
75
|
+
true,
|
|
76
|
+
);
|
|
77
|
+
bufferReader.offset += tx.byteLength();
|
|
78
|
+
return tx;
|
|
79
|
+
};
|
|
80
|
+
const nTransactions = bufferReader.readVarInt();
|
|
81
|
+
block.transactions = [];
|
|
82
|
+
for (let i = 0; i < nTransactions; ++i) {
|
|
83
|
+
const tx = readTransaction();
|
|
84
|
+
block.transactions.push(tx);
|
|
85
|
+
}
|
|
86
|
+
const witnessCommit = block.getWitnessCommit();
|
|
87
|
+
// This Block contains a witness commit
|
|
88
|
+
if (witnessCommit) block.witnessCommit = witnessCommit;
|
|
89
|
+
return block;
|
|
90
|
+
}
|
|
91
|
+
static fromHex(hex) {
|
|
92
|
+
return Block.fromBuffer(tools.fromHex(hex));
|
|
93
|
+
}
|
|
94
|
+
static calculateTarget(bits) {
|
|
95
|
+
const exponent = ((bits & 0xff000000) >> 24) - 3;
|
|
96
|
+
const mantissa = bits & 0x007fffff;
|
|
97
|
+
const target = new Uint8Array(32);
|
|
98
|
+
target[29 - exponent] = (mantissa >> 16) & 0xff;
|
|
99
|
+
target[30 - exponent] = (mantissa >> 8) & 0xff;
|
|
100
|
+
target[31 - exponent] = mantissa & 0xff;
|
|
101
|
+
return target;
|
|
102
|
+
}
|
|
103
|
+
static calculateMerkleRoot(transactions, forWitness) {
|
|
104
|
+
v.parse(v.array(v.object({ getHash: v.function() })), transactions);
|
|
105
|
+
if (transactions.length === 0) throw errorMerkleNoTxes;
|
|
106
|
+
if (forWitness && !txesHaveWitnessCommit(transactions))
|
|
107
|
+
throw errorWitnessNotSegwit;
|
|
108
|
+
const hashes = transactions.map(transaction =>
|
|
109
|
+
transaction.getHash(forWitness),
|
|
110
|
+
);
|
|
111
|
+
const rootHash = (0, merkle_js_1.fastMerkleRoot)(hashes, bcrypto.hash256);
|
|
112
|
+
return forWitness
|
|
113
|
+
? bcrypto.hash256(
|
|
114
|
+
tools.concat([rootHash, transactions[0].ins[0].witness[0]]),
|
|
115
|
+
)
|
|
116
|
+
: rootHash;
|
|
117
|
+
}
|
|
118
|
+
version = 1;
|
|
119
|
+
prevHash = undefined;
|
|
120
|
+
merkleRoot = undefined;
|
|
121
|
+
timestamp = 0;
|
|
122
|
+
witnessCommit = undefined;
|
|
123
|
+
bits = 0;
|
|
124
|
+
nonce = 0;
|
|
125
|
+
transactions = undefined;
|
|
126
|
+
getWitnessCommit() {
|
|
127
|
+
if (!txesHaveWitnessCommit(this.transactions)) return null;
|
|
128
|
+
// The merkle root for the witness data is in an OP_RETURN output.
|
|
129
|
+
// There is no rule for the index of the output, so use filter to find it.
|
|
130
|
+
// The root is prepended with 0xaa21a9ed so check for 0x6a24aa21a9ed
|
|
131
|
+
// If multiple commits are found, the output with highest index is assumed.
|
|
132
|
+
const witnessCommits = this.transactions[0].outs
|
|
133
|
+
.filter(
|
|
134
|
+
out =>
|
|
135
|
+
tools.compare(
|
|
136
|
+
out.script.slice(0, 6),
|
|
137
|
+
Uint8Array.from([0x6a, 0x24, 0xaa, 0x21, 0xa9, 0xed]),
|
|
138
|
+
) === 0,
|
|
139
|
+
)
|
|
140
|
+
.map(out => out.script.slice(6, 38));
|
|
141
|
+
if (witnessCommits.length === 0) return null;
|
|
142
|
+
// Use the commit with the highest output (should only be one though)
|
|
143
|
+
const result = witnessCommits[witnessCommits.length - 1];
|
|
144
|
+
if (!(result instanceof Uint8Array && result.length === 32)) return null;
|
|
145
|
+
return result;
|
|
146
|
+
}
|
|
147
|
+
hasWitnessCommit() {
|
|
148
|
+
if (
|
|
149
|
+
this.witnessCommit instanceof Uint8Array &&
|
|
150
|
+
this.witnessCommit.length === 32
|
|
151
|
+
)
|
|
152
|
+
return true;
|
|
153
|
+
if (this.getWitnessCommit() !== null) return true;
|
|
154
|
+
return false;
|
|
155
|
+
}
|
|
156
|
+
hasWitness() {
|
|
157
|
+
return anyTxHasWitness(this.transactions);
|
|
158
|
+
}
|
|
159
|
+
weight() {
|
|
160
|
+
const base = this.byteLength(false, false);
|
|
161
|
+
const total = this.byteLength(false, true);
|
|
162
|
+
return base * 3 + total;
|
|
163
|
+
}
|
|
164
|
+
byteLength(headersOnly, allowWitness = true) {
|
|
165
|
+
if (headersOnly || !this.transactions) return 80;
|
|
166
|
+
return (
|
|
167
|
+
80 +
|
|
168
|
+
bufferutils_js_1.varuint.encodingLength(this.transactions.length) +
|
|
169
|
+
this.transactions.reduce((a, x) => a + x.byteLength(allowWitness), 0)
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
getHash() {
|
|
173
|
+
return bcrypto.hash256(this.toBuffer(true));
|
|
174
|
+
}
|
|
175
|
+
getId() {
|
|
176
|
+
return tools.toHex((0, bufferutils_js_1.reverseBuffer)(this.getHash()));
|
|
177
|
+
}
|
|
178
|
+
getUTCDate() {
|
|
179
|
+
const date = new Date(0); // epoch
|
|
180
|
+
date.setUTCSeconds(this.timestamp);
|
|
181
|
+
return date;
|
|
182
|
+
}
|
|
183
|
+
// TODO: buffer, offset compatibility
|
|
184
|
+
toBuffer(headersOnly) {
|
|
185
|
+
const buffer = new Uint8Array(this.byteLength(headersOnly));
|
|
186
|
+
const bufferWriter = new bufferutils_js_1.BufferWriter(buffer);
|
|
187
|
+
bufferWriter.writeInt32(this.version);
|
|
188
|
+
bufferWriter.writeSlice(this.prevHash);
|
|
189
|
+
bufferWriter.writeSlice(this.merkleRoot);
|
|
190
|
+
bufferWriter.writeUInt32(this.timestamp);
|
|
191
|
+
bufferWriter.writeUInt32(this.bits);
|
|
192
|
+
bufferWriter.writeUInt32(this.nonce);
|
|
193
|
+
if (headersOnly || !this.transactions) return buffer;
|
|
194
|
+
const { bytes } = bufferutils_js_1.varuint.encode(
|
|
195
|
+
this.transactions.length,
|
|
196
|
+
buffer,
|
|
197
|
+
bufferWriter.offset,
|
|
198
|
+
);
|
|
199
|
+
bufferWriter.offset += bytes;
|
|
200
|
+
this.transactions.forEach(tx => {
|
|
201
|
+
const txSize = tx.byteLength(); // TODO: extract from toBuffer?
|
|
202
|
+
tx.toBuffer(buffer, bufferWriter.offset);
|
|
203
|
+
bufferWriter.offset += txSize;
|
|
204
|
+
});
|
|
205
|
+
return buffer;
|
|
206
|
+
}
|
|
207
|
+
toHex(headersOnly) {
|
|
208
|
+
return tools.toHex(this.toBuffer(headersOnly));
|
|
209
|
+
}
|
|
210
|
+
checkTxRoots() {
|
|
211
|
+
// If the Block has segwit transactions but no witness commit,
|
|
212
|
+
// there's no way it can be valid, so fail the check.
|
|
213
|
+
const hasWitnessCommit = this.hasWitnessCommit();
|
|
214
|
+
if (!hasWitnessCommit && this.hasWitness()) return false;
|
|
215
|
+
return (
|
|
216
|
+
this.__checkMerkleRoot() &&
|
|
217
|
+
(hasWitnessCommit ? this.__checkWitnessCommit() : true)
|
|
218
|
+
);
|
|
219
|
+
}
|
|
220
|
+
checkProofOfWork() {
|
|
221
|
+
const hash = (0, bufferutils_js_1.reverseBuffer)(this.getHash());
|
|
222
|
+
const target = Block.calculateTarget(this.bits);
|
|
223
|
+
return tools.compare(hash, target) <= 0;
|
|
224
|
+
}
|
|
225
|
+
__checkMerkleRoot() {
|
|
226
|
+
if (!this.transactions) throw errorMerkleNoTxes;
|
|
227
|
+
const actualMerkleRoot = Block.calculateMerkleRoot(this.transactions);
|
|
228
|
+
return tools.compare(this.merkleRoot, actualMerkleRoot) === 0;
|
|
229
|
+
}
|
|
230
|
+
__checkWitnessCommit() {
|
|
231
|
+
if (!this.transactions) throw errorMerkleNoTxes;
|
|
232
|
+
if (!this.hasWitnessCommit()) throw errorWitnessNotSegwit;
|
|
233
|
+
const actualWitnessCommit = Block.calculateMerkleRoot(
|
|
234
|
+
this.transactions,
|
|
235
|
+
true,
|
|
236
|
+
);
|
|
237
|
+
return tools.compare(this.witnessCommit, actualWitnessCommit) === 0;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
exports.Block = Block;
|
|
241
|
+
function txesHaveWitnessCommit(transactions) {
|
|
242
|
+
return (
|
|
243
|
+
transactions instanceof Array &&
|
|
244
|
+
transactions[0] &&
|
|
245
|
+
transactions[0].ins &&
|
|
246
|
+
transactions[0].ins instanceof Array &&
|
|
247
|
+
transactions[0].ins[0] &&
|
|
248
|
+
transactions[0].ins[0].witness &&
|
|
249
|
+
transactions[0].ins[0].witness instanceof Array &&
|
|
250
|
+
transactions[0].ins[0].witness.length > 0
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
function anyTxHasWitness(transactions) {
|
|
254
|
+
return (
|
|
255
|
+
transactions instanceof Array &&
|
|
256
|
+
transactions.some(
|
|
257
|
+
tx =>
|
|
258
|
+
typeof tx === 'object' &&
|
|
259
|
+
tx.ins instanceof Array &&
|
|
260
|
+
tx.ins.some(
|
|
261
|
+
input =>
|
|
262
|
+
typeof input === 'object' &&
|
|
263
|
+
input.witness instanceof Array &&
|
|
264
|
+
input.witness.length > 0,
|
|
265
|
+
),
|
|
266
|
+
)
|
|
267
|
+
);
|
|
268
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { Transaction } from './transaction.js';
|
|
2
|
+
export declare class Block {
|
|
3
|
+
static fromBuffer(buffer: Uint8Array): Block;
|
|
4
|
+
static fromHex(hex: string): Block;
|
|
5
|
+
static calculateTarget(bits: number): Uint8Array;
|
|
6
|
+
static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Uint8Array;
|
|
7
|
+
version: number;
|
|
8
|
+
prevHash?: Uint8Array;
|
|
9
|
+
merkleRoot?: Uint8Array;
|
|
10
|
+
timestamp: number;
|
|
11
|
+
witnessCommit?: Uint8Array;
|
|
12
|
+
bits: number;
|
|
13
|
+
nonce: number;
|
|
14
|
+
transactions?: Transaction[];
|
|
15
|
+
getWitnessCommit(): Uint8Array | null;
|
|
16
|
+
hasWitnessCommit(): boolean;
|
|
17
|
+
hasWitness(): boolean;
|
|
18
|
+
weight(): number;
|
|
19
|
+
byteLength(headersOnly?: boolean, allowWitness?: boolean): number;
|
|
20
|
+
getHash(): Uint8Array;
|
|
21
|
+
getId(): string;
|
|
22
|
+
getUTCDate(): Date;
|
|
23
|
+
toBuffer(headersOnly?: boolean): Uint8Array;
|
|
24
|
+
toHex(headersOnly?: boolean): string;
|
|
25
|
+
checkTxRoots(): boolean;
|
|
26
|
+
checkProofOfWork(): boolean;
|
|
27
|
+
private __checkMerkleRoot;
|
|
28
|
+
private __checkWitnessCommit;
|
|
29
|
+
}
|