Bitcoin block parsing, validation, and Merkle root calculation with support for witness commitments, proof-of-work validation, and block serialization for all Bitcoin block formats.
Core block functionality with comprehensive methods for block creation, parsing, and validation.
class Block {
/** Block version */
version: number;
/** Previous block hash */
prevHash?: Buffer;
/** Merkle root of transactions */
merkleRoot?: Buffer;
/** Block timestamp (Unix timestamp) */
timestamp: number;
/** Witness commitment (BIP 141) */
witnessCommit?: Buffer;
/** Difficulty bits */
bits: number;
/** Proof-of-work nonce */
nonce: number;
/** Block transactions */
transactions?: Transaction[];
}Create blocks from various sources including buffers and hex strings.
/**
* Create block from buffer
* @param buffer - Raw block buffer
* @returns Parsed Block object
*/
static fromBuffer(buffer: Buffer): Block;
/**
* Create block from hex string
* @param hex - Hex-encoded block string
* @returns Parsed Block object
*/
static fromHex(hex: string): Block;Usage Examples:
import { Block } from 'bitcoinjs-lib';
// Parse block from hex
const blockHex = '01000000...';
const block = Block.fromHex(blockHex);
console.log('Block version:', block.version);
console.log('Previous hash:', block.prevHash?.toString('hex'));
console.log('Timestamp:', new Date(block.timestamp * 1000));
console.log('Transaction count:', block.transactions?.length);
// Parse from buffer
const blockBuffer = Buffer.from(blockHex, 'hex');
const block2 = Block.fromBuffer(blockBuffer);Utility methods for block-related calculations.
/**
* Calculate target from difficulty bits
* @param bits - Difficulty bits from block header
* @returns Target as 32-byte buffer
*/
static calculateTarget(bits: number): Buffer;
/**
* Calculate Merkle root from transactions
* @param transactions - Array of transactions
* @param forWitness - Calculate witness commitment Merkle root
* @returns Merkle root as 32-byte buffer
*/
static calculateMerkleRoot(transactions: Transaction[], forWitness?: boolean): Buffer;Usage Examples:
import { Block, Transaction } from 'bitcoinjs-lib';
// Calculate target from difficulty bits
const difficultyBits = 0x1d00ffff; // Example difficulty
const target = Block.calculateTarget(difficultyBits);
console.log('Target:', target.toString('hex'));
// Calculate Merkle root
const transactions = [
Transaction.fromHex('01000000...'),
Transaction.fromHex('01000000...'),
// ... more transactions
];
const merkleRoot = Block.calculateMerkleRoot(transactions);
console.log('Merkle root:', merkleRoot.toString('hex'));
// Calculate witness Merkle root
const witnessMerkleRoot = Block.calculateMerkleRoot(transactions, true);
console.log('Witness Merkle root:', witnessMerkleRoot.toString('hex'));Retrieve block properties and metadata.
/**
* Get witness commitment from coinbase transaction
* @returns Witness commitment or null if not present
*/
getWitnessCommit(): Buffer | null;
/**
* Check if block has witness commitment
* @returns True if block has witness commitment
*/
hasWitnessCommit(): boolean;
/**
* Check if block has witness data in any transaction
* @returns True if any transaction has witness data
*/
hasWitness(): boolean;
/**
* Calculate block weight (BIP 141)
* @returns Block weight in weight units
*/
weight(): number;
/**
* Calculate block byte length
* @param headersOnly - Calculate only header length
* @param allowWitness - Include witness data in calculation
* @returns Byte length
*/
byteLength(headersOnly?: boolean, allowWitness?: boolean): number;
/**
* Get block timestamp as Date object
* @returns Block timestamp as Date
*/
getUTCDate(): Date;Usage Examples:
const block = Block.fromHex('01000000...');
// Check witness support
console.log('Has witness commit:', block.hasWitnessCommit());
console.log('Has witness data:', block.hasWitness());
// Get witness commitment
const witnessCommit = block.getWitnessCommit();
if (witnessCommit) {
console.log('Witness commitment:', witnessCommit.toString('hex'));
}
// Size and weight calculations
console.log('Block weight:', block.weight());
console.log('Block size:', block.byteLength());
console.log('Header only size:', block.byteLength(true));
// Timestamp
console.log('Block time:', block.getUTCDate().toISOString());Generate block hashes and identifiers.
/**
* Get block hash (double SHA256 of header)
* @returns Block hash as 32-byte buffer
*/
getHash(): Buffer;
/**
* Get block ID (hex-encoded reversed hash)
* @returns Block ID string
*/
getId(): string;Usage Examples:
const block = Block.fromHex('01000000...');
// Get block hash and ID
const blockHash = block.getHash();
const blockId = block.getId();
console.log('Block hash:', blockHash.toString('hex'));
console.log('Block ID:', blockId);
// Verify hash matches expected format
console.log('Hash is 32 bytes:', blockHash.length === 32);
console.log('ID is 64 char hex:', blockId.length === 64);Convert blocks to various formats for storage and transmission.
/**
* Serialize block to buffer
* @param headersOnly - Serialize only block header
* @returns Serialized block buffer
*/
toBuffer(headersOnly?: boolean): Buffer;
/**
* Serialize block to hex string
* @param headersOnly - Serialize only block header
* @returns Hex-encoded block
*/
toHex(headersOnly?: boolean): string;Usage Examples:
const block = Block.fromHex('01000000...');
// Serialize full block
const fullBlockHex = block.toHex();
const fullBlockBuffer = block.toBuffer();
// Serialize header only (80 bytes)
const headerHex = block.toHex(true);
const headerBuffer = block.toBuffer(true);
console.log('Full block size:', fullBlockBuffer.length);
console.log('Header size:', headerBuffer.length); // Should be 80
console.log('Header hex:', headerHex);Validate block integrity and proof-of-work.
/**
* Check transaction Merkle roots
* @returns True if Merkle roots are valid
*/
checkTxRoots(): boolean;
/**
* Check proof-of-work
* @returns True if proof-of-work is valid
*/
checkProofOfWork(): boolean;Usage Examples:
const block = Block.fromHex('01000000...');
// Validate block
const validMerkleRoots = block.checkTxRoots();
const validProofOfWork = block.checkProofOfWork();
console.log('Valid Merkle roots:', validMerkleRoots);
console.log('Valid proof-of-work:', validProofOfWork);
if (validMerkleRoots && validProofOfWork) {
console.log('Block is valid');
} else {
console.log('Block validation failed');
}
// Check individual components
if (!validMerkleRoots) {
console.log('Merkle root mismatch');
console.log('Calculated:', Block.calculateMerkleRoot(block.transactions!).toString('hex'));
console.log('In header:', block.merkleRoot?.toString('hex'));
}
if (!validProofOfWork) {
console.log('Proof-of-work insufficient');
const target = Block.calculateTarget(block.bits);
const hash = block.getHash();
console.log('Block hash:', hash.toString('hex'));
console.log('Target:', target.toString('hex'));
}Analyze block header components:
import { Block } from 'bitcoinjs-lib';
function analyzeBlockHeader(block: Block): void {
console.log('=== Block Header Analysis ===');
console.log('Version:', block.version);
console.log('Previous hash:', block.prevHash?.toString('hex'));
console.log('Merkle root:', block.merkleRoot?.toString('hex'));
console.log('Timestamp:', block.timestamp, '(' + block.getUTCDate().toISOString() + ')');
console.log('Bits:', '0x' + block.bits.toString(16));
console.log('Nonce:', block.nonce);
// Calculate difficulty
const target = Block.calculateTarget(block.bits);
const maxTarget = Block.calculateTarget(0x1d00ffff); // Bitcoin's max target
const difficulty = parseInt(maxTarget.toString('hex'), 16) / parseInt(target.toString('hex'), 16);
console.log('Difficulty:', difficulty.toFixed(2));
// Check proof-of-work
const blockHash = block.getHash();
const hashBigInt = BigInt('0x' + blockHash.toString('hex'));
const targetBigInt = BigInt('0x' + target.toString('hex'));
console.log('Hash < Target:', hashBigInt < targetBigInt);
}
const block = Block.fromHex('01000000...');
analyzeBlockHeader(block);Work with Merkle trees for transaction verification:
import { Block, crypto } from 'bitcoinjs-lib';
function buildMerkleTree(hashes: Buffer[]): Buffer[] {
if (hashes.length === 0) return [];
if (hashes.length === 1) return hashes;
const tree = [...hashes];
let level = hashes;
while (level.length > 1) {
const nextLevel: Buffer[] = [];
for (let i = 0; i < level.length; i += 2) {
const left = level[i];
const right = level[i + 1] || left; // Duplicate last hash if odd number
const combined = Buffer.concat([left, right]);
const hash = crypto.hash256(combined);
nextLevel.push(hash);
tree.push(hash);
}
level = nextLevel;
}
return tree;
}
// Build Merkle tree from transaction hashes
const txHashes = block.transactions!.map(tx => tx.getHash());
const merkleTree = buildMerkleTree(txHashes);
const merkleRoot = merkleTree[merkleTree.length - 1];
console.log('Calculated Merkle root:', merkleRoot.toString('hex'));
console.log('Block Merkle root:', block.merkleRoot?.toString('hex'));
console.log('Roots match:', merkleRoot.equals(block.merkleRoot!));Work with the Bitcoin genesis block:
import { Block } from 'bitcoinjs-lib';
// Bitcoin genesis block
const genesisBlockHex = '0100000000000000000000000000000000000000000000000000000000000000000000003ba3edfd7a7b12b27ac72c3e67768f617fc81bc3888a51323a9fb8aa4b1e5e4a29ab5f49ffff001d1dac2b7c';
const genesisBlock = Block.fromHex(genesisBlockHex);
console.log('Genesis block ID:', genesisBlock.getId());
// Expected: '000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f'
console.log('Genesis timestamp:', genesisBlock.getUTCDate().toISOString());
// Expected: '2009-01-03T18:15:05.000Z'
console.log('Genesis is valid:', genesisBlock.checkProofOfWork());Verify witness commitments in SegWit blocks:
import { Block, crypto } from 'bitcoinjs-lib';
function verifyWitnessCommitment(block: Block): boolean {
if (!block.hasWitnessCommit() || !block.transactions) {
return false;
}
// Calculate witness Merkle root
const witnessMerkleRoot = Block.calculateMerkleRoot(block.transactions, true);
// Get witness commitment from coinbase
const witnessCommit = block.getWitnessCommit();
if (!witnessCommit) return false;
// Witness commitment should be hash256(witnessMerkleRoot + witnessReservedValue)
// For simplicity, we'll just check if witness commitment exists and format is correct
return witnessCommit.length === 32;
}
const segwitBlock = Block.fromHex('20000000...'); // SegWit block
console.log('Valid witness commitment:', verifyWitnessCommitment(segwitBlock));interface Transaction {
getHash(forWitness?: boolean): Buffer;
hasWitnesses(): boolean;
// ... other transaction properties
}