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