{"record":{"id":"d09e9ba8d0a48613","repo":"datahaven-xyz/datahaven","slug":"invalidancestrymerkleproof","errorCode":"InvalidAncestryMerkleProof","errorMessage":"InvalidAncestryMerkleProof","messagePattern":"InvalidAncestryMerkleProof","errorType":"error_code","errorClass":null,"httpStatus":null,"severity":"error","filePath":"operator/pallets/ethereum-client/src/impls.rs","lineNumber":151,"sourceCode":"\n    /// Verify that `block_root` is an ancestor of `finalized_block_root` Used to prove that\n    /// an execution header is an ancestor of a finalized header (i.e. the blocks are\n    /// on the same chain).\n    fn verify_ancestry_proof(\n        block_root: H256,\n        block_slot: u64,\n        block_root_proof: &[H256],\n        finalized_block_root: H256,\n    ) -> DispatchResult {\n        let state = <FinalizedBeaconState<T>>::get(finalized_block_root)\n            .ok_or(Error::<T>::ExpectedFinalizedHeaderNotStored)?;\n\n        ensure!(block_slot < state.slot, Error::<T>::HeaderNotFinalized);\n\n        let index_in_array = block_slot % (SLOTS_PER_HISTORICAL_ROOT as u64);\n        let leaf_index = (SLOTS_PER_HISTORICAL_ROOT as u64) + index_in_array;\n\n        ensure!(\n            verify_merkle_branch(\n                block_root,\n                block_root_proof,\n                leaf_index as usize,\n                config::BLOCK_ROOT_AT_INDEX_DEPTH,\n                state.block_roots_root\n            ),\n            Error::<T>::InvalidAncestryMerkleProof\n        );\n\n        Ok(())\n    }\n}\n","sourceCodeStart":133,"sourceCodeEnd":165,"githubUrl":"https://github.com/datahaven-xyz/datahaven/blob/edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec/operator/pallets/ethereum-client/src/impls.rs#L133-L165","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","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."],"exampleFix":"// before: index into state.block_roots directly\nconst proof = getBranch(state.blockRoots, blockSlot % SLOTS_PER_HISTORICAL_ROOT);\n// after: offset into block_roots_root tree and correct depth\nconst idx = SLOTS_PER_HISTORICAL_ROOT + (blockSlot % SLOTS_PER_HISTORICAL_ROOT);\nconst proof = getBranch(state.blockRoots, idx - SLOTS_PER_HISTORICAL_ROOT, BLOCK_ROOT_AT_INDEX_DEPTH);\nawait submitAncestryProof(blockRoot, blockSlot, proof, finalizedRoot);","handlingStrategy":"validation","validationCode":"const idx = blockSlot % SLOTS_PER_HISTORICAL_ROOT;\nif (proof.blockRootProof.length !== BLOCK_ROOT_AT_INDEX_DEPTH) throw new Error('ancestry proof depth mismatch');\nconst ok = verifyMerkleBranch(blockRoot, proof.blockRootProof, SLOTS_PER_HISTORICAL_ROOT + idx, BLOCK_ROOT_AT_INDEX_DEPTH, state.blockRootsRoot);\nif (!ok) throw new Error('local ancestry verification failed');","typeGuard":"const hasValidAncestryShape = (p) => Array.isArray(p.blockRootProof) && p.blockRootProof.every(isHex32) && p.blockRootProof.length === BLOCK_ROOT_AT_INDEX_DEPTH;","tryCatchPattern":"try {\n  await submitAncestryProof(blockRoot, blockSlot, proof, finalizedRoot);\n} catch (e) {\n  if (String(e).includes('InvalidAncestryMerkleProof')) refetchStateAndRebuildProof();\n  else throw e;\n}","preventionTips":["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."],"tags":["merkle-proof","ssz","beacon","light-client"],"backgroundTag":"checksum-mismatch","analyzedSha":"edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec","analyzedAt":"2026-09-13T19:19:32.206Z","contentChangedAt":"2026-09-13T19:19:32.206Z","schemaVersion":2},"datasetVersion":"2026-09-16T09:17:16.951Z"}