{"record":{"id":"dee3a6555265965c","repo":"linera-io/linera-protocol","slug":"block-header-payload-extends-past-available-data","errorCode":null,"errorMessage":"block header payload extends past available data","messagePattern":"block header payload extends past available data","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-bridge/src/proof/mod.rs","lineNumber":309,"sourceCode":"        let (root, proof) = super::build_receipt_proof(receipts, target_tx_index);\n        (root, proof.into_iter().map(Into::into).collect())\n    }\n}\n\n/// Decodes an RLP-encoded Ethereum block header, returning `(block_hash, receipts_root)`.\n///\n/// The block hash is `keccak256(header_rlp)`. The receipts root is field index 5\n/// in the RLP list.\npub fn decode_block_header(header_rlp: &[u8]) -> Result<(B256, B256)> {\n    let block_hash = keccak256(header_rlp);\n\n    let mut data = header_rlp;\n    let list_header =\n        alloy_rlp::Header::decode(&mut data).map_err(|e| anyhow!(\"invalid RLP header: {e}\"))?;\n    ensure!(list_header.list, \"block header must be an RLP list\");\n\n    // Limit reads to the header's declared payload.\n    ensure!(\n        data.len() >= list_header.payload_length,\n        \"block header payload extends past available data\"\n    );\n    let mut data = &data[..list_header.payload_length];\n\n    // Skip first 5 fields: parentHash, ommersHash, beneficiary, stateRoot, transactionsRoot\n    for i in 0..5 {\n        skip_rlp_item(&mut data).map_err(|e| anyhow!(\"failed to skip header field {i}: {e}\"))?;\n    }\n\n    // Field index 5: receiptsRoot (B256)\n    let receipts_root = <B256 as alloy_rlp::Decodable>::decode(&mut data)\n        .map_err(|e| anyhow!(\"failed to decode receipts_root: {e}\"))?;\n\n    Ok((block_hash, receipts_root))\n}\n\n/// Maximum number of MPT proof nodes accepted.","sourceCodeStart":291,"sourceCodeEnd":327,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-bridge/src/proof/mod.rs#L291-L327","documentation":"After decoding the outer list header, decode_block_header checks that the remaining bytes cover the declared payload_length. alloy_rlp::Header only strips the prefix, not the payload, so if the buffer is truncated relative to the declared size this ensure! fires. It is a deliberate bounds check that prevents out-of-bounds slicing at `&data[..payload_length]` and DoS via oversized length claims.","triggerScenarios":"Passing a header that was cut short (partial read from RPC, truncated proof, split message framing); malformed input where the RLP length prefix declares more bytes than actually follow.","commonSituations":"Fixed-size buffer truncation upstream; an L2/non-standard chain emitting headers with extra fields after receiptsRoot such that an intermediate parser sliced too early; network transport delivering partial frames.","solutions":["Log the input length vs declared payload_length to confirm truncation, then fix the upstream producer/transport","Fetch headers with full bodies from a trusted RPC and pass bytes through unmodified","For cross-chain support of non-standard headers (e.g. OP-stack extra fields), verify against the chain's actual header spec before parsing"],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match decode_block_header(header_rlp) {\n    Ok(v) => v,\n    Err(e) if e.to_string().contains(\"extends past available data\") => {\n        // truncated or malformed input: re-fetch rather than retry\n        anyhow::bail!(\"truncated block header ({} bytes); refetch from RPC\", header_rlp.len())\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Use length-prefixed framing or complete-response checks when transporting RLP blobs","Never slice header bytes manually before decoding; pass the full buffer","Log input length alongside parse errors to spot truncation immediately"],"tags":["ethereum","rlp","block-header","truncated-data","bridge","rust"],"backgroundTag":"rlp-decoding-failed","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}