{"record":{"id":"e313232b1c1cfa22","repo":"linera-io/linera-protocol","slug":"equivocationproofsameblock","errorCode":"EquivocationProofSameBlock","errorMessage":"Equivocation proof must reference two different blocks","messagePattern":"Equivocation proof must reference two different blocks","errorType":"validation","errorClass":"ChainError","httpStatus":null,"severity":"error","filePath":"linera-chain/src/justification/mod.rs","lineNumber":490,"sourceCode":"            }\n            EquivocationProof::DoubleVote {\n                validator,\n                round,\n                kind,\n                first_header,\n                first_unlocking_round,\n                first_attested,\n                first_commitment,\n                first_signature,\n                second_header,\n                second_unlocking_round,\n                second_attested,\n                second_commitment,\n                second_signature,\n            } => {\n                let first_block_hash = CryptoHash::new(first_header);\n                let second_block_hash = CryptoHash::new(second_header);\n                ensure!(\n                    first_block_hash != second_block_hash,\n                    ChainError::EquivocationProofSameBlock\n                );\n                // Both votes must concern the same height on the same chain: a validator voting\n                // for different blocks at different heights or on different chains in the same\n                // round number is not double-voting.\n                ensure!(\n                    first_header.chain_id == second_header.chain_id\n                        && first_header.height == second_header.height,\n                    ChainError::EquivocationProofDifferentChainOrHeight\n                );\n                let first = VoteValue(\n                    first_block_hash,\n                    *round,\n                    *kind,\n                    *first_unlocking_round,\n                    *first_attested,\n                    *first_commitment,","sourceCodeStart":472,"sourceCodeEnd":508,"githubUrl":"https://github.com/linera-io/linera-protocol/blob/6c226ddcb332ef55118dc8d0aafbd093d5420899/linera-chain/src/justification/mod.rs#L472-L508","documentation":"Thrown by EquivocationProof::check for a DoubleVote proof when both votes target the same block hash (ChainError::EquivocationProofSameBlock). A double vote requires two votes for different blocks in the same round and kind; two signatures over the identical block are redundant, not contradictory. check computes both header hashes and rejects the proof before verifying signatures.","triggerScenarios":"Constructing EquivocationProof::DoubleVote with first_header and second_header that hash equally — e.g. the same certificate's signature captured twice, or the same vote re-signed under a different unlocking round — and calling check on it.","commonSituations":"Evidence deduplication failures where the same vote enters the pair twice; re-broadcast of an identical vote mistaken for a second vote; proof builders that pair a vote with a retransmission instead of a genuinely different block vote.","solutions":["Deduplicate the validator's votes by (block hash, round, kind) before pairing; a true double vote needs two distinct block hashes.","Assert CryptoHash::new(&first_header) != CryptoHash::new(&second_header) when building the proof.","Treat the failing proof as malformed evidence and drop it.","Check whether the 'second' vote differs only in non-payload metadata — that is a retransmission, not a double vote."],"exampleFix":"// before\nlet proof = DoubleVote { first_header: h.clone(), second_header: h.clone(), .. };\nproof.check(&committee)?; // Err: same block\n\n// after\nlet distinct: BTreeSet<CryptoHash> = votes.iter().map(|v| v.block_hash).collect();\nensure!(distinct.len() >= 2, \"no distinct blocks: no double vote\");\nlet (a, b) = pick_two_distinct(&votes);\nlet proof = DoubleVote { first_header: a, second_header: b, .. };","handlingStrategy":"validation","validationCode":"ensure!(\n    CryptoHash::new(&first_header) != CryptoHash::new(&second_header),\n    \"double vote requires two different blocks\"\n);","typeGuard":null,"tryCatchPattern":"match proof.check(committee) {\n    Err(ChainError::EquivocationProofSameBlock) => {\n        // retransmission, not a double vote: discard\n        Ok(())\n    }\n    other => other,\n}","preventionTips":["Deduplicate a validator's votes by (block_hash, round, kind) before pairing.","Treat identical re-signed votes as retransmissions.","Assert hash inequality in proof builders."],"tags":["consensus","equivocation","double-voting","proof-validation"],"backgroundTag":"invalid-equivocation-proof","analyzedSha":"6c226ddcb332ef55118dc8d0aafbd093d5420899","analyzedAt":"2026-08-22T22:49:09.787Z","schemaVersion":2},"datasetVersion":"2026-08-23T01:17:44.959Z"}