diff --git a/primitives/block/src/block_proof.rs b/primitives/block/src/block_proof.rs index 3eed49025f..1cdb48a1d5 100644 --- a/primitives/block/src/block_proof.rs +++ b/primitives/block/src/block_proof.rs @@ -79,9 +79,9 @@ impl BlockInclusionProof { election_head.block_number(), ); - // The election head might already have an interlink or prev_election_head link to the target + // An empty proof is only valid if the election head already references the target directly. if hops.is_empty() { - return true; + return Self::references_block(election_head, target); } // Check that the proof contains all needed hops @@ -129,4 +129,15 @@ impl BlockInclusionProof { } true } + + fn references_block(block: &MacroBlock, target: &MacroBlock) -> bool { + let target_hash = target.hash(); + + block.header.parent_election_hash == target_hash + || block + .header + .interlink + .as_ref() + .is_some_and(|interlink| interlink.contains(&target_hash)) + } } diff --git a/primitives/block/tests/block_proof.rs b/primitives/block/tests/block_proof.rs index cb04e4bd1c..72dd5ae83e 100644 --- a/primitives/block/tests/block_proof.rs +++ b/primitives/block/tests/block_proof.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use nimiq_block::{BlockInclusionProof, MacroBlock, MacroHeader}; +use nimiq_hash::Hash; use nimiq_primitives::policy::Policy; #[test] @@ -85,6 +86,18 @@ fn test_is_block_proven() { let block_proof = BlockInclusionProof { proof: vec![] }; assert!(block_proof.is_block_proven(&blocks[&10], &blocks[&9])); + // Current election head: 10, target: forged 9. Claimed proof [] + let mut forged_parent_target = blocks[&9].clone(); + forged_parent_target.header.history_root = "forged-parent-target".hash(); + let block_proof = BlockInclusionProof { proof: vec![] }; + assert!(!block_proof.is_block_proven(&blocks[&10], &forged_parent_target)); + + // Current election head: 10, target: forged 8. Claimed proof [] + let mut forged_interlink_target = blocks[&8].clone(); + forged_interlink_target.header.history_root = "forged-interlink-target".hash(); + let block_proof = BlockInclusionProof { proof: vec![] }; + assert!(!block_proof.is_block_proven(&blocks[&10], &forged_interlink_target)); + // Current election head: 22, target: 1. Claimed proof [17 (wrong), 8, 4, 2] let block_proof = BlockInclusionProof { proof: vec![