@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
|
@@ -0,0 +1,679 @@
|
|
|
1
|
+
# Block
|
|
2
|
+
|
|
3
|
+
The `Block` class represents a Bitcoin block, including its 80-byte header and optional array of transactions. It provides methods for parsing raw block data, computing block hashes and IDs, validating proof-of-work, verifying merkle roots, and handling SegWit witness commitments (BIP 141).
|
|
4
|
+
|
|
5
|
+
## Overview
|
|
6
|
+
|
|
7
|
+
| Property | Value |
|
|
8
|
+
|----------|-------|
|
|
9
|
+
| Header size | 80 bytes |
|
|
10
|
+
| Hash algorithm | Double SHA-256 (`hash256`) |
|
|
11
|
+
| Block ID format | Reversed hash as hex (matches block explorers) |
|
|
12
|
+
| Witness commitment | BIP 141 (`OP_RETURN` with prefix `0x6a24aa21a9ed`) |
|
|
13
|
+
| Weight formula | `base_size * 3 + total_size` |
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
## Block Header Structure
|
|
26
|
+
|
|
27
|
+
Every Bitcoin block begins with an 80-byte header containing six fields, serialized in the following order:
|
|
28
|
+
|
|
29
|
+
| Field | Type | Size | Description |
|
|
30
|
+
|-------|------|------|-------------|
|
|
31
|
+
| `version` | `int32le` | 4 bytes | Block version number (signed, little-endian) |
|
|
32
|
+
| `prevHash` | `Bytes32` | 32 bytes | Hash of the previous block header |
|
|
33
|
+
| `merkleRoot` | `Bytes32` | 32 bytes | Merkle root of the block's transactions |
|
|
34
|
+
| `timestamp` | `uint32le` | 4 bytes | Block timestamp as Unix epoch seconds |
|
|
35
|
+
| `bits` | `uint32le` | 4 bytes | Compact target threshold for proof-of-work |
|
|
36
|
+
| `nonce` | `uint32le` | 4 bytes | Nonce value iterated during mining |
|
|
37
|
+
|
|
38
|
+
After the header, a full block contains a varint transaction count followed by the serialized transactions.
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
[version:4][prevHash:32][merkleRoot:32][timestamp:4][bits:4][nonce:4][txCount:varint][tx0][tx1]...[txN]
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## Class: Block
|
|
47
|
+
|
|
48
|
+
```typescript
|
|
49
|
+
class Block {
|
|
50
|
+
// Header fields
|
|
51
|
+
version: number;
|
|
52
|
+
prevHash?: Bytes32;
|
|
53
|
+
merkleRoot?: Bytes32;
|
|
54
|
+
timestamp: number;
|
|
55
|
+
bits: number;
|
|
56
|
+
nonce: number;
|
|
57
|
+
|
|
58
|
+
// Body
|
|
59
|
+
transactions?: Transaction[];
|
|
60
|
+
|
|
61
|
+
// Witness (BIP 141)
|
|
62
|
+
witnessCommit?: Bytes32;
|
|
63
|
+
|
|
64
|
+
// Static methods
|
|
65
|
+
static fromBuffer(buffer: Uint8Array): Block;
|
|
66
|
+
static fromHex(hex: string): Block;
|
|
67
|
+
static calculateTarget(bits: number): Bytes32;
|
|
68
|
+
static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Bytes32;
|
|
69
|
+
|
|
70
|
+
// Instance methods
|
|
71
|
+
getHash(): Bytes32;
|
|
72
|
+
getId(): string;
|
|
73
|
+
getUTCDate(): Date;
|
|
74
|
+
getWitnessCommit(): Bytes32 | null;
|
|
75
|
+
hasWitnessCommit(): boolean;
|
|
76
|
+
hasWitness(): boolean;
|
|
77
|
+
weight(): number;
|
|
78
|
+
byteLength(headersOnly?: boolean, allowWitness?: boolean): number;
|
|
79
|
+
checkTxRoots(): boolean;
|
|
80
|
+
checkProofOfWork(): boolean;
|
|
81
|
+
toBuffer(headersOnly?: boolean): Uint8Array;
|
|
82
|
+
toHex(headersOnly?: boolean): string;
|
|
83
|
+
}
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Instance Properties
|
|
89
|
+
|
|
90
|
+
| Property | Type | Default | Description |
|
|
91
|
+
|----------|------|---------|-------------|
|
|
92
|
+
| `version` | `number` | `1` | Block version number, interpreted as a signed 32-bit integer (little-endian). Version 2+ signals BIP 34 (height in coinbase). |
|
|
93
|
+
| `prevHash` | `Bytes32 \| undefined` | `undefined` | 32-byte hash of the previous block header. The genesis block uses all zeros. |
|
|
94
|
+
| `merkleRoot` | `Bytes32 \| undefined` | `undefined` | 32-byte merkle root computed from the double-SHA256 hashes of all transactions in the block. |
|
|
95
|
+
| `timestamp` | `number` | `0` | Block timestamp in Unix epoch seconds. Must be greater than the median of the last 11 blocks. |
|
|
96
|
+
| `bits` | `number` | `0` | Compact encoding of the target threshold. The block hash must be less than or equal to the expanded target for the proof-of-work to be valid. |
|
|
97
|
+
| `nonce` | `number` | `0` | 32-bit nonce value. Miners iterate this field to search for a valid proof-of-work. |
|
|
98
|
+
| `transactions` | `Transaction[] \| undefined` | `undefined` | Array of transactions in the block. `undefined` when only the 80-byte header was parsed. The first transaction is always the coinbase. |
|
|
99
|
+
| `witnessCommit` | `Bytes32 \| undefined` | `undefined` | 32-byte witness commitment extracted from the coinbase transaction's `OP_RETURN` output. Present only for SegWit blocks (BIP 141). |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
## Static Methods
|
|
104
|
+
|
|
105
|
+
### Block.fromBuffer(buffer)
|
|
106
|
+
|
|
107
|
+
Parses a `Block` from a raw `Uint8Array`. If the buffer is exactly 80 bytes, only the header fields are populated and `transactions` remains `undefined`. If the buffer is longer, the transaction data following the header is deserialized, and the witness commitment is extracted if present.
|
|
108
|
+
|
|
109
|
+
```typescript
|
|
110
|
+
static fromBuffer(buffer: Uint8Array): Block;
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
| Parameter | Type | Description |
|
|
114
|
+
|-----------|------|-------------|
|
|
115
|
+
| `buffer` | `Uint8Array` | Raw block data (minimum 80 bytes) |
|
|
116
|
+
|
|
117
|
+
**Returns:** A fully populated `Block` instance.
|
|
118
|
+
|
|
119
|
+
**Throws:** `Error` if the buffer is smaller than 80 bytes.
|
|
120
|
+
|
|
121
|
+
```typescript
|
|
122
|
+
import { Block, fromHex } from '@btc-vision/bitcoin';
|
|
123
|
+
|
|
124
|
+
// Parse a header-only block (80 bytes = 160 hex chars)
|
|
125
|
+
const headerHex =
|
|
126
|
+
'020000003385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf08000000000000' +
|
|
127
|
+
'cf52f0ed6571367818a801a169e64030d8cab1a9f17e27170a6924127e19dbb8' +
|
|
128
|
+
'eba43e54ffff001d12052ce0';
|
|
129
|
+
const block = Block.fromBuffer(fromHex(headerHex));
|
|
130
|
+
|
|
131
|
+
console.log(block.version); // 2
|
|
132
|
+
console.log(block.timestamp); // 1413391595
|
|
133
|
+
console.log(block.transactions); // undefined (header only)
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
### Block.fromHex(hex)
|
|
139
|
+
|
|
140
|
+
Convenience wrapper around `fromBuffer` that accepts a hex string instead of a `Uint8Array`.
|
|
141
|
+
|
|
142
|
+
```typescript
|
|
143
|
+
static fromHex(hex: string): Block;
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
| Parameter | Type | Description |
|
|
147
|
+
|-----------|------|-------------|
|
|
148
|
+
| `hex` | `string` | Hexadecimal representation of the block |
|
|
149
|
+
|
|
150
|
+
**Returns:** A fully populated `Block` instance.
|
|
151
|
+
|
|
152
|
+
```typescript
|
|
153
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
154
|
+
|
|
155
|
+
const block = Block.fromHex('020000003385c4b2a349...');
|
|
156
|
+
console.log(block.version); // 2
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
### Block.calculateTarget(bits)
|
|
162
|
+
|
|
163
|
+
Expands the compact `bits` field from the block header into the full 32-byte target threshold. The compact format encodes the target as a 3-byte mantissa with a 1-byte exponent.
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
static calculateTarget(bits: number): Bytes32;
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
| Parameter | Type | Description |
|
|
170
|
+
|-----------|------|-------------|
|
|
171
|
+
| `bits` | `number` | Compact bits value from the block header |
|
|
172
|
+
|
|
173
|
+
**Returns:** 32-byte target threshold as `Bytes32`.
|
|
174
|
+
|
|
175
|
+
The encoding works as follows:
|
|
176
|
+
- The top byte `(bits >> 24)` is the exponent.
|
|
177
|
+
- The lower 3 bytes `(bits & 0x007fffff)` are the mantissa.
|
|
178
|
+
- The target is `mantissa * 2^(8 * (exponent - 3))`.
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
182
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
183
|
+
|
|
184
|
+
// Bitcoin mainnet difficulty 1 target
|
|
185
|
+
const target = Block.calculateTarget(0x1d00ffff);
|
|
186
|
+
console.log(toHex(target));
|
|
187
|
+
// '00000000ffff0000000000000000000000000000000000000000000000000000'
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
---
|
|
191
|
+
|
|
192
|
+
### Block.calculateMerkleRoot(transactions, forWitness?)
|
|
193
|
+
|
|
194
|
+
Computes the merkle root from an array of transactions. When `forWitness` is `true`, computes the witness merkle root used in BIP 141 witness commitments by hashing with witness data and combining with the coinbase witness nonce.
|
|
195
|
+
|
|
196
|
+
```typescript
|
|
197
|
+
static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Bytes32;
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
| Parameter | Type | Description |
|
|
201
|
+
|-----------|------|-------------|
|
|
202
|
+
| `transactions` | `Transaction[]` | Array of transactions |
|
|
203
|
+
| `forWitness` | `boolean \| undefined` | If `true`, calculate the witness merkle root |
|
|
204
|
+
|
|
205
|
+
**Returns:** 32-byte merkle root as `Bytes32`.
|
|
206
|
+
|
|
207
|
+
**Throws:**
|
|
208
|
+
- `TypeError` if `transactions` is empty or not an array.
|
|
209
|
+
- `TypeError` if `forWitness` is `true` but the coinbase has no witness data.
|
|
210
|
+
|
|
211
|
+
```typescript
|
|
212
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
213
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
214
|
+
|
|
215
|
+
const block = Block.fromHex(fullBlockHex);
|
|
216
|
+
const merkleRoot = Block.calculateMerkleRoot(block.transactions!);
|
|
217
|
+
console.log(toHex(merkleRoot)); // matches block.merkleRoot
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
---
|
|
221
|
+
|
|
222
|
+
## Instance Methods
|
|
223
|
+
|
|
224
|
+
### block.getHash()
|
|
225
|
+
|
|
226
|
+
Computes the double-SHA256 hash of the 80-byte block header. This is the raw 32-byte hash in internal byte order (little-endian).
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
getHash(): Bytes32;
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
**Returns:** 32-byte block hash as `Bytes32`.
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
236
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
237
|
+
|
|
238
|
+
const block = Block.fromHex(blockHex);
|
|
239
|
+
const hash = block.getHash();
|
|
240
|
+
console.log(toHex(hash));
|
|
241
|
+
// '55388f8f9b326bd0b8e50fbe44c1903d4be14febcfad4dffa50c846c00000000'
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
### block.getId()
|
|
247
|
+
|
|
248
|
+
Returns the block hash as a hex string in reversed byte order, matching the format used by block explorers and Bitcoin RPC.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
getId(): string;
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
**Returns:** Block ID as a hex string.
|
|
255
|
+
|
|
256
|
+
The difference between `getHash()` and `getId()` is byte order. Bitcoin displays block hashes with the bytes reversed from the internal representation.
|
|
257
|
+
|
|
258
|
+
```typescript
|
|
259
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
260
|
+
|
|
261
|
+
const block = Block.fromHex(blockHex);
|
|
262
|
+
console.log(block.getId());
|
|
263
|
+
// '000000006c840ca5ff4dadcfeb4fe14b3d90c144be0fe5b8d06b329b8f8f3855'
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
---
|
|
267
|
+
|
|
268
|
+
### block.getWitnessCommit()
|
|
269
|
+
|
|
270
|
+
Extracts the witness commitment hash from the coinbase transaction. The witness commitment is stored in an `OP_RETURN` output of the coinbase transaction, prefixed with `0x6a24aa21a9ed`. If multiple outputs match, the one with the highest index is used.
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
getWitnessCommit(): Bytes32 | null;
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
**Returns:** 32-byte witness commitment, or `null` if the block has no witness commitment.
|
|
277
|
+
|
|
278
|
+
```typescript
|
|
279
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
280
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
281
|
+
|
|
282
|
+
const block = Block.fromHex(segwitBlockHex);
|
|
283
|
+
const commit = block.getWitnessCommit();
|
|
284
|
+
if (commit) {
|
|
285
|
+
console.log(toHex(commit)); // 32-byte witness commitment
|
|
286
|
+
}
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
---
|
|
290
|
+
|
|
291
|
+
### block.hasWitnessCommit()
|
|
292
|
+
|
|
293
|
+
Checks whether the block contains a witness commitment, either from the already-set `witnessCommit` property or by scanning the coinbase transaction outputs.
|
|
294
|
+
|
|
295
|
+
```typescript
|
|
296
|
+
hasWitnessCommit(): boolean;
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
**Returns:** `true` if a witness commitment is present.
|
|
300
|
+
|
|
301
|
+
---
|
|
302
|
+
|
|
303
|
+
### block.hasWitness()
|
|
304
|
+
|
|
305
|
+
Checks whether any transaction in the block contains witness data.
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
hasWitness(): boolean;
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
**Returns:** `true` if any transaction has non-empty witness fields. Returns `false` if `transactions` is `undefined`.
|
|
312
|
+
|
|
313
|
+
---
|
|
314
|
+
|
|
315
|
+
### block.checkProofOfWork()
|
|
316
|
+
|
|
317
|
+
Validates the block's proof-of-work by comparing the block hash against the target threshold derived from the `bits` field. The block hash (in reversed byte order) must be less than or equal to the target.
|
|
318
|
+
|
|
319
|
+
```typescript
|
|
320
|
+
checkProofOfWork(): boolean;
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
**Returns:** `true` if the block hash satisfies the target difficulty.
|
|
324
|
+
|
|
325
|
+
```typescript
|
|
326
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
327
|
+
|
|
328
|
+
const block = Block.fromHex(blockHex);
|
|
329
|
+
|
|
330
|
+
if (block.checkProofOfWork()) {
|
|
331
|
+
console.log('Block has valid proof-of-work');
|
|
332
|
+
} else {
|
|
333
|
+
console.log('Invalid proof-of-work');
|
|
334
|
+
}
|
|
335
|
+
```
|
|
336
|
+
|
|
337
|
+
---
|
|
338
|
+
|
|
339
|
+
### block.checkTxRoots()
|
|
340
|
+
|
|
341
|
+
Validates both the transaction merkle root and the witness commitment (if present). Returns `false` if the block has witness data in its transactions but no witness commitment in the coinbase.
|
|
342
|
+
|
|
343
|
+
```typescript
|
|
344
|
+
checkTxRoots(): boolean;
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
**Returns:** `true` if the merkle root and witness commitment (when applicable) are valid.
|
|
348
|
+
|
|
349
|
+
| Throws | Condition |
|
|
350
|
+
|--------|-----------|
|
|
351
|
+
| `TypeError` | Block has no `transactions` array (header-only block). Message: `"Cannot compute merkle root for zero transactions"` |
|
|
352
|
+
| `TypeError` | Block has no `merkleRoot` set. Message: `"Block merkleRoot is required"` |
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
356
|
+
|
|
357
|
+
const block = Block.fromHex(fullBlockHex);
|
|
358
|
+
console.log(block.checkTxRoots()); // true for valid blocks
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
---
|
|
362
|
+
|
|
363
|
+
### block.weight()
|
|
364
|
+
|
|
365
|
+
Calculates the block weight as defined by BIP 141. Weight is used for block size limits in SegWit (maximum 4,000,000 weight units).
|
|
366
|
+
|
|
367
|
+
```typescript
|
|
368
|
+
weight(): number;
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
**Returns:** Block weight in weight units.
|
|
372
|
+
|
|
373
|
+
**Formula:** `weight = base_size * 3 + total_size`
|
|
374
|
+
|
|
375
|
+
Where `base_size` is the serialized size without witness data, and `total_size` includes witness data.
|
|
376
|
+
|
|
377
|
+
---
|
|
378
|
+
|
|
379
|
+
### block.byteLength(headersOnly?, allowWitness?)
|
|
380
|
+
|
|
381
|
+
Calculates the serialized byte length of the block.
|
|
382
|
+
|
|
383
|
+
```typescript
|
|
384
|
+
byteLength(headersOnly?: boolean, allowWitness?: boolean): number;
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
| Parameter | Type | Default | Description |
|
|
388
|
+
|-----------|------|---------|-------------|
|
|
389
|
+
| `headersOnly` | `boolean \| undefined` | `undefined` | If `true`, returns 80 (header size only) |
|
|
390
|
+
| `allowWitness` | `boolean` | `true` | If `true`, includes witness data in the calculation |
|
|
391
|
+
|
|
392
|
+
**Returns:** Byte length of the serialized block.
|
|
393
|
+
|
|
394
|
+
```typescript
|
|
395
|
+
const block = Block.fromHex(fullBlockHex);
|
|
396
|
+
|
|
397
|
+
console.log(block.byteLength(true)); // 80 (header only)
|
|
398
|
+
console.log(block.byteLength(false, false)); // stripped size (no witness)
|
|
399
|
+
console.log(block.byteLength(false, true)); // total size (with witness)
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
---
|
|
403
|
+
|
|
404
|
+
### block.getUTCDate()
|
|
405
|
+
|
|
406
|
+
Converts the block's `timestamp` field to a JavaScript `Date` object.
|
|
407
|
+
|
|
408
|
+
```typescript
|
|
409
|
+
getUTCDate(): Date;
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
**Returns:** `Date` object representing the block time in UTC.
|
|
413
|
+
|
|
414
|
+
```typescript
|
|
415
|
+
const block = Block.fromHex(blockHex);
|
|
416
|
+
console.log(block.getUTCDate().toISOString());
|
|
417
|
+
// '2014-10-15T19:33:15.000Z'
|
|
418
|
+
```
|
|
419
|
+
|
|
420
|
+
---
|
|
421
|
+
|
|
422
|
+
### block.toBuffer(headersOnly?)
|
|
423
|
+
|
|
424
|
+
Serializes the block to a `Uint8Array`. When `headersOnly` is `true`, only the 80-byte header is serialized. Otherwise, the full block including all transactions is serialized.
|
|
425
|
+
|
|
426
|
+
```typescript
|
|
427
|
+
toBuffer(headersOnly?: boolean): Uint8Array;
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
| Parameter | Type | Description |
|
|
431
|
+
|-----------|------|-------------|
|
|
432
|
+
| `headersOnly` | `boolean \| undefined` | If `true`, serialize only the 80-byte header |
|
|
433
|
+
|
|
434
|
+
**Returns:** Serialized block data as `Uint8Array`.
|
|
435
|
+
|
|
436
|
+
**Throws:** `TypeError` if `prevHash` or `merkleRoot` is not set.
|
|
437
|
+
|
|
438
|
+
```typescript
|
|
439
|
+
const block = Block.fromHex(blockHex);
|
|
440
|
+
|
|
441
|
+
const headerBytes = block.toBuffer(true); // 80 bytes
|
|
442
|
+
const fullBytes = block.toBuffer(); // full block
|
|
443
|
+
```
|
|
444
|
+
|
|
445
|
+
---
|
|
446
|
+
|
|
447
|
+
### block.toHex(headersOnly?)
|
|
448
|
+
|
|
449
|
+
Serializes the block to a hex string. This is a convenience wrapper around `toBuffer()`.
|
|
450
|
+
|
|
451
|
+
```typescript
|
|
452
|
+
toHex(headersOnly?: boolean): string;
|
|
453
|
+
```
|
|
454
|
+
|
|
455
|
+
| Parameter | Type | Description |
|
|
456
|
+
|-----------|------|-------------|
|
|
457
|
+
| `headersOnly` | `boolean \| undefined` | If `true`, serialize only the 80-byte header |
|
|
458
|
+
|
|
459
|
+
**Returns:** Hex string representation of the block.
|
|
460
|
+
|
|
461
|
+
```typescript
|
|
462
|
+
const block = Block.fromHex(blockHex);
|
|
463
|
+
const headerHex = block.toHex(true); // 160-character hex string (80 bytes)
|
|
464
|
+
const fullHex = block.toHex(); // full block as hex
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
---
|
|
468
|
+
|
|
469
|
+
## Witness Commitment (BIP 141)
|
|
470
|
+
|
|
471
|
+
SegWit blocks include a witness commitment in the coinbase transaction. The commitment is stored in an `OP_RETURN` output identified by the 6-byte prefix `0x6a24aa21a9ed`:
|
|
472
|
+
|
|
473
|
+
```
|
|
474
|
+
OP_RETURN OP_PUSHBYTES_36 0xaa21a9ed <32-byte witness commitment>
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
The witness commitment is computed as:
|
|
478
|
+
|
|
479
|
+
```
|
|
480
|
+
witness_root = merkle_root(witness_hashes_of_all_transactions)
|
|
481
|
+
witness_commitment = hash256(witness_root || witness_nonce)
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
Where `witness_nonce` is a 32-byte value stored in the coinbase input's witness field (typically all zeros).
|
|
485
|
+
|
|
486
|
+
The `Block` class handles witness commitments automatically:
|
|
487
|
+
|
|
488
|
+
1. `fromBuffer()` / `fromHex()` -- Extracts the witness commitment during parsing and sets `witnessCommit`.
|
|
489
|
+
2. `getWitnessCommit()` -- Scans the coinbase outputs for the commitment prefix and returns the 32-byte hash.
|
|
490
|
+
3. `hasWitnessCommit()` -- Checks if a witness commitment exists.
|
|
491
|
+
4. `checkTxRoots()` -- Validates both the standard merkle root and the witness commitment.
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
495
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
496
|
+
|
|
497
|
+
const block = Block.fromHex(segwitBlockHex);
|
|
498
|
+
|
|
499
|
+
// Check for witness data
|
|
500
|
+
console.log(block.hasWitness()); // true
|
|
501
|
+
console.log(block.hasWitnessCommit()); // true
|
|
502
|
+
|
|
503
|
+
// Access the witness commitment
|
|
504
|
+
if (block.witnessCommit) {
|
|
505
|
+
console.log(toHex(block.witnessCommit));
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
// Validate witness merkle root
|
|
509
|
+
console.log(block.checkTxRoots()); // true
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
---
|
|
513
|
+
|
|
514
|
+
## Examples
|
|
515
|
+
|
|
516
|
+
### Parsing a Block from Hex
|
|
517
|
+
|
|
518
|
+
```typescript
|
|
519
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
520
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
521
|
+
|
|
522
|
+
const blockHex = '020000003385c4b2a3499669987f5d04fa4127b59dbf2ee625694fa0bf' +
|
|
523
|
+
'08000000000000cf52f0ed6571367818a801a169e64030d8cab1a9f17e27170a6924127e' +
|
|
524
|
+
'19dbb8eba43e54ffff001d12052ce00101000000010000000000000000000000000000000' +
|
|
525
|
+
'000000000000000000000000000000000ffffffff2403089904174b6e434d696e65724251' +
|
|
526
|
+
'521defe5cdcf04ad543ea4eb0101000000165e0000ffffffff0100f90295000000001976a' +
|
|
527
|
+
'9149e8985f82bc4e0f753d0492aa8d11cc39925774088ac00000000';
|
|
528
|
+
|
|
529
|
+
const block = Block.fromHex(blockHex);
|
|
530
|
+
|
|
531
|
+
// Header fields
|
|
532
|
+
console.log('Version:', block.version); // 2
|
|
533
|
+
console.log('Timestamp:', block.timestamp); // 1413391595
|
|
534
|
+
console.log('Bits:', block.bits); // 486604799
|
|
535
|
+
console.log('Nonce:', block.nonce); // 3760981266
|
|
536
|
+
console.log('Previous Hash:', toHex(block.prevHash!));
|
|
537
|
+
console.log('Merkle Root:', toHex(block.merkleRoot!));
|
|
538
|
+
|
|
539
|
+
// Block identification
|
|
540
|
+
console.log('Block ID:', block.getId());
|
|
541
|
+
// '000000006c840ca5ff4dadcfeb4fe14b3d90c144be0fe5b8d06b329b8f8f3855'
|
|
542
|
+
|
|
543
|
+
// Date
|
|
544
|
+
console.log('Date:', block.getUTCDate().toISOString());
|
|
545
|
+
// '2014-10-15T19:33:15.000Z'
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
---
|
|
549
|
+
|
|
550
|
+
### Checking Proof-of-Work
|
|
551
|
+
|
|
552
|
+
```typescript
|
|
553
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
554
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
555
|
+
|
|
556
|
+
const block = Block.fromHex(blockHex);
|
|
557
|
+
|
|
558
|
+
// Compute the target from the bits field
|
|
559
|
+
const target = Block.calculateTarget(block.bits);
|
|
560
|
+
console.log('Target:', toHex(target));
|
|
561
|
+
// '00000000ffff0000000000000000000000000000000000000000000000000000'
|
|
562
|
+
|
|
563
|
+
// Validate proof-of-work
|
|
564
|
+
if (block.checkProofOfWork()) {
|
|
565
|
+
console.log('Valid PoW: block hash is below target');
|
|
566
|
+
} else {
|
|
567
|
+
console.log('Invalid PoW: block hash exceeds target');
|
|
568
|
+
}
|
|
569
|
+
```
|
|
570
|
+
|
|
571
|
+
---
|
|
572
|
+
|
|
573
|
+
### Accessing Transactions
|
|
574
|
+
|
|
575
|
+
```typescript
|
|
576
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
577
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
578
|
+
|
|
579
|
+
const block = Block.fromHex(fullBlockHex);
|
|
580
|
+
|
|
581
|
+
if (block.transactions) {
|
|
582
|
+
console.log('Transaction count:', block.transactions.length);
|
|
583
|
+
|
|
584
|
+
// The first transaction is always the coinbase
|
|
585
|
+
const coinbase = block.transactions[0];
|
|
586
|
+
console.log('Coinbase TX ID:', coinbase.getId());
|
|
587
|
+
|
|
588
|
+
// Iterate over all transactions
|
|
589
|
+
for (const tx of block.transactions) {
|
|
590
|
+
console.log('TX:', tx.getId(), 'Inputs:', tx.ins.length, 'Outputs:', tx.outs.length);
|
|
591
|
+
}
|
|
592
|
+
} else {
|
|
593
|
+
console.log('Header-only block, no transactions available');
|
|
594
|
+
}
|
|
595
|
+
```
|
|
596
|
+
|
|
597
|
+
---
|
|
598
|
+
|
|
599
|
+
### Validating Merkle Roots
|
|
600
|
+
|
|
601
|
+
```typescript
|
|
602
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
603
|
+
import { toHex } from '@btc-vision/bitcoin';
|
|
604
|
+
|
|
605
|
+
const block = Block.fromHex(fullBlockHex);
|
|
606
|
+
|
|
607
|
+
// Recompute and compare the merkle root
|
|
608
|
+
const computed = Block.calculateMerkleRoot(block.transactions!);
|
|
609
|
+
console.log('Header merkle root:', toHex(block.merkleRoot!));
|
|
610
|
+
console.log('Computed merkle root:', toHex(computed));
|
|
611
|
+
|
|
612
|
+
// Validate both merkle root and witness commitment in one call
|
|
613
|
+
console.log('Roots valid:', block.checkTxRoots()); // true
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
---
|
|
617
|
+
|
|
618
|
+
### Round-Trip Serialization
|
|
619
|
+
|
|
620
|
+
```typescript
|
|
621
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
622
|
+
|
|
623
|
+
const original = '020000003385c4b2a3499669...'; // full block hex
|
|
624
|
+
const block = Block.fromHex(original);
|
|
625
|
+
|
|
626
|
+
// Serialize back to hex
|
|
627
|
+
const headerOnly = block.toHex(true); // 80-byte header (160 hex chars)
|
|
628
|
+
const full = block.toHex(); // full block including transactions
|
|
629
|
+
|
|
630
|
+
// The round-trip preserves the original data
|
|
631
|
+
console.log(full === original); // true
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
### Block Weight and Size
|
|
637
|
+
|
|
638
|
+
```typescript
|
|
639
|
+
import { Block } from '@btc-vision/bitcoin';
|
|
640
|
+
|
|
641
|
+
const block = Block.fromHex(fullBlockHex);
|
|
642
|
+
|
|
643
|
+
// Header size is always 80 bytes
|
|
644
|
+
console.log('Header size:', block.byteLength(true)); // 80
|
|
645
|
+
|
|
646
|
+
// Stripped size excludes witness data
|
|
647
|
+
const strippedSize = block.byteLength(false, false);
|
|
648
|
+
console.log('Stripped size:', strippedSize);
|
|
649
|
+
|
|
650
|
+
// Total size includes witness data
|
|
651
|
+
const totalSize = block.byteLength(false, true);
|
|
652
|
+
console.log('Total size:', totalSize);
|
|
653
|
+
|
|
654
|
+
// Weight = stripped_size * 3 + total_size
|
|
655
|
+
console.log('Weight:', block.weight());
|
|
656
|
+
console.log('Matches formula:', block.weight() === strippedSize * 3 + totalSize); // true
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
---
|
|
660
|
+
|
|
661
|
+
## Compact Target Encoding (bits)
|
|
662
|
+
|
|
663
|
+
The `bits` field uses Bitcoin's compact representation of the 256-bit target threshold. The format splits the 4-byte value into an exponent and mantissa:
|
|
664
|
+
|
|
665
|
+
```
|
|
666
|
+
bits = 0xEEMMMMMMM
|
|
667
|
+
|
|
668
|
+
exponent = (bits >> 24) - 3
|
|
669
|
+
mantissa = bits & 0x007fffff
|
|
670
|
+
target[29 - exponent .. 29 - exponent + 2] = mantissa (big-endian)
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
| bits (hex) | Expanded Target |
|
|
674
|
+
|------------|-----------------|
|
|
675
|
+
| `0x1d00ffff` | `00000000ffff0000000000000000000000000000000000000000000000000000` |
|
|
676
|
+
| `0x1b0404cb` | `00000000000404cb000000000000000000000000000000000000000000000000` |
|
|
677
|
+
| `0x1814dd04` | `000000000000000014dd04000000000000000000000000000000000000000000` |
|
|
678
|
+
|
|
679
|
+
A block's proof-of-work is valid when its double-SHA256 hash, interpreted as a 256-bit big-endian number, is less than or equal to the expanded target.
|