BlockchainJun 30, 20264 min read

SPV Verification Flow: How Transactions, Merkle Proofs, and Block Headers Work Together

This article systematically explains the full SPV (Simplified Payment Verification) process in the BSV blockchain from a technical editor’s perspective: from transaction verification and txid computation, through Merkle proof derivation of the Merkle root, to block header chain confirmation of the block’s validity. It also contrasts SPV with block explorer queries, helping developers understand how to verify on-chain transactions without downloading full blocks.

Ethan Lin

Ethan Lin

technical_editor

Share

Conclusion First

SPV (Simplified Payment Verification), proposed in the Bitcoin white paper, enables users to verify that a transaction is included in a valid proof-of-work chain without downloading full blocks. By retaining only block headers and using Merkle proofs, clients can independently confirm inclusion. In the BSV tech stack, SPV forms the foundation of lightweight verification protocols coordinating wallets, applications, miners, and header services.

This article breaks down the five core steps of SPV verification in process order, along with tooling support in BSV and common misconceptions.

SPV Verification Flow: How Transactions, Merkle Proofs, and Block Headers Work Together article cover

Step 1: Verify the Transaction Itself

SPV verification does not start with Merkle proofs; it begins with validating the transaction’s content:

  • Confirm the transaction format (serialized structure) is correct.
  • Verify that all referenced previous outputs exist and are unspent.
  • Check that unlocking scripts satisfy corresponding locking scripts.
  • Ensure total input value is greater than or equal to total output value (no inflation).
  • Optionally, verify the fee is reasonable.
  • Validate signatures.

If the transaction itself is invalid, no proof can make it acceptable. In BEEF (Buffer for Encrypted Envelopes and Fragments) scenarios, validation must also traverse the parent transaction chain until reaching a transaction anchored by a Merkle proof.

Step 2: Compute the txid

Hash the serialized transaction with double SHA-256:

Code
1raw transaction → double SHA-256 → txid

This txid is the starting point for the Merkle proof. Any change to the transaction alters the txid, invalidating previous proofs.

Step 3: Compute the Merkle Root from the Merkle Proof

Using the txid and a Merkle proof (often encoded in BUMP format), the verifier hashes upward:

Code
1txid + sibling hash 1 → parent hash
2parent hash + sibling hash 2 → higher parent hash
3...
4→ Merkle root

BUMP-aware SDKs automatically handle offsets, duplicates, and txid markers, producing the Merkle root.

Step 4: Compare Against the Block Header’s Merkle Root

Block headers contain the Merkle root of all transactions in that block (merkleRoot field). The verifier compares:

Code
1computed root == header.merkleRoot

If equal, the transaction is proven to be included in that block’s Merkle tree; otherwise the proof is invalid.

Step 5: Validate the Block Header Belongs to the Proof-of-Work Chain

Proving inclusion in a block is not enough; the block itself must be part of a valid chain:

  • Check the block header hash meets the difficulty target (proof-of-work).
  • Ensure the header correctly references the previous block (prevBlockHash).
  • Verify cumulative chainwork follows network rules.
  • Confirm the block is on the accepted longest valid chain (requires chain view context).

SPV clients can maintain their own header chains or rely on Block Headers Services or chain trackers for verified headers. In the BSV TypeScript SDK, MerklePath.verify(txid, chainTracker) exemplifies this division: the Merkle path computes the root, and the chain tracker confirms the associated header is valid.

Expressing SPV Verification with the SDK

Example verifying a single txid Merkle path:

TypeScript
1import { MerklePath, WhatsOnChain } from '@bsv/sdk'
2
3const txid = '...'
4const merklePath = MerklePath.fromHex(bumpHex)
5const chainTracker = new WhatsOnChain('main')
6
7const ok = await merklePath.verify(txid, chainTracker)

Using BEEF to validate a complete package with transaction dependencies and BUMPs:

TypeScript
1import { Beef, WhatsOnChain } from '@bsv/sdk'
2
3const beef = Beef.fromString(beefHex, 'hex')
4const chainTracker = new WhatsOnChain('main')
5
6const ok = await beef.verify(chainTracker)

MerklePath.verify() focuses on a single txid’s Merkle path, while Beef.verify() validates the entire transaction dependency graph and associated proofs.

Essential Difference: SPV vs. Block Explorer Queries

Many assume searching a txid on a block explorer is SPV; it is not.

  • Querying: relies on a service to return a result—you simply trust it.
  • Verification: obtains provable data (Merkle proof, block headers) and performs client-side (or trusted component) checks; the service is only a data provider.

SPV is designed so that services provide data, and clients verify it—distinct from simple API lookups.

SPV Security Model

SPV is not trustless magic; it depends on proof-of-work and economic incentives. Core assumptions:

  • The majority of network hash power follows the rules.
  • Forging a confirmed transaction requires redoing the work of that block and all subsequent blocks, making it prohibitively expensive.
  • SPV clients do not validate every network transaction, so they cannot defend against all attacks (e.g., full nodes can reject invalid transactions that SPV cannot proactively detect).

For common payments and application transactions, SPV strikes a practical balance between resource cost and verification capability.

Position in the BSV Tech Stack

BSV’s scaling architecture emphasizes role separation:

  • Miners: process full transactions and assemble blocks.
  • Wallets: hold user-relevant transactions, proofs, and keys.
  • Applications: only verify data and state relevant to their business.
  • Block Headers Services: provide block header verification interfaces or full-chain header data.
  • Overlay Services: index protocol-specific data, aiding SPV clients in locating needed proofs.

SPV is the foundational protocol for lightweight trust verification among these roles.

Common Misconceptions Corrected

  • SPV is not just looking up a txid; it requires verifying Merkle proofs and block headers.
  • Merkle proofs do not guarantee script validity; the transaction itself must be independently verified.
  • Block explorer links are not SPV proofs; they are query results, not verifiable proof data.
  • SPV does not require downloading full blocks, but still needs block headers and Merkle proofs.
  • SPV does not endorse accepting unconfirmed transactions without risk; unconfirmed transactions must be assessed per business risk.

Summary: SPV Verification Flow at a Glance

TEXT
1Transaction raw tx
2 → compute txid
3
4txid + Merkle proof / BUMP
5 → compute Merkle root
6
7Merkle root + block header
8 → prove txid belongs to that block
9
10block header + header chain
11 → prove that block belongs to the proof-of-work chain
12
13Transaction script and parent transaction validation
14 → prove the transaction itself is valid by rules

These five steps together answer: “How can I know this transaction is on-chain without downloading full blocks?”

Reference Resources

Recommended articles