diff --git a/crates/blockchain-tree/src/block_indices.rs b/crates/blockchain-tree/src/block_indices.rs index 3fe3c5e0bf6f..4cd73b68b34a 100644 --- a/crates/blockchain-tree/src/block_indices.rs +++ b/crates/blockchain-tree/src/block_indices.rs @@ -337,11 +337,24 @@ impl BlockIndices { lose_chains } - /// get canonical hash + /// Returns the block hash of the canonical block with the given number. pub fn canonical_hash(&self, block_number: BlockNumber) -> Option { self.canonical_chain.get(&block_number).cloned() } + /// Returns the block number of the canonical block with the given hash. + pub fn canonical_number(&self, block_hash: BlockHash) -> Option { + self.canonical_chain.iter().find_map( + |(number, hash)| { + if *hash == block_hash { + Some(*number) + } else { + None + } + }, + ) + } + /// get canonical tip pub fn canonical_tip(&self) -> BlockNumHash { self.canonical_chain diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 749aab5f306e..fc7842c71c42 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -5,7 +5,10 @@ use crate::{ }; use reth_db::{cursor::DbCursorRO, database::Database, tables, transaction::DbTx}; use reth_interfaces::{ - blockchain_tree::BlockStatus, consensus::Consensus, executor::Error as ExecError, Error, + blockchain_tree::BlockStatus, + consensus::{Consensus, ConsensusError}, + executor::Error as ExecError, + Error, }; use reth_primitives::{ BlockHash, BlockNumHash, BlockNumber, ForkBlock, Hardfork, SealedBlock, SealedBlockWithSenders, @@ -309,8 +312,10 @@ impl BlockchainTree return status } + let canonical_parent_block = self.block_indices.canonical_hash(parent.number); + // if not found, check if the parent can be found inside canonical chain. - if Some(parent.hash) == self.block_indices.canonical_hash(parent.number) { + if Some(parent.hash) == canonical_parent_block { // create new chain that points to that block //return self.fork_canonical_chain(block.clone()); // TODO save pending block to database @@ -354,6 +359,20 @@ impl BlockchainTree return Ok(block_status) } + // this is another check to ensure that if the block points to a canonical block its block + // is valid + if let Some(canonical_parent_number) = + self.block_indices.canonical_number(block.parent_hash) + { + // we found the parent block in canonical chain + if canonical_parent_number != parent.number { + return Err(Error::Consensus(ConsensusError::ParentBlockNumberMismatch { + parent_block_number: canonical_parent_number, + block_number: block.number, + })) + } + } + // if there is a parent inside the buffer, validate against it. if let Some(buffered_parent) = self.buffered_blocks.block(parent) { self.externals.consensus.validate_header_against_parent(&block, buffered_parent)? @@ -361,7 +380,6 @@ impl BlockchainTree // insert block inside unconnected block buffer. Delaying it execution. self.buffered_blocks.insert_block(block); - Ok(BlockStatus::Disconnected) } diff --git a/crates/rpc/rpc-types/src/eth/engine/payload.rs b/crates/rpc/rpc-types/src/eth/engine/payload.rs index 35b050f1083f..bda7526e9047 100644 --- a/crates/rpc/rpc-types/src/eth/engine/payload.rs +++ b/crates/rpc/rpc-types/src/eth/engine/payload.rs @@ -399,6 +399,9 @@ pub enum PayloadValidationError { /// Thrown when a forkchoice update's head links to a previously rejected payload. #[error("links to previously rejected block")] LinksToRejectedPayload, + /// Thrown when a new payload contains a wrong block number. + #[error("invalid block number")] + InvalidBlockNumber, } #[cfg(test)]