SPV Validation
Overview
Basic Merkle Proof Validation
import { MerkleProof, Transaction, Hash } from '@bsv/sdk'
/**
* Basic Merkle Proof Validator
*
* Validate merkle proofs for SPV
*/
class BasicMerkleValidator {
/**
* Validate merkle proof for a transaction
*/
validateMerkleProof(
txid: string,
merkleProof: MerkleProofData,
merkleRoot: string
): ValidationResult {
try {
console.log('Validating merkle proof...')
console.log('TXID:', txid)
console.log('Merkle root:', merkleRoot)
// Start with transaction hash
let hash = Hash.sha256(Hash.sha256(Buffer.from(txid, 'hex')))
let index = merkleProof.index
console.log(`Climbing merkle tree (${merkleProof.nodes.length} levels)`)
// Climb the merkle tree
for (let i = 0; i < merkleProof.nodes.length; i++) {
const sibling = merkleProof.nodes[i]
const siblingBuffer = Buffer.from(sibling, 'hex')
// Determine if current node is on right or left
const isRightNode = index % 2 === 1
console.log(`Level ${i}: index=${index}, isRight=${isRightNode}`)
// Concatenate in correct order
const combined = isRightNode
? Buffer.concat([siblingBuffer, hash])
: Buffer.concat([hash, siblingBuffer])
// Hash the concatenation
hash = Hash.sha256(Hash.sha256(combined))
index = Math.floor(index / 2)
}
const calculatedRoot = hash.toString('hex')
const valid = calculatedRoot === merkleRoot
console.log('Calculated root:', calculatedRoot)
console.log('Expected root:', merkleRoot)
console.log('Valid:', valid)
return {
valid,
calculatedRoot,
expectedRoot: merkleRoot,
error: valid ? undefined : 'Merkle root mismatch'
}
} catch (error) {
console.error('Validation failed:', error.message)
return {
valid: false,
error: error.message
}
}
}
/**
* Validate merkle proof with block header
*/
validateWithBlockHeader(
txid: string,
merkleProof: MerkleProofData,
blockHeader: BlockHeaderData
): ValidationResult {
try {
console.log('Validating with block header')
// Validate merkle proof
const proofResult = this.validateMerkleProof(
txid,
merkleProof,
blockHeader.merkleRoot
)
if (!proofResult.valid) {
return proofResult
}
// Additional header validation could go here
console.log('Block header validation passed')
return {
valid: true,
blockHash: blockHeader.hash,
blockHeight: blockHeader.height
}
} catch (error) {
return {
valid: false,
error: error.message
}
}
}
/**
* Validate multiple proofs in batch
*/
batchValidate(
proofs: ProofToValidate[]
): BatchValidationResult[] {
console.log(`Batch validating ${proofs.length} merkle proofs`)
const results: BatchValidationResult[] = []
for (let i = 0; i < proofs.length; i++) {
const proof = proofs[i]
try {
const result = this.validateMerkleProof(
proof.txid,
proof.merkleProof,
proof.merkleRoot
)
results.push({
index: i,
txid: proof.txid,
valid: result.valid,
error: result.error
})
} catch (error) {
results.push({
index: i,
txid: proof.txid,
valid: false,
error: error.message
})
}
}
const validCount = results.filter(r => r.valid).length
console.log(`Batch validation complete: ${validCount}/${proofs.length} valid`)
return results
}
/**
* Estimate proof size for a given block
*/
estimateProofSize(txCount: number): number {
// Merkle tree depth
const depth = Math.ceil(Math.log2(txCount))
// Each node is 32 bytes
const proofSize = depth * 32
// Add overhead for index and metadata
const overhead = 8
return proofSize + overhead
}
}
interface MerkleProofData {
index: number
nodes: string[]
}
interface BlockHeaderData {
hash: string
merkleRoot: string
height?: number
}
interface ValidationResult {
valid: boolean
calculatedRoot?: string
expectedRoot?: string
blockHash?: string
blockHeight?: number
error?: string
}
interface ProofToValidate {
txid: string
merkleProof: MerkleProofData
merkleRoot: string
}
interface BatchValidationResult {
index: number
txid: string
valid: boolean
error?: string
}
/**
* Usage Example
*/
async function basicMerkleValidationExample() {
const validator = new BasicMerkleValidator()
console.log('=== Basic Merkle Proof Validation ===')
// Validate merkle proof
const txid = 'transaction-id...'
const merkleProof: MerkleProofData = {
index: 2,
nodes: [
'sibling1...',
'parent-sibling...',
'grandparent-sibling...'
]
}
const merkleRoot = 'merkle-root...'
const result = validator.validateMerkleProof(txid, merkleProof, merkleRoot)
if (result.valid) {
console.log('Proof is valid!')
} else {
console.log('Proof is invalid:', result.error)
}
// Estimate proof size
const proofSize = validator.estimateProofSize(10000)
console.log('Estimated proof size for 10,000 txs:', proofSize, 'bytes')
}Advanced SPV Validation
SPV Validation Service
Related Examples
See Also
Last updated
