use std::{ collections::HashMap, ops::{RangeBounds, RangeInclusive}, sync::Arc, }; use reth_chain_state::{ CanonStateNotifications, CanonStateSubscriptions, ForkChoiceNotifications, ForkChoiceSubscriptions, }; use reth_chainspec::{ChainInfo, ChainSpec, MAINNET}; use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices}; use reth_errors::ProviderError; use reth_evm::ConfigureEvmEnv; use reth_primitives::{ Account, Address, Block, BlockHash, BlockHashOrNumber, BlockId, BlockNumber, BlockNumberOrTag, BlockWithSenders, Bytecode, Bytes, Header, Receipt, SealedBlock, SealedBlockWithSenders, SealedHeader, StorageKey, StorageValue, TransactionMeta, TransactionSigned, TransactionSignedNoHash, TxHash, TxNumber, Withdrawal, Withdrawals, B256, U256, }; use reth_prune_types::{PruneCheckpoint, PruneSegment}; use reth_stages_types::{StageCheckpoint, StageId}; use reth_storage_api::StateProofProvider; use reth_storage_errors::provider::ProviderResult; use reth_trie::{ prefix_set::TriePrefixSetsMut, updates::TrieUpdates, AccountProof, HashedPostState, }; use revm::primitives::{BlockEnv, CfgEnvWithHandlerCfg}; use tokio::sync::{broadcast, watch}; use crate::{ providers::StaticFileProvider, traits::{BlockSource, ReceiptProvider}, AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, EvmEnvProvider, HeaderProvider, PruneCheckpointReader, ReceiptProviderIdExt, RequestsProvider, StageCheckpointReader, StateProvider, StateProviderBox, StateProviderFactory, StateRootProvider, StaticFileProviderFactory, TransactionVariant, TransactionsProvider, WithdrawalsProvider, }; /// Supports various api interfaces for testing purposes. #[derive(Debug, Clone, Default, Copy)] #[non_exhaustive] pub struct NoopProvider; impl ChainSpecProvider for NoopProvider { fn chain_spec(&self) -> Arc { MAINNET.clone() } } /// Noop implementation for testing purposes impl BlockHashReader for NoopProvider { fn block_hash(&self, _number: u64) -> ProviderResult> { Ok(None) } fn canonical_hashes_range( &self, _start: BlockNumber, _end: BlockNumber, ) -> ProviderResult> { Ok(vec![]) } } impl BlockNumReader for NoopProvider { fn chain_info(&self) -> ProviderResult { Ok(ChainInfo::default()) } fn best_block_number(&self) -> ProviderResult { Ok(0) } fn last_block_number(&self) -> ProviderResult { Ok(0) } fn block_number(&self, _hash: B256) -> ProviderResult> { Ok(None) } } impl BlockReader for NoopProvider { fn find_block_by_hash( &self, hash: B256, _source: BlockSource, ) -> ProviderResult> { self.block(hash.into()) } fn block(&self, _id: BlockHashOrNumber) -> ProviderResult> { Ok(None) } fn pending_block(&self) -> ProviderResult> { Ok(None) } fn pending_block_with_senders(&self) -> ProviderResult> { Ok(None) } fn pending_block_and_receipts(&self) -> ProviderResult)>> { Ok(None) } fn ommers(&self, _id: BlockHashOrNumber) -> ProviderResult>> { Ok(None) } fn block_body_indices(&self, _num: u64) -> ProviderResult> { Ok(None) } fn block_with_senders( &self, _id: BlockHashOrNumber, _transaction_kind: TransactionVariant, ) -> ProviderResult> { Ok(None) } fn sealed_block_with_senders( &self, _id: BlockHashOrNumber, _transaction_kind: TransactionVariant, ) -> ProviderResult> { Ok(None) } fn block_range(&self, _range: RangeInclusive) -> ProviderResult> { Ok(vec![]) } fn block_with_senders_range( &self, _range: RangeInclusive, ) -> ProviderResult> { Ok(vec![]) } fn sealed_block_with_senders_range( &self, _range: RangeInclusive, ) -> ProviderResult> { Ok(vec![]) } } impl BlockReaderIdExt for NoopProvider { fn block_by_id(&self, _id: BlockId) -> ProviderResult> { Ok(None) } fn sealed_header_by_id(&self, _id: BlockId) -> ProviderResult> { Ok(None) } fn header_by_id(&self, _id: BlockId) -> ProviderResult> { Ok(None) } fn ommers_by_id(&self, _id: BlockId) -> ProviderResult>> { Ok(None) } } impl BlockIdReader for NoopProvider { fn pending_block_num_hash(&self) -> ProviderResult> { Ok(None) } fn safe_block_num_hash(&self) -> ProviderResult> { Ok(None) } fn finalized_block_num_hash(&self) -> ProviderResult> { Ok(None) } } impl TransactionsProvider for NoopProvider { fn transaction_id(&self, _tx_hash: TxHash) -> ProviderResult> { Ok(None) } fn transaction_by_id(&self, _id: TxNumber) -> ProviderResult> { Ok(None) } fn transaction_by_id_no_hash( &self, _id: TxNumber, ) -> ProviderResult> { Ok(None) } fn transaction_by_hash(&self, _hash: TxHash) -> ProviderResult> { Ok(None) } fn transaction_by_hash_with_meta( &self, _hash: TxHash, ) -> ProviderResult> { Ok(None) } fn transaction_block(&self, _id: TxNumber) -> ProviderResult> { todo!() } fn transactions_by_block( &self, _block_id: BlockHashOrNumber, ) -> ProviderResult>> { Ok(None) } fn transactions_by_block_range( &self, _range: impl RangeBounds, ) -> ProviderResult>> { Ok(Vec::default()) } fn transactions_by_tx_range( &self, _range: impl RangeBounds, ) -> ProviderResult> { Ok(Vec::default()) } fn senders_by_tx_range( &self, _range: impl RangeBounds, ) -> ProviderResult> { Ok(Vec::default()) } fn transaction_sender(&self, _id: TxNumber) -> ProviderResult> { Ok(None) } } impl ReceiptProvider for NoopProvider { fn receipt(&self, _id: TxNumber) -> ProviderResult> { Ok(None) } fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult> { Ok(None) } fn receipts_by_block(&self, _block: BlockHashOrNumber) -> ProviderResult>> { Ok(None) } fn receipts_by_tx_range( &self, _range: impl RangeBounds, ) -> ProviderResult> { Ok(vec![]) } } impl ReceiptProviderIdExt for NoopProvider {} impl HeaderProvider for NoopProvider { fn header(&self, _block_hash: &BlockHash) -> ProviderResult> { Ok(None) } fn header_by_number(&self, _num: u64) -> ProviderResult> { Ok(None) } fn header_td(&self, _hash: &BlockHash) -> ProviderResult> { Ok(None) } fn header_td_by_number(&self, _number: BlockNumber) -> ProviderResult> { Ok(None) } fn headers_range(&self, _range: impl RangeBounds) -> ProviderResult> { Ok(vec![]) } fn sealed_header(&self, _number: BlockNumber) -> ProviderResult> { Ok(None) } fn sealed_headers_while( &self, _range: impl RangeBounds, _predicate: impl FnMut(&SealedHeader) -> bool, ) -> ProviderResult> { Ok(vec![]) } } impl AccountReader for NoopProvider { fn basic_account(&self, _address: Address) -> ProviderResult> { Ok(None) } } impl ChangeSetReader for NoopProvider { fn account_block_changeset( &self, _block_number: BlockNumber, ) -> ProviderResult> { Ok(Vec::default()) } } impl StateRootProvider for NoopProvider { fn hashed_state_root(&self, _state: HashedPostState) -> ProviderResult { Ok(B256::default()) } fn hashed_state_root_from_nodes( &self, _nodes: TrieUpdates, _hashed_state: HashedPostState, _prefix_sets: TriePrefixSetsMut, ) -> ProviderResult { Ok(B256::default()) } fn hashed_state_root_with_updates( &self, _state: HashedPostState, ) -> ProviderResult<(B256, TrieUpdates)> { Ok((B256::default(), TrieUpdates::default())) } fn hashed_state_root_from_nodes_with_updates( &self, _nodes: TrieUpdates, _hashed_state: HashedPostState, _prefix_sets: TriePrefixSetsMut, ) -> ProviderResult<(B256, TrieUpdates)> { Ok((B256::default(), TrieUpdates::default())) } fn hashed_storage_root( &self, _address: Address, _hashed_storage: reth_trie::HashedStorage, ) -> ProviderResult { Ok(B256::default()) } } impl StateProofProvider for NoopProvider { fn hashed_proof( &self, _hashed_state: HashedPostState, address: Address, _slots: &[B256], ) -> ProviderResult { Ok(AccountProof::new(address)) } fn witness( &self, _overlay: HashedPostState, _target: HashedPostState, ) -> ProviderResult> { Ok(HashMap::default()) } } impl StateProvider for NoopProvider { fn storage( &self, _account: Address, _storage_key: StorageKey, ) -> ProviderResult> { Ok(None) } fn bytecode_by_hash(&self, _code_hash: B256) -> ProviderResult> { Ok(None) } } impl EvmEnvProvider for NoopProvider { fn fill_env_at( &self, _cfg: &mut CfgEnvWithHandlerCfg, _block_env: &mut BlockEnv, _at: BlockHashOrNumber, _evm_config: EvmConfig, ) -> ProviderResult<()> where EvmConfig: ConfigureEvmEnv, { Ok(()) } fn fill_env_with_header( &self, _cfg: &mut CfgEnvWithHandlerCfg, _block_env: &mut BlockEnv, _header: &Header, _evm_config: EvmConfig, ) -> ProviderResult<()> where EvmConfig: ConfigureEvmEnv, { Ok(()) } fn fill_cfg_env_at( &self, _cfg: &mut CfgEnvWithHandlerCfg, _at: BlockHashOrNumber, _evm_config: EvmConfig, ) -> ProviderResult<()> where EvmConfig: ConfigureEvmEnv, { Ok(()) } fn fill_cfg_env_with_header( &self, _cfg: &mut CfgEnvWithHandlerCfg, _header: &Header, _evm_config: EvmConfig, ) -> ProviderResult<()> where EvmConfig: ConfigureEvmEnv, { Ok(()) } } impl StateProviderFactory for NoopProvider { fn latest(&self) -> ProviderResult { Ok(Box::new(*self)) } fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult { Ok(Box::new(*self)) } fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult { Ok(Box::new(*self)) } fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult { Ok(Box::new(*self)) } fn pending(&self) -> ProviderResult { Ok(Box::new(*self)) } fn state_by_block_number_or_tag( &self, number_or_tag: BlockNumberOrTag, ) -> ProviderResult { match number_or_tag { BlockNumberOrTag::Latest => self.latest(), BlockNumberOrTag::Finalized => { // we can only get the finalized state by hash, not by num let hash = self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?; // only look at historical state self.history_by_block_hash(hash) } BlockNumberOrTag::Safe => { // we can only get the safe state by hash, not by num let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?; self.history_by_block_hash(hash) } BlockNumberOrTag::Earliest => self.history_by_block_number(0), BlockNumberOrTag::Pending => self.pending(), BlockNumberOrTag::Number(num) => self.history_by_block_number(num), } } fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult> { Ok(Some(Box::new(*self))) } } impl StageCheckpointReader for NoopProvider { fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult> { Ok(None) } fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult>> { Ok(None) } fn get_all_checkpoints(&self) -> ProviderResult> { Ok(Vec::new()) } } impl WithdrawalsProvider for NoopProvider { fn withdrawals_by_block( &self, _id: BlockHashOrNumber, _timestamp: u64, ) -> ProviderResult> { Ok(None) } fn latest_withdrawal(&self) -> ProviderResult> { Ok(None) } } impl RequestsProvider for NoopProvider { fn requests_by_block( &self, _id: BlockHashOrNumber, _timestamp: u64, ) -> ProviderResult> { Ok(None) } } impl PruneCheckpointReader for NoopProvider { fn get_prune_checkpoint( &self, _segment: PruneSegment, ) -> ProviderResult> { Ok(None) } fn get_prune_checkpoints(&self) -> ProviderResult> { Ok(Vec::new()) } } impl StaticFileProviderFactory for NoopProvider { fn static_file_provider(&self) -> StaticFileProvider { StaticFileProvider::default() } } impl CanonStateSubscriptions for NoopProvider { fn subscribe_to_canonical_state(&self) -> CanonStateNotifications { broadcast::channel(1).1 } } impl ForkChoiceSubscriptions for NoopProvider { fn subscribe_to_safe_block(&self) -> ForkChoiceNotifications { let (_, rx) = watch::channel(None); ForkChoiceNotifications(rx) } fn subscribe_to_finalized_block(&self) -> ForkChoiceNotifications { let (_, rx) = watch::channel(None); ForkChoiceNotifications(rx) } }