From 8103e8973920f495eb30c672968d9201e8ed0d47 Mon Sep 17 00:00:00 2001 From: teor Date: Thu, 11 Mar 2021 12:11:19 +1000 Subject: [PATCH] Check proof-of-work in the CheckpointVerifier These checks make some resource exhaustion attacks harder to carry out, because the malicious blocks need a valid proof-of-work. --- zebra-consensus/src/checkpoint.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/zebra-consensus/src/checkpoint.rs b/zebra-consensus/src/checkpoint.rs index 8c2c7190..2ae92a7c 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.