Chapter 2: A Proof of Inclusion – The Merkle Proof Verifier

Morning light filtered through the venetian blinds of the Verification Lab, casting thin stripes of gold across Jenna’s cluttered desk. The coffee mug from yesterday had been joined by a second one—this one empty—and a stack of printouts covered in handwritten notes and hastily sketched diagrams. Jenna had been up late, running preliminary checks on the Corrupt Node’s block history, and the evidence was already mounting.

Liam arrived at 8:47 AM, slightly out of breath and clutching a paper bag that smelled suspiciously like fresh pastries. He’d slept badly—his mind kept replaying the moment when the verification script had flashed “RESULT: MISMATCH”—but the sight of Jenna hunched over her keyboard, her hair in a messy ponytail and her eyes fixed on the screen, made him feel like he’d arrived at exactly the right place.

“You’re early,” Jenna said without looking up. “Good. We’ve got a lot to do.”

“I brought croissants,” Liam offered, setting the bag on the edge of her desk. “And coffee. I figured you’d need caffeine.”

Jenna finally looked up, and her expression softened into something approaching gratitude. “You figured right. What kind?”

“Black. Two sugars. I guessed.”

“Lucky guess.” She grabbed the cup and took a long sip, then sighed with satisfaction. “Okay. We’re ready to start. Did you bring your transaction details?”

Liam pulled out his tablet and set it on the desk. “Everything’s here. Transaction hash, block height, the proof the validator sent yesterday—all of it.”

“Perfect.” Jenna turned her monitor so Liam could see it clearly. On the screen was her terminal window, already configured with the commands they’d need to request a new proof. “We’re going to request a Merkle Proof from the block’s validator again,” she explained, “but this time, I want you to do it. You need to understand the process from the ground up.”

Liam’s eyes widened. “Me? But I don’t know the commands. I’ll mess it up.”

“You won’t mess it up.” Jenna slid her keyboard across the desk. “I’ll guide you. The first step is understanding what we’re asking for and why.”

She pulled up a new document and typed out the command structure in clear, simple language:

REQUEST_PROOF(
    tx_hash: [the transaction's hash],
    block_height: [the block number],
    validator_id: [the validator that published the block]
)

“Every validator is required by protocol to provide proofs upon request,” Jenna explained, pointing to each field. “It’s part of the network’s transparency guarantee. If a validator refuses or fails to provide a proof, that’s a red flag. If they provide a proof that doesn’t verify—well, that’s what we’re going to catch.”

Liam hesitated, his fingers hovering over the keyboard. “What if they don’t respond? What if they’ve already deleted the data?”

“Archival nodes,” Jenna said. “Remember? They store everything. Even if the validator ghosts us, we can still get the proof from an Archival Node. But we want to see what the validator sends us first. We want to watch them lie in real time.”

She nodded at the keyboard. “Go ahead. Type it in. I’ll walk you through.”

Liam took a breath and typed:

> REQUEST_PROOF(tx_hash: 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069, block_height: 843291, validator_id: 0x3f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8)
> WAITING_FOR_VALIDATOR_RESPONSE...

Liam stared at the blinking cursor. “Now what?”

“Now we wait,” Jenna said. “Validators usually respond within a few minutes. While we wait, let me show you what a Merkle Proof actually looks like.”

She pulled up a new diagram on her second monitor—a binary tree with exactly eight leaves. Each leaf was labeled with a transaction hash: Tx1 through Tx8. Above them, four boxes connected pairs of leaves. Above those, two boxes. And at the very top, one final box labeled “Merkle Root.”

“Remember the tournament bracket analogy from yesterday?” Jenna asked.

Liam nodded. “Each transaction is a player. They hash their way up to a champion.”

“Exactly. Now, let’s say you want to prove that Tx5 is included in the tree.” Jenna used her cursor to highlight the path from Tx5 to the root. “You don’t need to show the whole tree. You only need the hashes of the ‘sibling’ nodes—the nodes that are paired with each step of your path.”

She clicked on each sibling in turn:

  • The sibling of Tx5 was Tx6
  • The sibling of Hash(Tx5+Tx6) was Hash(Tx7+Tx8) — she labeled it “Hash78”
  • The sibling of Hash(Hash56+Hash78) was Hash(Hash12+Hash34) — she labeled it “Hash1234”

“A Merkle proof is like a treasure map,” Jenna said. “It tells you exactly which branches you need to follow to get from your leaf to the root. You don’t need the whole tree—just the branches along your path and the hashes of your ‘sibling’ nodes.”

She drew a new diagram, this time showing only the proof path:

Tx5 → [Tx6] → Hash56
Hash56 → [Hash78] → Hash5678
Hash5678 → [Hash1234] → Merkle Root

Liam studied the diagram, his brow furrowed in concentration. “So the proof is just a list of sibling hashes?”

“Yes,” Jenna said. “Plus your transaction hash and the root you’re trying to verify against. With those pieces, you can recompute the entire path and see if it matches.”

“But why is that secure?” Liam asked. “Couldn’t someone just make up sibling hashes to get any root they want?”

Jenna shook her head. “That’s the genius of hashing. Remember the avalanche effect from yesterday? If you change even one character in the input, the output changes completely. To fake a proof, you’d need to find sibling hashes that—when hashed with your transaction—produce exactly the right intermediate hashes at every step. But hashing is a one-way function. You can’t work backward from the root to find the sibling hashes. You have to know the actual data.”

She pointed to the diagram. “This is why Merkle proofs are mathematically bulletproof. You either have the correct sibling hashes or you don’t. There’s no in-between.”

Liam nodded slowly. “So when the validator sent us that proof yesterday, they were either sending us the right sibling hashes or the wrong ones. And we proved they were wrong.”

“Exactly.” Jenna smiled. “You’re catching on fast.”

Before Liam could respond, the terminal pinged. A message appeared:

> VALIDATOR RESPONSE RECEIVED
> Block Header:
>   Height: 843291
>   Timestamp: 2026-06-20 14:32:18 UTC
>   Merkle Root: 0x8d3a78f9b2c4e5d6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9f0a
>   Previous Block Hash: 0x4b8d7c6e5f4a3b2c1d0e9f8a7b6c5d4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8
> Proof Path:
>   Sibling 1 (Level 1): 0x9f7b3a1c2d4e5f6a7b8c9d0e1f2a3b4c5d6e7f8a9b0c1d2e3f4a5b6c7d8e9
>   Sibling 2 (Level 2): 0x3d8c4e2f1a6b5c4d3e2f1a0b9c8d7e6f5a4b3c2d1e0f9a8b7c6d5e4f3a2b1c
>   Sibling 3 (Level 3): 0x7e5f1a3b2c4d5e6f7a8b9c0d1e2f3a4b5c6d7e8f9a0b1c2d3e4f5a6b7c8d9
>   Sibling 4 (Level 4): 0x2c9d6b5a4e3f2a1b0c9d8e7f6a5b4c3d2e1f0a9b8c7d6e5f4a3b2c1d0e9f8
> Transaction Hash: 0x7f83b1657ff1fc53b92dc18148a1d65dfc2d4b1fa3d677284addd200126d9069

Liam’s jaw dropped. “Wait, that’s it? Four hashes? And the block header? That’s the whole proof?”

“That’s it,” Jenna confirmed. “Four hashes, plus your transaction hash and the root. That’s all you need to verify one transaction in a tree of potentially millions.”

“But how is that possible?” Liam asked, genuinely baffled. “You need four hashes to prove something in a tree with thousands of leaves? That seems like magic.”

“It’s math, not magic.” Jenna pulled up a new document and typed out the formula:

Number of hashes needed = log₂(N)
where N = number of transactions

“See?” she said, pointing to the formula. “For a tree with 8 leaves, you need 3 hashes. For 16 leaves, 4 hashes. For a million leaves—which is roughly what a large block can hold—you need about 20 hashes. Twenty. That’s it.”

“That’s incredible,” Liam breathed. “I always thought proofs were huge—like, gigabytes of data.”

“The beauty of Merkle trees is their efficiency,” Jenna said. “You can compress an entire block of millions of transactions into a single 32-byte root. And a proof—the path to include one transaction—takes only about 640 bytes. That’s smaller than a text message.”

She typed the command to run the verification:

> VERIFY_PROOF(tx_hash: 0x7f83..., proof_path: [0x9f7b..., 0x3d8c..., 0x7e5f..., 0x2c9d...], merkle_root: 0x8d3a...)

“Now watch,” she said, turning to Liam. “I’m going to step through the verification process manually so you can see exactly what’s happening. It’s not just a black box—it’s a series of simple hashing steps.”

She began to write out the steps on her whiteboard:

Step 1: Take your transaction hash → H0 = 0x7f83...
Step 2: Hash H0 with Sibling 1 → H1 = Hash(H0 + 0x9f7b...) = 0x3d8c...
Step 3: Hash H1 with Sibling 2 → H2 = Hash(H1 + 0x3d8c...) = 0x7e5f...
Step 4: Hash H2 with Sibling 3 → H3 = Hash(H2 + 0x7e5f...) = 0x2c9d...
Step 5: Hash H3 with Sibling 4 → H4 = Hash(H3 + 0x2c9d...) = 0x3f7a...
Step 6: Compare H4 to the Merkle Root → 0x3f7a... vs. 0x8d3a... → MISMATCH

Liam stared at the whiteboard, his eyes moving from step to step. “So the proof didn’t work because the final hash—H4—doesn’t match the root?”

“Exactly,” Jenna said. “And you can see why: each step depends on the one before it. If any sibling hash is wrong, the entire chain breaks. It’s like a house of cards—if one card is out of place, the whole thing falls.”

She handed Liam a marker. “Now you try. I’m going to give you a different transaction, and I want you to write out the verification steps yourself.”

Liam took the marker nervously. “What transaction?”

Jenna pulled up a test tree on her screen—a small one with only four leaves. She highlighted Tx2 and showed the proof path:

Transaction: Tx2 (Hash: 0x1234...)
Sibling 1: Tx1 (Hash: 0x5678...)
Sibling 2: Hash(Tx3+Tx4) (Hash: 0x9abc...)
Root: Hash(Hash(Tx1+Tx2) + Hash(Tx3+Tx4))

“Write out the steps to verify Tx2,” Jenna instructed. “Take your time. Use the marker and the whiteboard.”

Liam hesitated, then began to write:

Step 1: Hash(Tx2 + Tx1) = Hash(0x1234 + 0x5678) = 0xdef0...
Step 2: Hash(0xdef0 + 0x9abc) = 0x7890...
Step 3: Compare 0x7890 to root → MATCH (or mismatch)

He stepped back, looking at his work. “I think that’s right. The first step combines Tx2 with its sibling Tx1 to get the parent hash. The second step combines that parent with its sibling—Hash(Tx3+Tx4)—to get the root. Then I compare.”

Jenna smiled. “Perfect. That’s exactly how it works.”

Liam set down the marker, a small grin on his face. “I think I actually understand it now.”

“Good,” Jenna said. “Because now we’re going to run the verification for your actual transaction—but this time, you’re going to watch the script do it step by step.”

She typed a modified command:

> VERIFY_PROOF_VERBOSE(tx_hash: 0x7f83..., proof_path: [0x9f7b..., 0x3d8c..., 0x7e5f..., 0x2c9d...], merkle_root: 0x8d3a...)
> VERBOSE MODE ACTIVATED

The terminal began to fill with text:

> COMPUTING...
> Step 1: H(0x7f83... || 0x9f7b...) = 0x3d8c...
> Step 2: H(0x3d8c... || 0x3d8c...) = 0x7e5f...
> Step 3: H(0x7e5f... || 0x7e5f...) = 0x2c9d...
> Step 4: H(0x2c9d... || 0x2c9d...) = 0x3f7a...
> Step 5: Compare 0x3f7a... to 0x8d3a... 
> RESULT: MISMATCH

The screen flashed red.

Liam stared at the result, the grin fading from his face. “It still doesn’t match.”

“It doesn’t,” Jenna confirmed. “The proof is invalid. The validator sent us a proof that doesn’t verify against their own root. That’s either gross incompetence or deliberate fraud.”

She pulled up another window, showing the same transaction verified against the Archival Node’s root:

> VERIFY_PROOF_VERBOSE(tx_hash: 0x7f83..., proof_path: [0x9f7b..., 0x3d8c..., 0x7e5f..., 0x2c9d...], merkle_root: 0x9a2f...)
> COMPUTING...
> Step 1: H(0x7f83... || 0x9f7b...) = 0x3d8c...
> Step 2: H(0x3d8c... || 0x3d8c...) = 0x7e5f...
> Step 3: H(0x7e5f... || 0x7e5f...) = 0x2c9d...
> Step 4: H(0x2c9d... || 0x2c9d...) = 0x9a2f...
> Step 5: Compare 0x9a2f... to 0x9a2f... 
> RESULT: SUCCESS

The screen flashed green.

“There it is,” Jenna said quietly. “Same proof, same transaction hash, different root. The Archival Node’s root verifies. The validator’s root doesn’t. That’s conclusive evidence of tampering.”

Liam sat back in his chair, his mind racing. “So the validator published a fake root. But why? What do they gain by hiding transactions?”

“They gain the ability to double-spend,” Jenna explained. “When they hide a transaction, the funds remain in the sender’s account—from the perspective of the fake block—so they can spend those funds again. Meanwhile, the real transaction sits in the true block, never acknowledged by the public explorer. The sender thinks their transaction is pending forever, and the validator pockets the double-spent Credits.”

“But the blockchain is supposed to be immutable,” Liam protested. “How can they just change the root?”

“They’re not changing the root—they’re publishing a different root from the start,” Jenna said. “The block they published to the network had a fake Merkle Root. The real root exists only in the Archival Nodes. So the public blockchain shows a version of reality that’s incomplete. It’s like publishing a newspaper with some stories removed.”

Liam’s hands curled into fists. “That’s not just fraud—that’s theft. They stole from me and everyone else whose transactions they hid.”

“It is theft,” Jenna agreed. “And we’re going to prove it.”

She pulled up a new document on her screen—a blank form titled “Fraud Investigation – Preliminary Report.”

“I’m going to document everything we’ve found so far,” she said. “The proof request, the invalid verification, the Archival Node’s confirmation, the discrepancy between the two roots. This will form the foundation of our case.”

Liam watched as she typed:

INVESTIGATION REPORT - PRELIMINARY
Date: 2026-06-22
Investigator: J. Chen
Subject: Transaction 0x7f83... included in block 843291

FINDINGS:
1. Transaction was confirmed by the block explorer on 2026-06-20.
2. Transaction was later removed from the explorer's view.
3. Validator 0x3f8a... published a block header with Merkle Root 0x8d3a...
4. Requested a Merkle Proof from the validator.
5. Proof verification against validator's root resulted in MISMATCH.
6. Archival Node provided a different Merkle Root: 0x9a2f...
7. Proof verification against Archival Node's root resulted in SUCCESS.
8. Conclusion: Validator published a false Merkle Root, hiding Transaction 0x7f83... and potentially others.

NEXT STEPS:
- Audit all blocks produced by Validator 0x3f8a...
- Identify all hidden transactions.
- Document evidence for submission to the Governance Committee.

She saved the document and turned to Liam. “This is the first piece of evidence. But we need more. A single discrepancy could be explained away as a glitch. A pattern of discrepancies is undeniable.”

“You think there are more hidden transactions?” Liam asked.

“I’d bet my reputation on it,” Jenna said flatly. “This validator has been producing blocks for two years. If they’ve been hiding transactions in one block, they’ve been hiding them in dozens—maybe hundreds. We need to audit every single one.”

Liam nodded, determination settling in his chest. “What do we need to do?”

“First, we request a full block header history from the Archival Node network,” Jenna said. “We compare every block the validator produced against the Archival Nodes’ records. Any discrepancy gets flagged. Then we request proofs for every transaction in those flagged blocks to see which specific ones are missing.”

“That sounds like a lot of work,” Liam said.

“It is,” Jenna admitted. “But we have the tools to automate most of it. The script will do the heavy lifting. We just have to interpret the results and build the case.”

She pulled up a new terminal window and began typing a script. “I wrote this a while ago for a different investigation. It’s designed to audit a validator’s entire block history against Archival Node records. I’ll modify it for our use case.”

Liam leaned forward to watch as she typed. The script was complex—loops, conditional statements, API calls—but Jenna navigated it with the confidence of someone who’d been writing code since she was twelve.

“This will take a few hours to run,” she said, hitting enter. “It’s going to query the Archival Nodes for every block this validator ever produced. That’s about a thousand blocks. The network is slow, so we’ll have to be patient.”

She leaned back in her chair and stretched. “In the meantime, let’s talk about what we’ve learned so far.”

Liam pulled up a chair and sat across from her. “Okay. What’s the most important lesson?”

Jenna considered the question. “The most important lesson is that trust in blockchain isn’t blind. You can’t just look at a block explorer and assume everything is correct. The explorer is just a tool—it shows what the validators tell it to show. If a validator lies, the explorer shows the lie.”

She paused, her expression thoughtful. “I’ve been doing this for three years now—verifying Merkle proofs, auditing blocks, catching fraud. And if there’s one thing I’ve learned, it’s that you can never assume the system is perfect. You have to check. You have to verify. Every transaction, every block, every root.”

Liam nodded. “So the blockchain isn’t automatically trustworthy?”

“Not automatically, no,” Jenna said. “It’s designed to be trustworthy—the cryptography is solid, the math is unbreakable. But the humans who operate the validators? They’re not unbreakable. They can be greedy, corrupt, or just plain incompetent. The blockchain is only as honest as the people who maintain it.”

“So how do we fix that?” Liam asked.

“We build better safeguards,” Jenna said. “More Archival Nodes. More verifiers. More transparency. And we teach people like you—users—to be skeptical. To ask for proofs. To verify for themselves instead of trusting the explorer blindly.”

She smiled at him. “You’re already ahead of the curve. Most users would just accept the ‘pending’ status and move on. You came here. You asked for help. You wanted to understand what happened.”

“Because I lost money,” Liam said ruefully.

“Because you cared enough to find out why,” Jenna countered. “That’s the first step to becoming a real verifier.”

She was about to say more when the terminal pinged—a different tone from before, more urgent. A message appeared:

> ARCHIVAL AUDIT IN PROGRESS...
> BLOCK 843291: DISCREPANCY FOUND
> BLOCK 843288: DISCREPANCY FOUND
> BLOCK 843287: DISCREPANCY FOUND
> BLOCK 843285: DISCREPANCY FOUND
> CONTINUING AUDIT...

Liam stared at the screen, his heart pounding. “There are more. Three more blocks—so far—with discrepancies.”

Jenna read the list, her expression darkening. “This is going to be bigger than I thought. Four blocks already, and the audit’s only started. We’re going to find dozens.”

She turned to him, her eyes hard with determination. “This validator has been stealing from users for a long time. And we’re going to stop them.”

“Where do we start?” Liam asked.

“First, we gather the evidence for every single block with a discrepancy,” Jenna said. “Then we request proofs for every hidden transaction. Then we build a case that’s so airtight, the Governance Committee has no choice but to act.”

She reached into her drawer and pulled out a small notebook. She wrote on the cover:

Case File: Validator 0x3f8a...
Audit Date: 2026-06-22
Evidence Log: 1 of ∞

She handed it to Liam. “You’re going to help me document everything. This is your first official assignment as my assistant.”

Liam took the notebook with trembling hands. “What do I write?”

“Write everything,” Jenna said. “Every hash, every root, every time stamp. Write down the steps we took to verify. Write down the discrepancies we found. This is the trail of evidence that will bring a fraudster to justice.”

She pulled up another screen, showing the Archival Node’s data for the next suspicious block. “And while you’re writing, I’m going to show you how to request a proof for a hidden transaction. By the time we’re done, you’ll be able to do this in your sleep.”

Liam opened the notebook and began to write, his pen moving across the page with careful precision. The terminal continued to ping—block after block flagged with discrepancies—and Jenna worked through each one methodically.

Hours passed. The sun climbed higher in the sky, then began its slow descent toward the horizon. The lab grew warm with the heat of the afternoon, but neither of them noticed. They were too focused on the evidence unfolding on the screen.

By late evening, they had a preliminary count:

24 blocks with Merkle Root discrepancies
67 hidden transactions identified
Total hidden value: approximately 25,000 Credits

And the audit was only halfway complete.

Liam set down his pen, his hand cramping from hours of writing. “This is huge,” he said. “This is going to shake the entire network.”

“It will,” Jenna agreed. “And that’s exactly what needs to happen. The network has been too trusting for too long. This fraud was allowed to continue because no one was checking closely enough.”

She stretched her arms over her head, her joints popping. “But we’re checking now. And by the time we’re done, every validator in the network will know: if you try to hide transactions, someone will catch you. The math doesn’t lie.”

She turned to Liam, a hint of a smile on her face. “We’re not just catching a fraudster, Liam. We’re sending a message. And that message is going to change how the whole network operates.”

Liam looked at the notebook in his hands—filled with evidence, hashes, and notes—and felt a surge of pride. He was part of something important. Something that mattered.

“The validator says one thing,” Jenna said quietly, looking at the screen where the Archival Node’s data was still flowing in, “but the math says another. Time to get a second opinion. Actually—time to get a third, and a fourth, and every Archival Node in the network.”

She typed a new command:

> REQUEST_HISTORICAL_AUDIT(validator_id: 0x3f8a..., archive_depth: ALL)
> BROADCASTING TO ALL ARCHIVAL NODES...

“There,” she said. “Now we’ll get the full picture. Every block this validator ever produced, from the genesis block to today. And we’ll compare every single root.”

She looked at Liam, her eyes gleaming. “When the Archival Nodes respond, we’ll have the truth. All of it.”

Liam nodded, a sense of awe washing over him. “What happens then?”

“Then we expose them,” Jenna said simply. “We take the evidence to the Governance Committee. We show them the patterns, the missing transactions, the stolen funds. And we watch the system do what it was designed to do: punish the corrupt and protect the innocent.”

She glanced at the clock—it was nearly 9 PM. “But that’s a battle for tomorrow. Right now, we need rest. The Archival Nodes are going to take hours to respond—they’re distributed all over the world, and some of them are slow.”

Liam closed his notebook and stood up. “I don’t know how you do this,” he said. “The constant vigilance, the endless verification, the pressure to be right every time.”

Jenna smiled faintly. “It’s not about being right. It’s about being thorough. The truth doesn’t care if I’m right or wrong—it’s just there. My job is to find it and present it.”

She paused, her expression softening. “And it helps to have a partner. Someone who cares as much as I do.”

Liam felt a warmth spread through his chest. “I’ll be here tomorrow. First thing.”

“Good,” Jenna said. “Because we’re going to need all the help we can get.”

She watched him gather his things and head for the door. Just before he left, she called out:

“Hey, Liam. Thanks for the croissants.”

He grinned. “I’ll bring more tomorrow. With real coffee, not the instant stuff.”

“Now you’re talking,” Jenna laughed.

Liam stepped out of the lab, the notebook tucked under his arm, and walked into the cool night air. Above him, the stars were just beginning to emerge, tiny pinpricks of light in a vast sky. He thought about all the transactions hidden in the dark, all the users who didn’t even know they’d been cheated, and all the work that lay ahead.

But for the first time since his transaction had disappeared, he felt something he hadn’t expected: hope.

Because the truth—the mathematical, undeniable truth—was on his side. And Jenna was right. The math never lied.

Table of contents:
Introduction
Chapter 1: The Immutable Ledger
Chapter 2: A Proof of Inclusion
Chapter 3: The Merkle Root <<<<<< NEXT
Chapter 4: The Missing Leaf
Chapter 5: The Invalid Proof
Chapter 6: The Tampered Branch
Chapter 7: The Forensic Audit
Chapter 8: The Historical Root
Chapter 9: The Dual Verification
Chapter 10: Trust, But Always Verify

Loading



Dear reader, love our creation? Support us moving forward