diff --git a/crates/blockchain-tree/src/blockchain_tree.rs b/crates/blockchain-tree/src/blockchain_tree.rs index 799e7e343..08f588cd2 100644 --- a/crates/blockchain-tree/src/blockchain_tree.rs +++ b/crates/blockchain-tree/src/blockchain_tree.rs @@ -1259,8 +1259,8 @@ mod tests { use super::*; use assert_matches::assert_matches; use linked_hash_set::LinkedHashSet; + use reth_consensus::test_utils::TestConsensus; use reth_db::{tables, test_utils::TempDatabase, transaction::DbTxMut, DatabaseEnv}; - use reth_interfaces::test_utils::TestConsensus; use reth_node_ethereum::EthEvmConfig; #[cfg(not(feature = "optimism"))] use reth_primitives::proofs::calculate_receipt_root; diff --git a/crates/consensus/beacon/Cargo.toml b/crates/consensus/beacon/Cargo.toml index 0fed12597..9a7841447 100644 --- a/crates/consensus/beacon/Cargo.toml +++ b/crates/consensus/beacon/Cargo.toml @@ -45,6 +45,7 @@ schnellru.workspace = true # reth reth-payload-builder = { workspace = true, features = ["test-utils"] } reth-primitives = { workspace = true, features = ["test-utils"] } +reth-consensus = { workspace = true, features = ["test-utils"] } reth-interfaces = { workspace = true, features = ["test-utils"] } reth-stages = { workspace = true, features = ["test-utils"] } reth-blockchain-tree = { workspace = true, features = ["test-utils"] } @@ -57,7 +58,6 @@ reth-downloaders.workspace = true reth-evm-ethereum.workspace = true reth-ethereum-engine-primitives.workspace = true reth-config.workspace = true -reth-consensus.workspace = true assert_matches.workspace = true diff --git a/crates/consensus/beacon/src/engine/test_utils.rs b/crates/consensus/beacon/src/engine/test_utils.rs index 297269975..ff36e871b 100644 --- a/crates/consensus/beacon/src/engine/test_utils.rs +++ b/crates/consensus/beacon/src/engine/test_utils.rs @@ -7,7 +7,7 @@ use reth_blockchain_tree::{ config::BlockchainTreeConfig, externals::TreeExternals, BlockchainTree, ShareableBlockchainTree, }; use reth_config::config::EtlConfig; -use reth_consensus::Consensus; +use reth_consensus::{test_utils::TestConsensus, Consensus}; use reth_db::{test_utils::TempDatabase, DatabaseEnv as DE}; use reth_downloaders::{ bodies::bodies::BodiesDownloaderBuilder, @@ -19,7 +19,7 @@ use reth_interfaces::{ executor::BlockExecutionError, p2p::{bodies::client::BodiesClient, either::EitherDownloader, headers::client::HeadersClient}, sync::NoopSyncStateUpdater, - test_utils::{NoopFullBlockClient, TestConsensus}, + test_utils::NoopFullBlockClient, }; use reth_payload_builder::test_utils::spawn_test_payload_service; use reth_primitives::{BlockNumber, ChainSpec, FinishedExExHeight, PruneModes, B256}; diff --git a/crates/consensus/consensus/Cargo.toml b/crates/consensus/consensus/Cargo.toml index 6e4fc7ee9..308a16f20 100644 --- a/crates/consensus/consensus/Cargo.toml +++ b/crates/consensus/consensus/Cargo.toml @@ -15,4 +15,7 @@ reth-primitives.workspace = true # misc auto_impl.workspace = true -thiserror.workspace = true \ No newline at end of file +thiserror.workspace = true + +[features] +test-utils = [] \ No newline at end of file diff --git a/crates/consensus/consensus/src/lib.rs b/crates/consensus/consensus/src/lib.rs index ab2453b74..b434272a4 100644 --- a/crates/consensus/consensus/src/lib.rs +++ b/crates/consensus/consensus/src/lib.rs @@ -14,6 +14,10 @@ use reth_primitives::{ }; use std::fmt::Debug; +#[cfg(any(test, feature = "test-utils"))] +/// test helpers for mocking consensus +pub mod test_utils; + /// Consensus is a protocol that chooses canonical chain. #[auto_impl::auto_impl(&, Arc)] pub trait Consensus: Debug + Send + Sync { diff --git a/crates/consensus/consensus/src/test_utils.rs b/crates/consensus/consensus/src/test_utils.rs new file mode 100644 index 000000000..a8655661b --- /dev/null +++ b/crates/consensus/consensus/src/test_utils.rs @@ -0,0 +1,70 @@ +use crate::{Consensus, ConsensusError}; +use reth_primitives::{Header, SealedBlock, SealedHeader, U256}; +use std::sync::atomic::{AtomicBool, Ordering}; + +/// Consensus engine implementation for testing +#[derive(Debug)] +pub struct TestConsensus { + /// Flag whether the header validation should purposefully fail + fail_validation: AtomicBool, +} + +impl Default for TestConsensus { + fn default() -> Self { + Self { fail_validation: AtomicBool::new(false) } + } +} + +impl TestConsensus { + /// Get the failed validation flag. + pub fn fail_validation(&self) -> bool { + self.fail_validation.load(Ordering::SeqCst) + } + + /// Update the validation flag. + pub fn set_fail_validation(&self, val: bool) { + self.fail_validation.store(val, Ordering::SeqCst) + } +} + +impl Consensus for TestConsensus { + fn validate_header(&self, _header: &SealedHeader) -> Result<(), ConsensusError> { + if self.fail_validation() { + Err(ConsensusError::BaseFeeMissing) + } else { + Ok(()) + } + } + + fn validate_header_against_parent( + &self, + _header: &SealedHeader, + _parent: &SealedHeader, + ) -> Result<(), ConsensusError> { + if self.fail_validation() { + Err(ConsensusError::BaseFeeMissing) + } else { + Ok(()) + } + } + + fn validate_header_with_total_difficulty( + &self, + _header: &Header, + _total_difficulty: U256, + ) -> Result<(), ConsensusError> { + if self.fail_validation() { + Err(ConsensusError::BaseFeeMissing) + } else { + Ok(()) + } + } + + fn validate_block(&self, _block: &SealedBlock) -> Result<(), ConsensusError> { + if self.fail_validation() { + Err(ConsensusError::BaseFeeMissing) + } else { + Ok(()) + } + } +} diff --git a/crates/interfaces/Cargo.toml b/crates/interfaces/Cargo.toml index 70ac2f942..6c066593b 100644 --- a/crates/interfaces/Cargo.toml +++ b/crates/interfaces/Cargo.toml @@ -34,12 +34,14 @@ parking_lot = { workspace = true, optional = true } rand = { workspace = true, optional = true } [dev-dependencies] +reth-consensus = { workspace = true, features = ["test-utils"] } + parking_lot.workspace = true rand.workspace = true tokio = { workspace = true, features = ["full"] } secp256k1 = { workspace = true, features = ["alloc", "recovery", "rand"] } [features] -test-utils = ["secp256k1", "rand", "parking_lot"] +test-utils = ["reth-consensus/test-utils", "secp256k1", "rand", "parking_lot"] cli = ["clap"] optimism = ["reth-eth-wire-types/optimism"] diff --git a/crates/interfaces/src/p2p/full_block.rs b/crates/interfaces/src/p2p/full_block.rs index cb4c66543..6cf3f2c81 100644 --- a/crates/interfaces/src/p2p/full_block.rs +++ b/crates/interfaces/src/p2p/full_block.rs @@ -36,7 +36,7 @@ impl FullBlockClient { /// Returns a client with Test consensus #[cfg(any(test, feature = "test-utils"))] pub fn test_client(client: Client) -> Self { - Self::new(client, Arc::new(crate::test_utils::TestConsensus::default())) + Self::new(client, Arc::new(reth_consensus::test_utils::TestConsensus::default())) } } diff --git a/crates/interfaces/src/test_utils/headers.rs b/crates/interfaces/src/test_utils/headers.rs index c0da9ff16..304f394c8 100644 --- a/crates/interfaces/src/test_utils/headers.rs +++ b/crates/interfaces/src/test_utils/headers.rs @@ -1,5 +1,18 @@ //! Testing support for headers related interfaces. +use std::{ + fmt, + pin::Pin, + sync::{ + atomic::{AtomicU64, Ordering}, + Arc, + }, + task::{ready, Context, Poll}, +}; + +use futures::{Future, FutureExt, Stream, StreamExt}; +use tokio::sync::Mutex; + use crate::p2p::{ download::DownloadClient, error::{DownloadError, DownloadResult, PeerRequestResult, RequestError}, @@ -10,21 +23,8 @@ use crate::p2p::{ }, priority::Priority, }; -use futures::{Future, FutureExt, Stream, StreamExt}; -use reth_consensus::{Consensus, ConsensusError}; -use reth_primitives::{ - Header, HeadersDirection, PeerId, SealedBlock, SealedHeader, WithPeerId, U256, -}; -use std::{ - fmt, - pin::Pin, - sync::{ - atomic::{AtomicBool, AtomicU64, Ordering}, - Arc, - }, - task::{ready, Context, Poll}, -}; -use tokio::sync::Mutex; +use reth_consensus::{test_utils::TestConsensus, Consensus}; +use reth_primitives::{Header, HeadersDirection, PeerId, SealedHeader, WithPeerId}; /// A test downloader which just returns the values that have been pushed to it. #[derive(Debug)] @@ -243,70 +243,3 @@ impl HeadersClient for TestHeadersClient { }) } } - -/// Consensus engine implementation for testing -#[derive(Debug)] -pub struct TestConsensus { - /// Flag whether the header validation should purposefully fail - fail_validation: AtomicBool, -} - -impl Default for TestConsensus { - fn default() -> Self { - Self { fail_validation: AtomicBool::new(false) } - } -} - -impl TestConsensus { - /// Get the failed validation flag. - pub fn fail_validation(&self) -> bool { - self.fail_validation.load(Ordering::SeqCst) - } - - /// Update the validation flag. - pub fn set_fail_validation(&self, val: bool) { - self.fail_validation.store(val, Ordering::SeqCst) - } -} - -impl Consensus for TestConsensus { - fn validate_header(&self, _header: &SealedHeader) -> Result<(), ConsensusError> { - if self.fail_validation() { - Err(ConsensusError::BaseFeeMissing) - } else { - Ok(()) - } - } - - fn validate_header_against_parent( - &self, - _header: &SealedHeader, - _parent: &SealedHeader, - ) -> Result<(), ConsensusError> { - if self.fail_validation() { - Err(ConsensusError::BaseFeeMissing) - } else { - Ok(()) - } - } - - fn validate_header_with_total_difficulty( - &self, - _header: &Header, - _total_difficulty: U256, - ) -> Result<(), ConsensusError> { - if self.fail_validation() { - Err(ConsensusError::BaseFeeMissing) - } else { - Ok(()) - } - } - - fn validate_block(&self, _block: &SealedBlock) -> Result<(), ConsensusError> { - if self.fail_validation() { - Err(ConsensusError::BaseFeeMissing) - } else { - Ok(()) - } - } -} diff --git a/crates/net/downloaders/Cargo.toml b/crates/net/downloaders/Cargo.toml index b5de192f2..f1f14c85c 100644 --- a/crates/net/downloaders/Cargo.toml +++ b/crates/net/downloaders/Cargo.toml @@ -45,6 +45,7 @@ itertools.workspace = true [dev-dependencies] reth-db = { workspace = true, features = ["test-utils"] } +reth-consensus = { workspace = true, features = ["test-utils"] } reth-interfaces = { workspace = true, features = ["test-utils"] } reth-provider = { workspace = true, features = ["test-utils"] } reth-tracing.workspace = true @@ -58,5 +59,5 @@ rand.workspace = true tempfile.workspace = true [features] -test-utils = ["dep:tempfile", "reth-db/test-utils", "reth-interfaces/test-utils"] +test-utils = ["dep:tempfile", "reth-db/test-utils", "reth-consensus/test-utils", "reth-interfaces/test-utils"] diff --git a/crates/net/downloaders/src/bodies/bodies.rs b/crates/net/downloaders/src/bodies/bodies.rs index 28b43359e..985c545e9 100644 --- a/crates/net/downloaders/src/bodies/bodies.rs +++ b/crates/net/downloaders/src/bodies/bodies.rs @@ -604,8 +604,9 @@ mod tests { test_utils::{generate_bodies, TestBodiesClient}, }; use assert_matches::assert_matches; + use reth_consensus::test_utils::TestConsensus; use reth_db::test_utils::{create_test_rw_db, create_test_static_files_dir}; - use reth_interfaces::test_utils::{generators, generators::random_block_range, TestConsensus}; + use reth_interfaces::test_utils::{generators, generators::random_block_range}; use reth_primitives::{BlockBody, B256, MAINNET}; use reth_provider::ProviderFactory; use std::collections::HashMap; diff --git a/crates/net/downloaders/src/bodies/request.rs b/crates/net/downloaders/src/bodies/request.rs index 1a87928d5..d6da2444c 100644 --- a/crates/net/downloaders/src/bodies/request.rs +++ b/crates/net/downloaders/src/bodies/request.rs @@ -250,7 +250,8 @@ mod tests { bodies::test_utils::zip_blocks, test_utils::{generate_bodies, TestBodiesClient}, }; - use reth_interfaces::test_utils::{generators, generators::random_header_range, TestConsensus}; + use reth_consensus::test_utils::TestConsensus; + use reth_interfaces::test_utils::{generators, generators::random_header_range}; /// Check if future returns empty bodies without dispatching any requests. #[tokio::test] diff --git a/crates/net/downloaders/src/bodies/task.rs b/crates/net/downloaders/src/bodies/task.rs index 2d9bb3f96..f8815bcb0 100644 --- a/crates/net/downloaders/src/bodies/task.rs +++ b/crates/net/downloaders/src/bodies/task.rs @@ -170,7 +170,8 @@ mod tests { test_utils::{generate_bodies, TestBodiesClient}, }; use assert_matches::assert_matches; - use reth_interfaces::{p2p::error::DownloadError, test_utils::TestConsensus}; + use reth_consensus::test_utils::TestConsensus; + use reth_interfaces::p2p::error::DownloadError; use reth_provider::test_utils::create_test_provider_factory; use std::sync::Arc; diff --git a/crates/net/downloaders/src/file_client.rs b/crates/net/downloaders/src/file_client.rs index 7d29cc577..b5b7aceae 100644 --- a/crates/net/downloaders/src/file_client.rs +++ b/crates/net/downloaders/src/file_client.rs @@ -434,12 +434,10 @@ mod tests { use assert_matches::assert_matches; use futures_util::stream::StreamExt; use rand::Rng; - use reth_interfaces::{ - p2p::{ - bodies::downloader::BodyDownloader, - headers::downloader::{HeaderDownloader, SyncTarget}, - }, - test_utils::TestConsensus, + use reth_consensus::test_utils::TestConsensus; + use reth_interfaces::p2p::{ + bodies::downloader::BodyDownloader, + headers::downloader::{HeaderDownloader, SyncTarget}, }; use reth_provider::test_utils::create_test_provider_factory; use std::{mem, sync::Arc}; diff --git a/crates/net/downloaders/src/headers/reverse_headers.rs b/crates/net/downloaders/src/headers/reverse_headers.rs index 8d2318507..5c12a161a 100644 --- a/crates/net/downloaders/src/headers/reverse_headers.rs +++ b/crates/net/downloaders/src/headers/reverse_headers.rs @@ -1223,7 +1223,8 @@ mod tests { use crate::headers::test_utils::child_header; use assert_matches::assert_matches; - use reth_interfaces::test_utils::{TestConsensus, TestHeadersClient}; + use reth_consensus::test_utils::TestConsensus; + use reth_interfaces::test_utils::TestHeadersClient; /// Tests that `replace_number` works the same way as Option::replace #[test] diff --git a/crates/net/downloaders/src/headers/task.rs b/crates/net/downloaders/src/headers/task.rs index 16597342b..aa079dad2 100644 --- a/crates/net/downloaders/src/headers/task.rs +++ b/crates/net/downloaders/src/headers/task.rs @@ -183,7 +183,8 @@ mod tests { use crate::headers::{ reverse_headers::ReverseHeadersDownloaderBuilder, test_utils::child_header, }; - use reth_interfaces::test_utils::{TestConsensus, TestHeadersClient}; + use reth_consensus::test_utils::TestConsensus; + use reth_interfaces::test_utils::TestHeadersClient; use std::sync::Arc; #[tokio::test(flavor = "multi_thread")] diff --git a/crates/stages/Cargo.toml b/crates/stages/Cargo.toml index 3c4a3d5a1..2692c9410 100644 --- a/crates/stages/Cargo.toml +++ b/crates/stages/Cargo.toml @@ -45,6 +45,7 @@ reth-primitives = { workspace = true, features = ["test-utils", "arbitrary"] } reth-db = { workspace = true, features = ["test-utils", "mdbx"] } reth-evm-ethereum.workspace = true reth-interfaces = { workspace = true, features = ["test-utils"] } +reth-consensus = { workspace = true, features = ["test-utils"] } reth-downloaders.workspace = true reth-revm.workspace = true reth-static-file.workspace = true diff --git a/crates/stages/src/lib.rs b/crates/stages/src/lib.rs index cf2b8acbe..4b6df9391 100644 --- a/crates/stages/src/lib.rs +++ b/crates/stages/src/lib.rs @@ -15,7 +15,7 @@ //! # use std::sync::Arc; //! # use reth_downloaders::bodies::bodies::BodiesDownloaderBuilder; //! # use reth_downloaders::headers::reverse_headers::ReverseHeadersDownloaderBuilder; -//! # use reth_interfaces::test_utils::{TestBodiesClient, TestConsensus, TestHeadersClient}; +//! # use reth_interfaces::test_utils::{TestBodiesClient, TestHeadersClient}; //! # use reth_revm::EvmProcessorFactory; //! # use reth_primitives::{PeerId, MAINNET, B256, PruneModes}; //! # use reth_stages::Pipeline; @@ -28,6 +28,7 @@ //! # use reth_static_file::StaticFileProducer; //! # use reth_config::config::EtlConfig; //! # use reth_consensus::Consensus; +//! # use reth_consensus::test_utils::TestConsensus; //! # //! # let chain_spec = MAINNET.clone(); //! # let consensus: Arc = Arc::new(TestConsensus::default()); diff --git a/crates/stages/src/stages/headers.rs b/crates/stages/src/stages/headers.rs index f90149e1a..83dd710d0 100644 --- a/crates/stages/src/stages/headers.rs +++ b/crates/stages/src/stages/headers.rs @@ -371,13 +371,13 @@ mod tests { mod test_runner { use super::*; use crate::test_utils::{TestRunnerError, TestStageDB}; + use reth_consensus::test_utils::TestConsensus; use reth_db::{test_utils::TempDatabase, DatabaseEnv}; use reth_downloaders::headers::reverse_headers::{ ReverseHeadersDownloader, ReverseHeadersDownloaderBuilder, }; use reth_interfaces::test_utils::{ - generators, generators::random_header_range, TestConsensus, TestHeaderDownloader, - TestHeadersClient, + generators, generators::random_header_range, TestHeaderDownloader, TestHeadersClient, }; use reth_provider::BlockNumReader; use tokio::sync::watch;