reth_provider/test_utils/
mock.rs

1use crate::{
2    traits::{BlockSource, ReceiptProvider},
3    AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
4    ChainSpecProvider, ChangeSetReader, EthStorage, HeaderProvider, ReceiptProviderIdExt,
5    StateProvider, StateProviderBox, StateProviderFactory, StateReader, StateRootProvider,
6    TransactionVariant, TransactionsProvider, WithdrawalsProvider,
7};
8use alloy_consensus::{constants::EMPTY_ROOT_HASH, transaction::TransactionMeta, Header};
9use alloy_eips::{eip4895::Withdrawals, BlockHashOrNumber, BlockId, BlockNumberOrTag};
10use alloy_primitives::{
11    keccak256, map::HashMap, Address, BlockHash, BlockNumber, Bytes, StorageKey, TxHash, TxNumber,
12    B256, U256,
13};
14use parking_lot::Mutex;
15use reth_chain_state::{CanonStateNotifications, CanonStateSubscriptions};
16use reth_chainspec::{ChainInfo, EthChainSpec};
17use reth_db_api::{
18    mock::{DatabaseMock, TxMock},
19    models::{AccountBeforeTx, StoredBlockBodyIndices},
20};
21use reth_ethereum_engine_primitives::EthEngineTypes;
22use reth_ethereum_primitives::{EthPrimitives, Receipt};
23use reth_execution_types::ExecutionOutcome;
24use reth_node_types::NodeTypes;
25use reth_primitives_traits::{
26    Account, Bytecode, GotExpected, NodePrimitives, RecoveredBlock, SealedBlock, SealedHeader,
27    SignerRecoverable,
28};
29use reth_prune_types::PruneModes;
30use reth_stages_types::{StageCheckpoint, StageId};
31use reth_storage_api::{
32    BlockBodyIndicesProvider, DBProvider, DatabaseProviderFactory, HashedPostStateProvider,
33    NodePrimitivesProvider, OmmersProvider, StageCheckpointReader, StateCommitmentProvider,
34    StateProofProvider, StorageRootProvider,
35};
36use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
37use reth_trie::{
38    updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
39    MultiProofTargets, StorageMultiProof, StorageProof, TrieInput,
40};
41use reth_trie_db::MerklePatriciaTrie;
42use revm_state::FlaggedStorage;
43use std::{
44    collections::BTreeMap,
45    fmt::Debug,
46    ops::{RangeBounds, RangeInclusive},
47    sync::Arc,
48};
49use tokio::sync::broadcast;
50
51/// A mock implementation for Provider interfaces.
52#[derive(Debug)]
53pub struct MockEthProvider<
54    T: NodePrimitives = reth_ethereum_primitives::EthPrimitives,
55    ChainSpec = reth_chainspec::ChainSpec,
56> {
57    ///local block store
58    pub blocks: Arc<Mutex<HashMap<B256, T::Block>>>,
59    /// Local header store
60    pub headers: Arc<Mutex<HashMap<B256, Header>>>,
61    /// Local account store
62    pub accounts: Arc<Mutex<HashMap<Address, ExtendedAccount>>>,
63    /// Local chain spec
64    pub chain_spec: Arc<ChainSpec>,
65    /// Local state roots
66    pub state_roots: Arc<Mutex<Vec<B256>>>,
67    tx: TxMock,
68    prune_modes: Arc<PruneModes>,
69}
70
71impl<T: NodePrimitives, ChainSpec> Clone for MockEthProvider<T, ChainSpec>
72where
73    T::Block: Clone,
74{
75    fn clone(&self) -> Self {
76        Self {
77            blocks: self.blocks.clone(),
78            headers: self.headers.clone(),
79            accounts: self.accounts.clone(),
80            chain_spec: self.chain_spec.clone(),
81            state_roots: self.state_roots.clone(),
82            tx: self.tx.clone(),
83            prune_modes: self.prune_modes.clone(),
84        }
85    }
86}
87
88impl<T: NodePrimitives> MockEthProvider<T, reth_chainspec::ChainSpec> {
89    /// Create a new, empty instance
90    pub fn new() -> Self {
91        Self {
92            blocks: Default::default(),
93            headers: Default::default(),
94            accounts: Default::default(),
95            chain_spec: Arc::new(reth_chainspec::ChainSpecBuilder::mainnet().build()),
96            state_roots: Default::default(),
97            tx: Default::default(),
98            prune_modes: Default::default(),
99        }
100    }
101}
102
103impl<ChainSpec> MockEthProvider<reth_ethereum_primitives::EthPrimitives, ChainSpec> {
104    /// Add block to local block store
105    pub fn add_block(&self, hash: B256, block: reth_ethereum_primitives::Block) {
106        self.add_header(hash, block.header.clone());
107        self.blocks.lock().insert(hash, block);
108    }
109
110    /// Add multiple blocks to local block store
111    pub fn extend_blocks(
112        &self,
113        iter: impl IntoIterator<Item = (B256, reth_ethereum_primitives::Block)>,
114    ) {
115        for (hash, block) in iter {
116            self.add_header(hash, block.header.clone());
117            self.add_block(hash, block)
118        }
119    }
120
121    /// Add header to local header store
122    pub fn add_header(&self, hash: B256, header: Header) {
123        self.headers.lock().insert(hash, header);
124    }
125
126    /// Add multiple headers to local header store
127    pub fn extend_headers(&self, iter: impl IntoIterator<Item = (B256, Header)>) {
128        for (hash, header) in iter {
129            self.add_header(hash, header)
130        }
131    }
132
133    /// Add account to local account store
134    pub fn add_account(&self, address: Address, account: ExtendedAccount) {
135        self.accounts.lock().insert(address, account);
136    }
137
138    /// Add account to local account store
139    pub fn extend_accounts(&self, iter: impl IntoIterator<Item = (Address, ExtendedAccount)>) {
140        for (address, account) in iter {
141            self.add_account(address, account)
142        }
143    }
144
145    /// Add state root to local state root store
146    pub fn add_state_root(&self, state_root: B256) {
147        self.state_roots.lock().push(state_root);
148    }
149
150    /// Set chain spec.
151    pub fn with_chain_spec<C>(
152        self,
153        chain_spec: C,
154    ) -> MockEthProvider<reth_ethereum_primitives::EthPrimitives, C> {
155        MockEthProvider {
156            blocks: self.blocks,
157            headers: self.headers,
158            accounts: self.accounts,
159            chain_spec: Arc::new(chain_spec),
160            state_roots: self.state_roots,
161            tx: self.tx,
162            prune_modes: self.prune_modes,
163        }
164    }
165}
166
167impl Default for MockEthProvider {
168    fn default() -> Self {
169        Self::new()
170    }
171}
172
173/// An extended account for local store
174#[derive(Debug, Clone)]
175pub struct ExtendedAccount {
176    account: Account,
177    bytecode: Option<Bytecode>,
178    storage: HashMap<StorageKey, FlaggedStorage>,
179}
180
181impl ExtendedAccount {
182    /// Create new instance of extended account
183    pub fn new(nonce: u64, balance: U256) -> Self {
184        Self {
185            account: Account { nonce, balance, bytecode_hash: None },
186            bytecode: None,
187            storage: Default::default(),
188        }
189    }
190
191    /// Set bytecode and bytecode hash on the extended account
192    pub fn with_bytecode(mut self, bytecode: Bytes) -> Self {
193        let hash = keccak256(&bytecode);
194        self.account.bytecode_hash = Some(hash);
195        self.bytecode = Some(Bytecode::new_raw(bytecode));
196        self
197    }
198
199    /// Add storage to the extended account. If the storage key is already present,
200    /// the value is updated.
201    pub fn extend_storage(
202        mut self,
203        storage: impl IntoIterator<Item = (StorageKey, FlaggedStorage)>,
204    ) -> Self {
205        self.storage.extend(storage);
206        self
207    }
208}
209
210/// Mock node.
211#[derive(Clone, Debug)]
212pub struct MockNode;
213
214impl NodeTypes for MockNode {
215    type Primitives = EthPrimitives;
216    type ChainSpec = reth_chainspec::ChainSpec;
217    type StateCommitment = MerklePatriciaTrie;
218    type Storage = EthStorage;
219    type Payload = EthEngineTypes;
220}
221
222impl<T, ChainSpec> StateCommitmentProvider for MockEthProvider<T, ChainSpec>
223where
224    T: NodePrimitives,
225    ChainSpec: EthChainSpec + Send + Sync + 'static,
226{
227    type StateCommitment = <MockNode as NodeTypes>::StateCommitment;
228}
229
230impl<T: NodePrimitives, ChainSpec: EthChainSpec + Clone + 'static> DatabaseProviderFactory
231    for MockEthProvider<T, ChainSpec>
232{
233    type DB = DatabaseMock;
234    type Provider = Self;
235    type ProviderRW = Self;
236
237    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
238        // TODO: return Ok(self.clone()) when engine tests stops relying on an
239        // Error returned here https://github.com/paradigmxyz/reth/pull/14482
240        //Ok(self.clone())
241        Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
242    }
243
244    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
245        // TODO: return Ok(self.clone()) when engine tests stops relying on an
246        // Error returned here https://github.com/paradigmxyz/reth/pull/14482
247        //Ok(self.clone())
248        Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
249    }
250}
251
252impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DBProvider
253    for MockEthProvider<T, ChainSpec>
254{
255    type Tx = TxMock;
256
257    fn tx_ref(&self) -> &Self::Tx {
258        &self.tx
259    }
260
261    fn tx_mut(&mut self) -> &mut Self::Tx {
262        &mut self.tx
263    }
264
265    fn into_tx(self) -> Self::Tx {
266        self.tx
267    }
268
269    fn prune_modes_ref(&self) -> &PruneModes {
270        &self.prune_modes
271    }
272}
273
274impl<ChainSpec: EthChainSpec + Send + Sync + 'static> HeaderProvider
275    for MockEthProvider<reth_ethereum_primitives::EthPrimitives, ChainSpec>
276{
277    type Header = Header;
278
279    fn header(&self, block_hash: &BlockHash) -> ProviderResult<Option<Header>> {
280        let lock = self.headers.lock();
281        Ok(lock.get(block_hash).cloned())
282    }
283
284    fn header_by_number(&self, num: u64) -> ProviderResult<Option<Header>> {
285        let lock = self.headers.lock();
286        Ok(lock.values().find(|h| h.number == num).cloned())
287    }
288
289    fn header_td(&self, hash: &BlockHash) -> ProviderResult<Option<U256>> {
290        let lock = self.headers.lock();
291        Ok(lock.get(hash).map(|target| {
292            lock.values()
293                .filter(|h| h.number < target.number)
294                .fold(target.difficulty, |td, h| td + h.difficulty)
295        }))
296    }
297
298    fn header_td_by_number(&self, number: BlockNumber) -> ProviderResult<Option<U256>> {
299        let lock = self.headers.lock();
300        let sum = lock
301            .values()
302            .filter(|h| h.number <= number)
303            .fold(U256::ZERO, |td, h| td + h.difficulty);
304        Ok(Some(sum))
305    }
306
307    fn headers_range(&self, range: impl RangeBounds<BlockNumber>) -> ProviderResult<Vec<Header>> {
308        let lock = self.headers.lock();
309
310        let mut headers: Vec<_> =
311            lock.values().filter(|header| range.contains(&header.number)).cloned().collect();
312        headers.sort_by_key(|header| header.number);
313
314        Ok(headers)
315    }
316
317    fn sealed_header(&self, number: BlockNumber) -> ProviderResult<Option<SealedHeader>> {
318        Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
319    }
320
321    fn sealed_headers_while(
322        &self,
323        range: impl RangeBounds<BlockNumber>,
324        mut predicate: impl FnMut(&SealedHeader) -> bool,
325    ) -> ProviderResult<Vec<SealedHeader>> {
326        Ok(self
327            .headers_range(range)?
328            .into_iter()
329            .map(SealedHeader::seal_slow)
330            .take_while(|h| predicate(h))
331            .collect())
332    }
333}
334
335impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
336where
337    T: NodePrimitives,
338    ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
339{
340    type ChainSpec = ChainSpec;
341
342    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
343        self.chain_spec.clone()
344    }
345}
346
347impl<ChainSpec: EthChainSpec + 'static> TransactionsProvider
348    for MockEthProvider<reth_ethereum_primitives::EthPrimitives, ChainSpec>
349{
350    type Transaction = reth_ethereum_primitives::TransactionSigned;
351
352    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
353        let lock = self.blocks.lock();
354        let tx_number = lock
355            .values()
356            .flat_map(|block| &block.body.transactions)
357            .position(|tx| *tx.tx_hash() == tx_hash)
358            .map(|pos| pos as TxNumber);
359
360        Ok(tx_number)
361    }
362
363    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
364        let lock = self.blocks.lock();
365        let transaction =
366            lock.values().flat_map(|block| &block.body.transactions).nth(id as usize).cloned();
367
368        Ok(transaction)
369    }
370
371    fn transaction_by_id_unhashed(
372        &self,
373        id: TxNumber,
374    ) -> ProviderResult<Option<Self::Transaction>> {
375        let lock = self.blocks.lock();
376        let transaction =
377            lock.values().flat_map(|block| &block.body.transactions).nth(id as usize).cloned();
378
379        Ok(transaction)
380    }
381
382    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
383        Ok(self.blocks.lock().iter().find_map(|(_, block)| {
384            block.body.transactions.iter().find(|tx| *tx.tx_hash() == hash).cloned()
385        }))
386    }
387
388    fn transaction_by_hash_with_meta(
389        &self,
390        hash: TxHash,
391    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
392        let lock = self.blocks.lock();
393        for (block_hash, block) in lock.iter() {
394            for (index, tx) in block.body.transactions.iter().enumerate() {
395                if *tx.tx_hash() == hash {
396                    let meta = TransactionMeta {
397                        tx_hash: hash,
398                        index: index as u64,
399                        block_hash: *block_hash,
400                        block_number: block.header.number,
401                        base_fee: block.header.base_fee_per_gas,
402                        excess_blob_gas: block.header.excess_blob_gas,
403                        timestamp: block.header.timestamp,
404                    };
405                    return Ok(Some((tx.clone(), meta)))
406                }
407            }
408        }
409        Ok(None)
410    }
411
412    fn transaction_block(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
413        let lock = self.blocks.lock();
414        let mut current_tx_number: TxNumber = 0;
415        for block in lock.values() {
416            if current_tx_number + (block.body.transactions.len() as TxNumber) > id {
417                return Ok(Some(block.header.number))
418            }
419            current_tx_number += block.body.transactions.len() as TxNumber;
420        }
421        Ok(None)
422    }
423
424    fn transactions_by_block(
425        &self,
426        id: BlockHashOrNumber,
427    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
428        Ok(self.block(id)?.map(|b| b.body.transactions))
429    }
430
431    fn transactions_by_block_range(
432        &self,
433        range: impl RangeBounds<alloy_primitives::BlockNumber>,
434    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
435        // init btreemap so we can return in order
436        let mut map = BTreeMap::new();
437        for (_, block) in self.blocks.lock().iter() {
438            if range.contains(&block.number) {
439                map.insert(block.number, block.body.transactions.clone());
440            }
441        }
442
443        Ok(map.into_values().collect())
444    }
445
446    fn transactions_by_tx_range(
447        &self,
448        range: impl RangeBounds<TxNumber>,
449    ) -> ProviderResult<Vec<Self::Transaction>> {
450        let lock = self.blocks.lock();
451        let transactions = lock
452            .values()
453            .flat_map(|block| &block.body.transactions)
454            .enumerate()
455            .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
456            .map(|(_, tx)| tx.clone())
457            .collect();
458
459        Ok(transactions)
460    }
461
462    fn senders_by_tx_range(
463        &self,
464        range: impl RangeBounds<TxNumber>,
465    ) -> ProviderResult<Vec<Address>> {
466        let lock = self.blocks.lock();
467        let transactions = lock
468            .values()
469            .flat_map(|block| &block.body.transactions)
470            .enumerate()
471            .filter_map(|(tx_number, tx)| {
472                if range.contains(&(tx_number as TxNumber)) {
473                    tx.recover_signer().ok()
474                } else {
475                    None
476                }
477            })
478            .collect();
479
480        Ok(transactions)
481    }
482
483    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
484        self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
485    }
486}
487
488impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
489where
490    T: NodePrimitives,
491    ChainSpec: Send + Sync + 'static,
492{
493    type Receipt = Receipt;
494
495    fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
496        Ok(None)
497    }
498
499    fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
500        Ok(None)
501    }
502
503    fn receipts_by_block(
504        &self,
505        _block: BlockHashOrNumber,
506    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
507        Ok(None)
508    }
509
510    fn receipts_by_tx_range(
511        &self,
512        _range: impl RangeBounds<TxNumber>,
513    ) -> ProviderResult<Vec<Self::Receipt>> {
514        Ok(vec![])
515    }
516}
517
518impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
519where
520    T: NodePrimitives,
521    Self: ReceiptProvider + BlockIdReader,
522{
523}
524
525impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
526    for MockEthProvider<T, ChainSpec>
527{
528    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
529        let lock = self.headers.lock();
530        let hash =
531            lock.iter().find_map(|(hash, header)| (header.number == number).then_some(*hash));
532        Ok(hash)
533    }
534
535    fn canonical_hashes_range(
536        &self,
537        start: BlockNumber,
538        end: BlockNumber,
539    ) -> ProviderResult<Vec<B256>> {
540        let lock = self.headers.lock();
541        let mut hashes: Vec<_> =
542            lock.iter().filter(|(_, header)| (start..end).contains(&header.number)).collect();
543
544        hashes.sort_by_key(|(_, header)| header.number);
545
546        Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
547    }
548}
549
550impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
551    for MockEthProvider<T, ChainSpec>
552{
553    fn chain_info(&self) -> ProviderResult<ChainInfo> {
554        let best_block_number = self.best_block_number()?;
555        let lock = self.headers.lock();
556
557        Ok(lock
558            .iter()
559            .find(|(_, header)| header.number == best_block_number)
560            .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number })
561            .unwrap_or_default())
562    }
563
564    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
565        let lock = self.headers.lock();
566        lock.iter()
567            .max_by_key(|h| h.1.number)
568            .map(|(_, header)| header.number)
569            .ok_or(ProviderError::BestBlockNotFound)
570    }
571
572    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
573        self.best_block_number()
574    }
575
576    fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
577        let lock = self.headers.lock();
578        Ok(lock.get(&hash).map(|header| header.number))
579    }
580}
581
582impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
583    for MockEthProvider<T, ChainSpec>
584{
585    fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
586        Ok(None)
587    }
588
589    fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
590        Ok(None)
591    }
592
593    fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
594        Ok(None)
595    }
596}
597
598//look
599impl<ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
600    for MockEthProvider<reth_ethereum_primitives::EthPrimitives, ChainSpec>
601{
602    type Block = reth_ethereum_primitives::Block;
603
604    fn find_block_by_hash(
605        &self,
606        hash: B256,
607        _source: BlockSource,
608    ) -> ProviderResult<Option<Self::Block>> {
609        self.block(hash.into())
610    }
611
612    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
613        let lock = self.blocks.lock();
614        match id {
615            BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
616            BlockHashOrNumber::Number(num) => Ok(lock.values().find(|b| b.number == num).cloned()),
617        }
618    }
619
620    fn pending_block(&self) -> ProviderResult<Option<SealedBlock<Self::Block>>> {
621        Ok(None)
622    }
623
624    fn pending_block_with_senders(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
625        Ok(None)
626    }
627
628    fn pending_block_and_receipts(
629        &self,
630    ) -> ProviderResult<Option<(SealedBlock<Self::Block>, Vec<Receipt>)>> {
631        Ok(None)
632    }
633
634    fn recovered_block(
635        &self,
636        _id: BlockHashOrNumber,
637        _transaction_kind: TransactionVariant,
638    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
639        Ok(None)
640    }
641
642    fn sealed_block_with_senders(
643        &self,
644        _id: BlockHashOrNumber,
645        _transaction_kind: TransactionVariant,
646    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
647        Ok(None)
648    }
649
650    fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
651        let lock = self.blocks.lock();
652
653        let mut blocks: Vec<_> =
654            lock.values().filter(|block| range.contains(&block.number)).cloned().collect();
655        blocks.sort_by_key(|block| block.number);
656
657        Ok(blocks)
658    }
659
660    fn block_with_senders_range(
661        &self,
662        _range: RangeInclusive<BlockNumber>,
663    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
664        Ok(vec![])
665    }
666
667    fn recovered_block_range(
668        &self,
669        _range: RangeInclusive<BlockNumber>,
670    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
671        Ok(vec![])
672    }
673}
674
675impl<ChainSpec> BlockReaderIdExt
676    for MockEthProvider<reth_ethereum_primitives::EthPrimitives, ChainSpec>
677where
678    ChainSpec: EthChainSpec + Send + Sync + 'static,
679{
680    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<reth_ethereum_primitives::Block>> {
681        match id {
682            BlockId::Number(num) => self.block_by_number_or_tag(num),
683            BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
684        }
685    }
686
687    fn sealed_header_by_id(&self, id: BlockId) -> ProviderResult<Option<SealedHeader>> {
688        self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
689    }
690
691    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Header>> {
692        match self.block_by_id(id)? {
693            None => Ok(None),
694            Some(block) => Ok(Some(block.header)),
695        }
696    }
697
698    fn ommers_by_id(&self, id: BlockId) -> ProviderResult<Option<Vec<Header>>> {
699        match id {
700            BlockId::Number(num) => self.ommers_by_number_or_tag(num),
701            BlockId::Hash(hash) => self.ommers(BlockHashOrNumber::Hash(hash.block_hash)),
702        }
703    }
704}
705
706impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
707    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
708        Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
709    }
710}
711
712impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
713    for MockEthProvider<T, ChainSpec>
714{
715    fn get_stage_checkpoint(&self, _id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
716        Ok(None)
717    }
718
719    fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
720        Ok(None)
721    }
722
723    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
724        Ok(vec![])
725    }
726}
727
728impl<T, ChainSpec> StateRootProvider for MockEthProvider<T, ChainSpec>
729where
730    T: NodePrimitives,
731    ChainSpec: Send + Sync,
732{
733    fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
734        Ok(self.state_roots.lock().pop().unwrap_or_default())
735    }
736
737    fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
738        Ok(self.state_roots.lock().pop().unwrap_or_default())
739    }
740
741    fn state_root_with_updates(
742        &self,
743        _state: HashedPostState,
744    ) -> ProviderResult<(B256, TrieUpdates)> {
745        let state_root = self.state_roots.lock().pop().unwrap_or_default();
746        Ok((state_root, Default::default()))
747    }
748
749    fn state_root_from_nodes_with_updates(
750        &self,
751        _input: TrieInput,
752    ) -> ProviderResult<(B256, TrieUpdates)> {
753        let state_root = self.state_roots.lock().pop().unwrap_or_default();
754        Ok((state_root, Default::default()))
755    }
756}
757
758impl<T, ChainSpec> StorageRootProvider for MockEthProvider<T, ChainSpec>
759where
760    T: NodePrimitives,
761    ChainSpec: Send + Sync,
762{
763    fn storage_root(
764        &self,
765        _address: Address,
766        _hashed_storage: HashedStorage,
767    ) -> ProviderResult<B256> {
768        Ok(EMPTY_ROOT_HASH)
769    }
770
771    fn storage_proof(
772        &self,
773        _address: Address,
774        slot: B256,
775        _hashed_storage: HashedStorage,
776    ) -> ProviderResult<reth_trie::StorageProof> {
777        Ok(StorageProof::new(slot))
778    }
779
780    fn storage_multiproof(
781        &self,
782        _address: Address,
783        _slots: &[B256],
784        _hashed_storage: HashedStorage,
785    ) -> ProviderResult<StorageMultiProof> {
786        Ok(StorageMultiProof::empty())
787    }
788}
789
790impl<T, ChainSpec> StateProofProvider for MockEthProvider<T, ChainSpec>
791where
792    T: NodePrimitives,
793    ChainSpec: Send + Sync,
794{
795    fn proof(
796        &self,
797        _input: TrieInput,
798        address: Address,
799        _slots: &[B256],
800    ) -> ProviderResult<AccountProof> {
801        Ok(AccountProof::new(address))
802    }
803
804    fn multiproof(
805        &self,
806        _input: TrieInput,
807        _targets: MultiProofTargets,
808    ) -> ProviderResult<MultiProof> {
809        Ok(MultiProof::default())
810    }
811
812    fn witness(&self, _input: TrieInput, _target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
813        Ok(Vec::default())
814    }
815}
816
817impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HashedPostStateProvider
818    for MockEthProvider<T, ChainSpec>
819{
820    fn hashed_post_state(&self, _state: &revm_database::BundleState) -> HashedPostState {
821        HashedPostState::default()
822    }
823}
824
825impl<T, ChainSpec> StateProvider for MockEthProvider<T, ChainSpec>
826where
827    T: NodePrimitives,
828    ChainSpec: EthChainSpec + Send + Sync + 'static,
829{
830    fn storage(
831        &self,
832        account: Address,
833        storage_key: StorageKey,
834    ) -> ProviderResult<Option<FlaggedStorage>> {
835        let lock = self.accounts.lock();
836        Ok(lock.get(&account).and_then(|account| account.storage.get(&storage_key)).copied())
837    }
838
839    fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
840        let lock = self.accounts.lock();
841        Ok(lock.values().find_map(|account| {
842            match (account.account.bytecode_hash.as_ref(), account.bytecode.as_ref()) {
843                (Some(bytecode_hash), Some(bytecode)) if bytecode_hash == code_hash => {
844                    Some(bytecode.clone())
845                }
846                _ => None,
847            }
848        }))
849    }
850}
851
852impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> StateProviderFactory
853    for MockEthProvider<T, ChainSpec>
854{
855    fn latest(&self) -> ProviderResult<StateProviderBox> {
856        Ok(Box::new(self.clone()))
857    }
858
859    fn state_by_block_number_or_tag(
860        &self,
861        number_or_tag: BlockNumberOrTag,
862    ) -> ProviderResult<StateProviderBox> {
863        match number_or_tag {
864            BlockNumberOrTag::Latest => self.latest(),
865            BlockNumberOrTag::Finalized => {
866                // we can only get the finalized state by hash, not by num
867                let hash =
868                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
869
870                // only look at historical state
871                self.history_by_block_hash(hash)
872            }
873            BlockNumberOrTag::Safe => {
874                // we can only get the safe state by hash, not by num
875                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
876
877                self.history_by_block_hash(hash)
878            }
879            BlockNumberOrTag::Earliest => self.history_by_block_number(0),
880            BlockNumberOrTag::Pending => self.pending(),
881            BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
882        }
883    }
884
885    fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
886        Ok(Box::new(self.clone()))
887    }
888
889    fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
890        Ok(Box::new(self.clone()))
891    }
892
893    fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
894        Ok(Box::new(self.clone()))
895    }
896
897    fn pending(&self) -> ProviderResult<StateProviderBox> {
898        Ok(Box::new(self.clone()))
899    }
900
901    fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
902        Ok(Some(Box::new(self.clone())))
903    }
904}
905
906impl<T: NodePrimitives, ChainSpec: Send + Sync> WithdrawalsProvider
907    for MockEthProvider<T, ChainSpec>
908{
909    fn withdrawals_by_block(
910        &self,
911        _id: BlockHashOrNumber,
912        _timestamp: u64,
913    ) -> ProviderResult<Option<Withdrawals>> {
914        Ok(None)
915    }
916}
917
918impl<T, ChainSpec> OmmersProvider for MockEthProvider<T, ChainSpec>
919where
920    T: NodePrimitives,
921    ChainSpec: Send + Sync,
922    Self: HeaderProvider,
923{
924    fn ommers(&self, _id: BlockHashOrNumber) -> ProviderResult<Option<Vec<Self::Header>>> {
925        Ok(None)
926    }
927}
928
929impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
930    for MockEthProvider<T, ChainSpec>
931{
932    fn block_body_indices(&self, _num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
933        Ok(None)
934    }
935    fn block_body_indices_range(
936        &self,
937        _range: RangeInclusive<BlockNumber>,
938    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
939        Ok(vec![])
940    }
941}
942
943impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
944    fn account_block_changeset(
945        &self,
946        _block_number: BlockNumber,
947    ) -> ProviderResult<Vec<AccountBeforeTx>> {
948        Ok(Vec::default())
949    }
950}
951
952impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
953    type Receipt = Receipt;
954
955    fn get_state(&self, _block: BlockNumber) -> ProviderResult<Option<ExecutionOutcome>> {
956        Ok(None)
957    }
958}
959
960impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
961    for MockEthProvider<T, ChainSpec>
962{
963    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
964        broadcast::channel(1).1
965    }
966}
967
968impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
969    for MockEthProvider<T, ChainSpec>
970{
971    type Primitives = T;
972}