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