diff --git a/zebra-consensus/src/checkpoint.rs b/zebra-consensus/src/checkpoint.rs index 8c2c7190e..2ae92a7c2 100644 --- a/zebra-consensus/src/checkpoint.rs +++ b/zebra-consensus/src/checkpoint.rs @@ -438,16 +438,25 @@ where } } - /// Check that the block height and Merkle root are valid. + /// Check that the block height, proof of work, and Merkle root are valid. + /// + /// ## Security + /// + /// Checking the proof of work makes resource exhaustion attacks harder to + /// carry out, because malicious blocks require a valid proof of work. /// /// Checking the Merkle root ensures that the block hash binds the block /// contents. To prevent malleability (CVE-2012-2459), we also need to check /// whether the transaction hashes are unique. fn check_block(&self, block: &Block) -> Result { - let block_height = block + let hash = block.hash(); + let height = block .coinbase_height() - .ok_or(VerifyCheckpointError::CoinbaseHeight { hash: block.hash() })?; - self.check_height(block_height)?; + .ok_or(VerifyCheckpointError::CoinbaseHeight { hash })?; + self.check_height(height)?; + + crate::block::check::difficulty_is_valid(&block.header, self.network, &height, &hash)?; + crate::block::check::equihash_solution_is_valid(&block.header)?; let transaction_hashes = block .transactions @@ -457,7 +466,7 @@ where crate::block::check::merkle_root_validity(&block, &transaction_hashes)?; - Ok(block_height) + Ok(height) } /// Queue `block` for verification, and return the `Receiver` for the @@ -842,6 +851,12 @@ impl From for VerifyCheckpointError { } } +impl From for VerifyCheckpointError { + fn from(err: equihash::Error) -> VerifyCheckpointError { + VerifyCheckpointError::VerifyBlock(err.into()) + } +} + /// The CheckpointVerifier service implementation. /// /// After verification, the block futures resolve to their hashes.