datahaven-xyz/datahaven · error
InvalidAncestryMerkleProof
InvalidAncestryMerkleProof
Error message
InvalidAncestryMerkleProof
What it means
verify_ancestry_proof validates, via verify_merkle_branch, that the provided block_root is a valid Merkle leaf at leaf_index = SLOTS_PER_HISTORICAL_ROOT + (block_slot % SLOTS_PER_HISTORICAL_ROOT) within the state's block_roots_root, at depth config::BLOCK_ROOT_AT_INDEX_DEPTH. A wrong or tampered proof fails with InvalidAncestryMerkleProof.
Solutions
- Rebuild block_root_proof from state.block_roots[block_slot % SLOTS_PER_HISTORICAL_ROOT] using depth config::BLOCK_ROOT_AT_INDEX_DEPTH.
- Ensure the leaf index used is SLOTS_PER_HISTORICAL_ROOT + (block_slot % SLOTS_PER_HISTORICAL_ROOT), matching the pallet's block_roots_root tree layout.
- Confirm the client and pallet agree on SLOTS_PER_HISTORICAL_ROOT and BLOCK_ROOT_AT_INDEX_DEPTH constants.
- Re-fetch the beacon state and regenerate the proof if it was fetched from a different fork/state.
Example fix
// before: index into state.block_roots directly const proof = getBranch(state.blockRoots, blockSlot % SLOTS_PER_HISTORICAL_ROOT); // after: offset into block_roots_root tree and correct depth const idx = SLOTS_PER_HISTORICAL_ROOT + (blockSlot % SLOTS_PER_HISTORICAL_ROOT); const proof = getBranch(state.blockRoots, idx - SLOTS_PER_HISTORICAL_ROOT, BLOCK_ROOT_AT_INDEX_DEPTH); await submitAncestryProof(blockRoot, blockSlot, proof, finalizedRoot);
Defensive patterns
Strategy: validation
Validate before calling
const idx = blockSlot % SLOTS_PER_HISTORICAL_ROOT;
if (proof.blockRootProof.length !== BLOCK_ROOT_AT_INDEX_DEPTH) throw new Error('ancestry proof depth mismatch');
const ok = verifyMerkleBranch(blockRoot, proof.blockRootProof, SLOTS_PER_HISTORICAL_ROOT + idx, BLOCK_ROOT_AT_INDEX_DEPTH, state.blockRootsRoot);
if (!ok) throw new Error('local ancestry verification failed'); Type guard
const hasValidAncestryShape = (p) => Array.isArray(p.blockRootProof) && p.blockRootProof.every(isHex32) && p.blockRootProof.length === BLOCK_ROOT_AT_INDEX_DEPTH;
Try / catch
try {
await submitAncestryProof(blockRoot, blockSlot, proof, finalizedRoot);
} catch (e) {
if (String(e).includes('InvalidAncestryMerkleProof')) refetchStateAndRebuildProof();
else throw e;
} Prevention
- Verify ancestry proofs locally against block_roots_root before submitting.
- Use the correct leaf offset (SLOTS_PER_HISTORICAL_ROOT) when indexing the tree.
- Keep BLOCK_ROOT_AT_INDEX_DEPTH and SLOTS_PER_HISTORICAL_ROOT in sync with pallet config.
- Refetch the beacon state from a trusted source when proofs fail repeatedly.
When it happens
Trigger: Submitting an ancestry proof whose block_root_proof is wrong-length, built for a different slot/block_root, computed with the wrong depth (not BLOCK_ROOT_AT_INDEX_DEPTH), or taken from a different beacon state's block_roots array.
Common situations: Relayer slicing the wrong section of block_roots (leaf index must include the +SLOTS_PER_HISTORICAL_ROOT offset into block_roots_root), spec/config drift between client and pallet constants, or proof corruption during transport/serialization.
Understand the failure class
Background: Checksum mismatch errors: "checksum verification failed", "digest mismatch", "expected vs actual checksum" — what they mean and how to fix them — this error's family across 41 libraries.
Related errors
- InvalidExecutionHeaderProof
- HeaderNotFinalized
- InvalidSyncCommitteeMerkleProof
- InvalidBlockRootsRootMerkleProof
- InvalidHeaderMerkleProof
AI-assisted analysis of datahaven-xyz/datahaven@edcb13dbbc (2026-09-13).
Data as JSON: /api/errors/d09e9ba8d0a48613.
Report an issue: GitHub.
Appendix: source
Thrown at operator/pallets/ethereum-client/src/impls.rs:151
/// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that
/// an execution header is an ancestor of a finalized header (i.e. the blocks are
/// on the same chain).
fn verify_ancestry_proof(
block_root: H256,
block_slot: u64,
block_root_proof: &[H256],
finalized_block_root: H256,
) -> DispatchResult {
let state = <FinalizedBeaconState<T>>::get(finalized_block_root)
.ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;
ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized);
let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64);
let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array;
ensure!(
verify_merkle_branch(
block_root,
block_root_proof,
leaf_index as usize,
config::BLOCK_ROOT_AT_INDEX_DEPTH,
state.block_roots_root
),
Error::<T>::InvalidAncestryMerkleProof
);
Ok(())
}
}
View on GitHub (pinned to edcb13dbbc)