{"record":{"id":"f201484c6665cfb6","repo":"linera-io/linera-protocol","slug":"topics-payload-extends-past-log-boundary","errorCode":null,"errorMessage":"topics payload extends past log boundary","messagePattern":"topics payload extends past log boundary","errorType":"validation","errorClass":null,"httpStatus":null,"severity":"error","filePath":"linera-bridge/src/proof/mod.rs","lineNumber":569,"sourceCode":"        alloy_rlp::Header::decode(data).map_err(|e| anyhow!(\"invalid log RLP: {e}\"))?;\n    ensure!(log_header.list, \"log must be an RLP list\");\n    ensure!(\n        data.len() >= log_header.payload_length,\n        \"log payload extends past available data\"\n    );\n\n    // Limit reads to the declared payload boundary.\n    let mut log_data_buf = &data[..log_header.payload_length];\n    *data = &data[log_header.payload_length..];\n\n    let address = <Address as alloy_rlp::Decodable>::decode(&mut log_data_buf)\n        .map_err(|e| anyhow!(\"invalid log address: {e}\"))?;\n\n    // Decode topics list\n    let topics_header = alloy_rlp::Header::decode(&mut log_data_buf)\n        .map_err(|e| anyhow!(\"invalid topics list RLP: {e}\"))?;\n    ensure!(topics_header.list, \"topics must be an RLP list\");\n    ensure!(\n        log_data_buf.len() >= topics_header.payload_length,\n        \"topics payload extends past log boundary\"\n    );\n\n    let mut topics_data = &log_data_buf[..topics_header.payload_length];\n    log_data_buf = &log_data_buf[topics_header.payload_length..];\n\n    let mut topics = Vec::new();\n    while !topics_data.is_empty() {\n        let topic = <B256 as alloy_rlp::Decodable>::decode(&mut topics_data)\n            .map_err(|e| anyhow!(\"invalid topic: {e}\"))?;\n        topics.push(topic);\n    }\n\n    // Decode log data (byte string)\n    let data_header = alloy_rlp::Header::decode(&mut log_data_buf)\n        .map_err(|e| anyhow!(\"invalid log data RLP: {e}\"))?;\n    ensure!(","sourceCodeStart":551,"sourceCodeEnd":587,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-bridge/src/proof/mod.rs#L551-L587","documentation":"decode_log bounds every field read by the log's declared payload boundary. At linera-bridge/src/proof/mod.rs:569 it verifies the topics list's declared payload_length fits inside the remaining log payload before slicing topics_data. Failure means the topics header claims more bytes than the log's own boundary allows — an inconsistent inner length inside a truncated or malformed log.","triggerScenarios":"A log whose topics-list length prefix exceeds the space left after the address field; corrupt trie node bytes where one length field was edited but others were not; fixtures that enlarge topics without growing the outer log payload length.","commonSituations":"Partial writes or truncation of proof nodes; hand-maintained test RLP where the topics count changed but both the topics-list header and the log-list header were not updated; provider serving a garbled node.","solutions":["Rebuild the receipt/log via proper RLP encoding (alloy_rlp Encodable) so all nested length prefixes are computed, not hand-written.","Verify the proof against receipts_root; discard and re-fetch nodes that fail structural checks.","Add a structural sanity pass: outer log payload >= address item + topics header + topics payload before decoding.","Log the three numbers (log payload_length, topics payload_length, remaining bytes) at failure to pinpoint which length is wrong."],"exampleFix":null,"handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"match decode_receipt_logs(receipt_rlp) {\n    Ok(logs) => logs,\n    Err(e) if e.to_string().contains(\"topics payload extends past log boundary\") => {\n        tracing::warn!(error = %e, \"inconsistent nested lengths; rejecting node\");\n        Vec::new()\n    }\n    Err(e) => return Err(e),\n}","preventionTips":["Always build nested RLP with library encoders so inner lengths agree with outer boundaries.","After editing any encoded structure, re-encode end to end rather than splicing bytes.","Treat nested-length inconsistencies as corruption until proof verification says otherwise."],"tags":["rlp","ethereum","decoding","bounds-check","rust","linera-bridge"],"backgroundTag":"rlp-decoding-error","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}