{"record":{"id":"3d4476032d88c7b0","repo":"datahaven-xyz/datahaven","slug":"invalidblockrootsrootmerkleproof","errorCode":"InvalidBlockRootsRootMerkleProof","errorMessage":"InvalidBlockRootsRootMerkleProof","messagePattern":"InvalidBlockRootsRootMerkleProof","errorType":"error_code","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"operator/pallets/ethereum-client/src/lib.rs","lineNumber":285,"sourceCode":"                    &update.current_sync_committee_branch,\n                    subtree_index(sync_committee_gindex),\n                    generalized_index_length(sync_committee_gindex),\n                    update.header.state_root\n                ),\n                Error::<T>::InvalidSyncCommitteeMerkleProof\n            );\n\n            let header_root: H256 = update\n                .header\n                .hash_tree_root()\n                .map_err(|_| Error::<T>::HeaderHashTreeRootFailed)?;\n\n            // This is used for ancestry proofs in ExecutionHeader updates. This verifies the\n            // BeaconState: the beacon state root is the tree root; the `block_roots` hash is the\n            // tree leaf.\n            let block_roots_gindex =\n                Self::block_roots_gindex_at_slot(update.header.slot, fork_versions);\n            ensure!(\n                verify_merkle_branch(\n                    update.block_roots_root,\n                    &update.block_roots_branch,\n                    subtree_index(block_roots_gindex),\n                    generalized_index_length(block_roots_gindex),\n                    update.header.state_root\n                ),\n                Error::<T>::InvalidBlockRootsRootMerkleProof\n            );\n\n            let sync_committee_prepared: SyncCommitteePrepared = (&update.current_sync_committee)\n                .try_into()\n                .map_err(|_| <Error<T>>::BLSPreparePublicKeysFailed)?;\n            <CurrentSyncCommittee<T>>::set(sync_committee_prepared);\n            <NextSyncCommittee<T>>::kill();\n            InitialCheckpointRoot::<T>::set(header_root);\n\n            Self::store_validators_root(update.validators_root);","sourceCodeStart":267,"sourceCodeEnd":303,"githubUrl":"https://github.com/datahaven-xyz/datahaven/blob/edcb13dbbcd3c29489eaa2480a6f60ee4cb1f3ec/operator/pallets/ethereum-client/src/lib.rs#L267-L303","documentation":"The `block_roots_branch` in the update fails to prove `block_roots_root` is part of the beacon state at `update.header.state_root`. This proof (via `process_checkpoint_update`, using the fork-dependent `block_roots` generalized index) is required so later execution-header updates can do ancestry proofs. A failed verification means the block-roots root or branch does not correspond to the update's beacon state.","triggerScenarios":"Submitting an `Update` where `verify_merkle_branch(update.block_roots_root, update.block_roots_branch, ...)` against `update.header.state_root` fails — wrong branch, wrong root, or state_root/branch from different states.","commonSituations":"Relayer computed the block_roots root itself instead of reading the state's field; branch taken at a different slot than the header; fork-specific gindex mismatch; relaying updates across a hard fork boundary with outdated fork version config.","solutions":["Fetch `block_roots_root` and its branch from a beacon node at exactly `update.header.slot` with the correct `block_roots` generalized index.","Ensure `block_roots_gindex_at_slot` in `T::ForkVersions` reflects the fork at the header slot.","Regenerate the whole update from a single consistent beacon state snapshot rather than mixing fields from different slots.","Verify chain identity (testnet vs mainnet beacon chain)."],"exampleFix":"// before\n let branch = state.get_branch(\"block_roots\")?; // fetched at state.slot\n// after\n let branch = consensus_client.get_block_roots_branch(header.slot)?; // same slot as header.state_root","handlingStrategy":"validation","validationCode":"const ok = verifyMerkleBranch(update.blockRootsRoot, update.blockRootsBranch, subtreeIndex(blockRootsGindex), generalizedIndexLength(blockRootsGindex), update.header.stateRoot);\nif (!ok) throw new Error('block roots proof invalid');","typeGuard":null,"tryCatchPattern":"try { await submit(update); } catch (e) { if (e.includes('InvalidBlockRootsRootMerkleProof')) { refetchProofsAt(headerSlot); } else throw e; }","preventionTips":["Always fetch branch and root at the header's slot","Keep ForkVersions gindex table up to date","Mirror verify_merkle_branch checks locally pre-submit"],"tags":["substrate","merkle-proof","beacon-consensus","ssz"],"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"}