feat(chain): Bitcoin merkle inclusion proofs (#112)#119
Merged
Conversation
First piece of the ION fast-sync overlay (epic #111). MerkleProof/VerifyMerkleProof let a node prove a tx is included at a given index in a block whose merkle root it already PoW-verified — without the full block. This is the trustless core: a fast-sync peer is untrusted, but an inclusion proof verified against the node's own header merkle root makes "this anchor exists at block H, index I" impossible to forge (omission is handled separately by trust-then-verify). - internal/chain/merkleproof.go: MerkleProof (sibling branch, bottom-up) + VerifyMerkleProof (fold per index bits, require i==0 residual so an inflated index can't be fabricated), over the classic witness=false txid tree, handling the odd-row last-element duplication and the single-tx (empty branch) case. Documents the 64-byte second-preimage caveat (callers validate the leaf is a real tx). - internal/chain/merkleproof_test.go: round-trips for sizes 1..100 cross-checked against btcd CalcMerkleRoot; rejects tampered branch / wrong index / wrong root / inflated index / wrong tx; bounds-check errors. Mutation-verified (left/right swap). - docs/design/ion-fast-sync-overlay.md: design summary + roadmap. go test -race ./... green. Co-authored-by: Liran Cohen <liranlasvegas@gmail.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First piece of the ION fast-sync overlay (epic #111).
MerkleProof/VerifyMerkleProofprove a transaction is included at a given index in a block whose merkle root the node has already PoW-verified (via its header chain) — without downloading the full block.This is the trustless core of fast-sync: a fast-sync peer is an untrusted source, but an inclusion proof verified against the node's own header merkle root makes the claim "this anchor exists at block H, index I" impossible to forge. (A peer can still omit anchors — handled separately by trust-then-verify in #116.) Same trust philosophy as
--esplora-api: untrusted hint, verified against our own PoW chain, fails closed.What's here
internal/chain/merkleproof.go—MerkleProof(txids, index)→ sibling branch (bottom-up).VerifyMerkleProof(txid, index, branch, root)→ folds per the index bits and requires a zero residual (i==0), so an inflated index can't be fabricated.falsetxid tree (the one the header commits to); handles the odd-row last-element duplication and the single-tx (empty branch) case.internal/chain/merkleproof_test.go— round-trips for sizes1..100cross-checked against btcdCalcMerkleRoot; negative paths (tampered branch / wrong index / wrong root / inflated index / wrong tx); bounds errors. Mutation-verified (a left/right swap fails the round-trip).docs/design/ion-fast-sync-overlay.md— design summary + the 7-issue roadmap.go test -race ./...green (27 packages).Post-Deploy Monitoring & Validation
No additional operational monitoring required: pure, self-contained primitive with no wiring into runtime paths yet — it's consumed by later fast-sync issues (#113+).Part of #111. Closes #112
🤖 Generated with Claude Code