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