linera-io/linera-protocol · critical · ProofError

receipts root mismatch: computed {receipts_root}, header say

Error message

receipts root mismatch: computed {receipts_root}, header says {}. Receipt encoding may be incorrect.

What it means

A permanent integrity check: the receipts trie rebuilt locally from the RPC's receipts must root exactly at block.header.receipts_root. A mismatch means the canonical EIP-2718 re-encoding of receipts is wrong for at least one receipt in the block (e.g. transaction-type envelope handling, OP deposit type 0x7e) or the RPC returned altered receipts. The generated proof would not verify on-chain, so generation aborts.

Source

Thrown at linera-bridge/src/proof/gen.rs:176

            .collect();

        // 5. Build receipt trie and generate proof
        let receipt_rlp = canonical_receipts
            .iter()
            .find(|(idx, _)| *idx == tx_index)
            .map(|(_, rlp)| rlp.clone())
            .ok_or_else(|| {
                ProofError::Permanent(anyhow::anyhow!(
                    "tx_index {tx_index} not found in block receipts"
                ))
            })?;

        let (receipts_root, proof_nodes) =
            crate::proof::build_receipt_proof(&canonical_receipts, tx_index);

        // Sanity check: computed receipts root matches block header
        if receipts_root != block.header.inner.receipts_root {
            return Err(ProofError::Permanent(anyhow::anyhow!(
                "receipts root mismatch: computed {receipts_root}, \
                 header says {}. Receipt encoding may be incorrect.",
                block.header.inner.receipts_root
            )));
        }

        // Find all DepositInitiated log indices from the canonical receipt
        let logs =
            crate::proof::decode_receipt_logs(&receipt_rlp).map_err(ProofError::Permanent)?;
        let log_indices = crate::proof::find_deposit_log_indices(&logs);
        if log_indices.is_empty() {
            return Err(ProofError::Permanent(anyhow::anyhow!(
                "no DepositInitiated event found in receipt for tx {tx_hash}"
            )));
        }

        Ok(DepositProof {
            block_header_rlp,

View on GitHub (pinned to 6c226ddcb3)

Solutions

  1. Try a different RPC provider to rule out receipt tampering/normalization
  2. Check that the chain matches the client's network type (Optimism/Base with 0x7e deposit receipts)
  3. Compare the failing block's receipts against a reference node and identify which receipt type mis-encodes
  4. Update alloy/op-alloy and linera-bridge — receipt encoding fixes land there
Defensive patterns

Strategy: fallback

Try / catch

Err(ProofError::Permanent(e)) if e.to_string().contains("receipts root mismatch") => {
    // encoding integrity failure: fall back to another provider to rule out receipt tampering;
    // if reproducible, halt processing for this chain and escalate — proofs would not verify
}

Prevention

When it happens

Trigger: A block containing a transaction type whose receipt envelope is encoded differently than this crate's OpReceiptEnvelope path expects; RPC providers returning receipts with adjusted fields; alloy/op-alloy version drift in encoded_2718 behavior.

Common situations: New or unusual transaction types landing on the chain after this code was written; upgraded RPC backends normalizing receipts; running against a non-OP chain while the client assumes Optimism receipt types.

Related errors


AI-assisted analysis of linera-io/linera-protocol@6c226ddcb3 (2026-08-22). Data as JSON: /api/errors/3a650d5d2251d7bd. Report an issue: GitHub.