Skip to main content

reth_provider/test_utils/
mock.rs

1use crate::{
2    traits::{BlockSource, ReceiptProvider},
3    AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
4    BlockReader, BlockReaderIdExt, ChainSpecProvider, ChangeSetReader, HeaderProvider,
5    PruneCheckpointReader, RangeEnd, RangeResponse, RangeResult, ReceiptProviderIdExt,
6    StateProvider, StateProviderBox, StateProviderFactory, StateRangeProvider,
7    StateRangeProviderFactory, StateRangeView, StateReader, StateRootProvider, StorageRangeResult,
8    TransactionVariant, TransactionsProvider,
9};
10use alloy_consensus::{
11    constants::EMPTY_ROOT_HASH,
12    transaction::{TransactionMeta, TxHashRef},
13    BlockHeader,
14};
15use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
16use alloy_primitives::{
17    keccak256,
18    map::{AddressMap, B256Map, HashMap},
19    Address, BlockHash, BlockNumber, Bytes, StorageKey, StorageValue, TxHash, TxNumber, B256, U256,
20};
21use parking_lot::Mutex;
22use reth_chain_state::{CanonStateNotifications, CanonStateSubscriptions, ExecutedBlock};
23use reth_chainspec::{ChainInfo, EthChainSpec};
24use reth_db::transaction::DbTx;
25use reth_db_api::{
26    mock::{DatabaseMock, TxMock},
27    models::{AccountBeforeTx, StorageSettings, StoredBlockBodyIndices},
28};
29use reth_ethereum_primitives::EthPrimitives;
30use reth_execution_types::{ExecutionOutcome, RecoveredBlockAndExecutionOutput};
31use reth_primitives_traits::{
32    Account, Block, BlockBody, Bytecode, GotExpected, NodePrimitives, RecoveredBlock, SealedHeader,
33    SignerRecoverable, StorageEntry,
34};
35use reth_prune_types::{PruneCheckpoint, PruneModes, PruneSegment};
36use reth_stages_types::{StageCheckpoint, StageId};
37use reth_storage_api::{
38    BlockBodyIndicesProvider, BytecodeReader, DBProvider, DatabaseProviderFactory, DbTxProvider,
39    HashedPostStateProvider, HistoryInfo, HistoryReader, NodePrimitivesProvider,
40    StageCheckpointReader, StateProofProvider, StorageChangeSetReader, StorageRootProvider,
41    StorageSettingsCache,
42};
43use reth_storage_errors::provider::{ConsistentViewError, ProviderError, ProviderResult};
44use reth_trie::{
45    updates::TrieUpdates, AccountProof, HashedPostState, HashedStorage, MultiProof,
46    MultiProofTargets, StorageMultiProof, StorageProof, TrieInput,
47};
48use std::{
49    collections::{BTreeMap, VecDeque},
50    fmt::Debug,
51    ops::{RangeBounds, RangeInclusive},
52    sync::{
53        atomic::{AtomicBool, AtomicUsize, Ordering},
54        Arc,
55    },
56};
57use tokio::sync::broadcast;
58
59/// A mock implementation for Provider interfaces.
60#[derive(Debug)]
61pub struct MockEthProvider<T: NodePrimitives = EthPrimitives, ChainSpec = reth_chainspec::ChainSpec>
62{
63    ///local block store
64    pub blocks: Arc<Mutex<B256Map<T::Block>>>,
65    /// Local header store
66    pub headers: Arc<Mutex<B256Map<<T::Block as Block>::Header>>>,
67    /// Local receipt store indexed by block number
68    pub receipts: Arc<Mutex<HashMap<BlockNumber, Vec<T::Receipt>>>>,
69    /// Local account store
70    pub accounts: Arc<Mutex<AddressMap<ExtendedAccount>>>,
71    /// Local chain spec
72    pub chain_spec: Arc<ChainSpec>,
73    /// Local state roots
74    pub state_roots: Arc<Mutex<Vec<B256>>>,
75    /// Local block body indices store
76    pub block_body_indices: Arc<Mutex<HashMap<BlockNumber, StoredBlockBodyIndices>>>,
77    /// Local stage checkpoints
78    stage_checkpoints: Arc<Mutex<HashMap<StageId, StageCheckpoint>>>,
79    /// The engine's pending block, if any
80    pending_block_num_hash: Arc<Mutex<Option<BlockNumHash>>>,
81    /// Local BAL store handle
82    pub bal_store: BalStoreHandle,
83    /// Whether database provider creation succeeds.
84    database_provider_available: Arc<AtomicBool>,
85    /// Whether snap state reads should fail for handler error-path tests.
86    snap_state_reads_fail: Arc<AtomicBool>,
87    /// Whether a snap state range view is available.
88    snap_state_range_available: Arc<AtomicBool>,
89    /// Number of snap state range view resolutions.
90    snap_state_range_resolutions: Arc<AtomicUsize>,
91    /// Account range returned to snap handler tests.
92    snap_account_range: Arc<Mutex<MockAccountRange>>,
93    /// Storage roots returned to snap handler tests, keyed by hashed address.
94    snap_storage_roots: Arc<Mutex<B256Map<B256>>>,
95    /// Storage ranges returned to snap handler tests.
96    snap_storage_ranges: Arc<Mutex<VecDeque<MockStorageRangeOutcome>>>,
97    /// Storage range requests observed by snap handler tests.
98    snap_storage_range_requests: Arc<Mutex<Vec<MockStorageRangeRequest>>>,
99    /// Account proof returned to snap handler tests.
100    snap_account_proof: Arc<Mutex<Option<Vec<Bytes>>>>,
101    /// Storage proof returned to snap handler tests.
102    snap_storage_proof: Arc<Mutex<Option<Vec<Bytes>>>>,
103    tx: TxMock,
104    prune_modes: Arc<PruneModes>,
105}
106
107/// Optional mock account entries paired with why the range ended.
108type MockAccountRange = Option<(Vec<(B256, Account)>, RangeEnd)>;
109/// Outcome of a queued mock `storage_range` call.
110#[derive(Debug, Clone)]
111enum MockStorageRangeOutcome {
112    /// The provider fails this call (e.g. simulating a database error).
113    Error,
114    /// The requested account isn't present in the pinned state.
115    AccountMissing,
116    /// The account is present; these are its slots and why the range ended.
117    Found(Vec<(B256, U256)>, RangeEnd),
118}
119/// Hashed address, origin, limit, and byte budget of a mock storage range request.
120type MockStorageRangeRequest = (B256, B256, B256, usize);
121
122impl<T: NodePrimitives, ChainSpec> Clone for MockEthProvider<T, ChainSpec>
123where
124    T::Block: Clone,
125{
126    fn clone(&self) -> Self {
127        Self {
128            blocks: self.blocks.clone(),
129            headers: self.headers.clone(),
130            receipts: self.receipts.clone(),
131            accounts: self.accounts.clone(),
132            chain_spec: self.chain_spec.clone(),
133            state_roots: self.state_roots.clone(),
134            block_body_indices: self.block_body_indices.clone(),
135            stage_checkpoints: self.stage_checkpoints.clone(),
136            pending_block_num_hash: self.pending_block_num_hash.clone(),
137            bal_store: self.bal_store.clone(),
138            database_provider_available: self.database_provider_available.clone(),
139            snap_state_reads_fail: self.snap_state_reads_fail.clone(),
140            snap_state_range_available: self.snap_state_range_available.clone(),
141            snap_state_range_resolutions: self.snap_state_range_resolutions.clone(),
142            snap_account_range: self.snap_account_range.clone(),
143            snap_storage_roots: self.snap_storage_roots.clone(),
144            snap_storage_ranges: self.snap_storage_ranges.clone(),
145            snap_storage_range_requests: self.snap_storage_range_requests.clone(),
146            snap_account_proof: self.snap_account_proof.clone(),
147            snap_storage_proof: self.snap_storage_proof.clone(),
148            tx: self.tx.clone(),
149            prune_modes: self.prune_modes.clone(),
150        }
151    }
152}
153
154impl<T: NodePrimitives> MockEthProvider<T, reth_chainspec::ChainSpec> {
155    /// Create a new, empty instance
156    pub fn new() -> Self {
157        Self {
158            blocks: Default::default(),
159            headers: Default::default(),
160            receipts: Default::default(),
161            accounts: Default::default(),
162            chain_spec: Arc::new(reth_chainspec::ChainSpecBuilder::mainnet().build()),
163            state_roots: Default::default(),
164            block_body_indices: Default::default(),
165            stage_checkpoints: Default::default(),
166            pending_block_num_hash: Default::default(),
167            bal_store: Default::default(),
168            database_provider_available: Default::default(),
169            snap_state_reads_fail: Default::default(),
170            snap_state_range_available: Default::default(),
171            snap_state_range_resolutions: Default::default(),
172            snap_account_range: Default::default(),
173            snap_storage_roots: Default::default(),
174            snap_storage_ranges: Default::default(),
175            snap_storage_range_requests: Default::default(),
176            snap_account_proof: Default::default(),
177            snap_storage_proof: Default::default(),
178            tx: Default::default(),
179            prune_modes: Default::default(),
180        }
181    }
182}
183
184impl<T: NodePrimitives, ChainSpec> MockEthProvider<T, ChainSpec> {
185    /// Allows database provider creation to return this mock.
186    pub fn enable_database_provider(&self) {
187        self.database_provider_available.store(true, Ordering::Relaxed);
188    }
189
190    /// Makes snap state reads return provider errors when `fail` is true.
191    pub fn set_snap_state_reads_fail(&self, fail: bool) {
192        self.snap_state_reads_fail.store(fail, Ordering::Relaxed);
193    }
194
195    /// Sets the available account range returned to snap handler tests.
196    pub fn set_snap_account_range(&self, accounts: Vec<(B256, Account)>, end: RangeEnd) {
197        self.snap_state_range_available.store(true, Ordering::Relaxed);
198        *self.snap_account_range.lock() = Some((accounts, end));
199    }
200
201    /// Sets an account's storage root for snap handler tests.
202    pub fn set_snap_storage_root(&self, hashed_address: B256, storage_root: B256) {
203        self.snap_storage_roots.lock().insert(hashed_address, storage_root);
204    }
205
206    /// Adds an available storage range for the next snap handler call.
207    pub fn push_snap_storage_range(&self, slots: Vec<(B256, U256)>, end: RangeEnd) {
208        self.snap_state_range_available.store(true, Ordering::Relaxed);
209        self.snap_storage_ranges.lock().push_back(MockStorageRangeOutcome::Found(slots, end));
210    }
211
212    /// Marks the account for the next snap handler call as absent from the pinned state.
213    pub fn push_missing_snap_storage_account(&self) {
214        self.snap_state_range_available.store(true, Ordering::Relaxed);
215        self.snap_storage_ranges.lock().push_back(MockStorageRangeOutcome::AccountMissing);
216    }
217
218    /// Adds an unavailable storage range for the next snap handler call.
219    pub fn push_unavailable_snap_storage_range(&self) {
220        self.snap_state_range_available.store(true, Ordering::Relaxed);
221        self.snap_storage_ranges.lock().push_back(MockStorageRangeOutcome::Error);
222    }
223
224    /// Returns the number of queued storage ranges for snap handler tests.
225    pub fn snap_storage_ranges_remaining(&self) -> usize {
226        self.snap_storage_ranges.lock().len()
227    }
228
229    /// Returns the storage range requests observed by snap handler tests.
230    pub fn snap_storage_range_requests(&self) -> Vec<(B256, B256, B256, usize)> {
231        self.snap_storage_range_requests.lock().clone()
232    }
233
234    /// Returns the number of snap state range view resolutions.
235    pub fn snap_state_range_resolutions(&self) -> usize {
236        self.snap_state_range_resolutions.load(Ordering::Relaxed)
237    }
238
239    /// Sets the account proof returned to snap handler tests.
240    pub fn set_snap_account_proof(&self, proof: Option<Vec<Bytes>>) {
241        *self.snap_account_proof.lock() = proof;
242    }
243
244    /// Sets the storage proof returned to snap handler tests.
245    pub fn set_snap_storage_proof(&self, proof: Option<Vec<Bytes>>) {
246        *self.snap_storage_proof.lock() = proof;
247    }
248
249    fn ensure_snap_state_reads_succeed(&self) -> ProviderResult<()> {
250        if self.snap_state_reads_fail.load(Ordering::Relaxed) {
251            return Err(ProviderError::BestBlockNotFound)
252        }
253        Ok(())
254    }
255
256    /// Add block to local block store
257    pub fn add_block(&self, hash: B256, block: T::Block) {
258        self.add_header(hash, block.header().clone());
259        self.blocks.lock().insert(hash, block);
260    }
261
262    /// Add multiple blocks to local block store
263    pub fn extend_blocks(&self, iter: impl IntoIterator<Item = (B256, T::Block)>) {
264        for (hash, block) in iter {
265            self.add_block(hash, block)
266        }
267    }
268
269    /// Add header to local header store
270    pub fn add_header(&self, hash: B256, header: <T::Block as Block>::Header) {
271        self.headers.lock().insert(hash, header);
272    }
273
274    /// Add multiple headers to local header store
275    pub fn extend_headers(
276        &self,
277        iter: impl IntoIterator<Item = (B256, <T::Block as Block>::Header)>,
278    ) {
279        for (hash, header) in iter {
280            self.add_header(hash, header)
281        }
282    }
283
284    /// Add account to local account store
285    pub fn add_account(&self, address: Address, account: ExtendedAccount) {
286        self.accounts.lock().insert(address, account);
287    }
288
289    /// Add account to local account store
290    pub fn extend_accounts(&self, iter: impl IntoIterator<Item = (Address, ExtendedAccount)>) {
291        for (address, account) in iter {
292            self.add_account(address, account)
293        }
294    }
295
296    /// Add receipts to local receipt store
297    pub fn add_receipts(&self, block_number: BlockNumber, receipts: Vec<T::Receipt>) {
298        self.receipts.lock().insert(block_number, receipts);
299    }
300
301    /// Add multiple receipts to local receipt store
302    pub fn extend_receipts(&self, iter: impl IntoIterator<Item = (BlockNumber, Vec<T::Receipt>)>) {
303        for (block_number, receipts) in iter {
304            self.add_receipts(block_number, receipts);
305        }
306    }
307
308    /// Add block body indices to local store
309    pub fn add_block_body_indices(
310        &self,
311        block_number: BlockNumber,
312        indices: StoredBlockBodyIndices,
313    ) {
314        self.block_body_indices.lock().insert(block_number, indices);
315    }
316
317    /// Adds a stage checkpoint to the local store.
318    pub fn add_stage_checkpoint(&self, id: StageId, checkpoint: StageCheckpoint) {
319        self.stage_checkpoints.lock().insert(id, checkpoint);
320    }
321
322    /// Sets the pending block the engine holds
323    pub fn set_pending_block_num_hash(&self, num_hash: Option<BlockNumHash>) {
324        *self.pending_block_num_hash.lock() = num_hash;
325    }
326
327    /// Add state root to local state root store
328    pub fn add_state_root(&self, state_root: B256) {
329        self.state_roots.lock().push(state_root);
330    }
331
332    /// Set chain spec.
333    pub fn with_chain_spec<C>(self, chain_spec: C) -> MockEthProvider<T, C> {
334        MockEthProvider {
335            blocks: self.blocks,
336            headers: self.headers,
337            receipts: self.receipts,
338            accounts: self.accounts,
339            chain_spec: Arc::new(chain_spec),
340            state_roots: self.state_roots,
341            block_body_indices: self.block_body_indices,
342            stage_checkpoints: self.stage_checkpoints,
343            pending_block_num_hash: self.pending_block_num_hash,
344            bal_store: self.bal_store,
345            database_provider_available: self.database_provider_available,
346            snap_state_reads_fail: self.snap_state_reads_fail,
347            snap_state_range_available: self.snap_state_range_available,
348            snap_state_range_resolutions: self.snap_state_range_resolutions,
349            snap_account_range: self.snap_account_range,
350            snap_storage_roots: self.snap_storage_roots,
351            snap_storage_ranges: self.snap_storage_ranges,
352            snap_storage_range_requests: self.snap_storage_range_requests,
353            snap_account_proof: self.snap_account_proof,
354            snap_storage_proof: self.snap_storage_proof,
355            tx: self.tx,
356            prune_modes: self.prune_modes,
357        }
358    }
359
360    /// Adds the genesis block from the chain spec to the provider.
361    ///
362    /// This is useful for tests that require a valid latest block (e.g., transaction validation).
363    pub fn with_genesis_block(self) -> Self
364    where
365        ChainSpec: EthChainSpec<Header = <T::Block as Block>::Header>,
366        <T::Block as Block>::Body: Default,
367    {
368        let genesis_hash = self.chain_spec.genesis_hash();
369        let genesis_header = self.chain_spec.genesis_header().clone();
370        let genesis_block = T::Block::new(genesis_header, Default::default());
371        self.add_block(genesis_hash, genesis_block);
372        self
373    }
374}
375
376impl Default for MockEthProvider {
377    fn default() -> Self {
378        Self::new()
379    }
380}
381
382impl<T: NodePrimitives, ChainSpec> BalProvider for MockEthProvider<T, ChainSpec> {
383    fn bal_store(&self) -> &BalStoreHandle {
384        &self.bal_store
385    }
386}
387
388impl<T, ChainSpec> StateRangeProviderFactory for MockEthProvider<T, ChainSpec>
389where
390    T: NodePrimitives,
391    T::Block: Clone,
392    ChainSpec: Send + Sync + 'static,
393{
394    fn state_range_provider(&self, _state_root: B256) -> ProviderResult<Option<StateRangeView>> {
395        self.snap_state_range_resolutions.fetch_add(1, Ordering::Relaxed);
396        self.ensure_snap_state_reads_succeed()?;
397        if !self.snap_state_range_available.load(Ordering::Relaxed) {
398            return Ok(None)
399        }
400        Ok(Some(Box::new(self.clone())))
401    }
402}
403
404impl<T: NodePrimitives, ChainSpec> StateRangeProvider for MockEthProvider<T, ChainSpec> {
405    fn account_range(
406        &self,
407        _start: B256,
408        _limit: B256,
409        _response_bytes: usize,
410    ) -> RangeResult<(B256, Account)> {
411        self.ensure_snap_state_reads_succeed()?;
412        let (items, end) =
413            self.snap_account_range.lock().clone().ok_or(ProviderError::BestBlockNotFound)?;
414        Ok(RangeResponse { items, end })
415    }
416
417    fn storage_root_by_hash(&self, hashed_address: B256) -> ProviderResult<B256> {
418        self.ensure_snap_state_reads_succeed()?;
419        self.snap_storage_roots
420            .lock()
421            .get(&hashed_address)
422            .copied()
423            .ok_or(ProviderError::BestBlockNotFound)
424    }
425
426    fn storage_range(
427        &self,
428        hashed_address: B256,
429        start: B256,
430        limit: B256,
431        response_bytes: usize,
432    ) -> StorageRangeResult {
433        self.ensure_snap_state_reads_succeed()?;
434        self.snap_storage_range_requests.lock().push((
435            hashed_address,
436            start,
437            limit,
438            response_bytes,
439        ));
440        let outcome =
441            self.snap_storage_ranges.lock().pop_front().ok_or(ProviderError::BestBlockNotFound)?;
442        match outcome {
443            MockStorageRangeOutcome::Error => Err(ProviderError::BestBlockNotFound),
444            MockStorageRangeOutcome::AccountMissing => Ok(None),
445            MockStorageRangeOutcome::Found(items, end) => Ok(Some(RangeResponse { items, end })),
446        }
447    }
448
449    fn account_range_proof(&self, _keys: &[B256]) -> ProviderResult<Vec<Bytes>> {
450        self.ensure_snap_state_reads_succeed()?;
451        self.snap_account_proof.lock().clone().ok_or(ProviderError::BestBlockNotFound)
452    }
453
454    fn storage_range_proof(
455        &self,
456        _hashed_address: B256,
457        _keys: &[B256],
458    ) -> ProviderResult<Vec<Bytes>> {
459        self.ensure_snap_state_reads_succeed()?;
460        self.snap_storage_proof.lock().clone().ok_or(ProviderError::BestBlockNotFound)
461    }
462}
463
464/// An extended account for local store
465#[derive(Debug, Clone)]
466pub struct ExtendedAccount {
467    account: Account,
468    bytecode: Option<Bytecode>,
469    storage: HashMap<StorageKey, StorageValue>,
470}
471
472impl ExtendedAccount {
473    /// Create new instance of extended account
474    pub fn new(nonce: u64, balance: U256) -> Self {
475        Self {
476            account: Account { nonce, balance, ..Default::default() },
477            bytecode: None,
478            storage: Default::default(),
479        }
480    }
481
482    /// Set bytecode and bytecode hash on the extended account
483    pub fn with_bytecode(mut self, bytecode: Bytes) -> Self {
484        let hash = keccak256(&bytecode);
485        self.account.bytecode_hash = Some(hash);
486        self.bytecode = Some(Bytecode::new_raw(bytecode));
487        self
488    }
489
490    /// Add storage to the extended account. If the storage key is already present,
491    /// the value is updated.
492    pub fn extend_storage(
493        mut self,
494        storage: impl IntoIterator<Item = (StorageKey, StorageValue)>,
495    ) -> Self {
496        self.storage.extend(storage);
497        self
498    }
499
500    /// Sets the account extension.
501    #[cfg(feature = "account-ext")]
502    pub fn with_extension(
503        mut self,
504        extension: impl Into<reth_primitives_traits::AccountExtension>,
505    ) -> Self {
506        self.account.extension = extension.into();
507        self
508    }
509}
510
511impl<T: NodePrimitives, ChainSpec: EthChainSpec + Clone + 'static> DatabaseProviderFactory
512    for MockEthProvider<T, ChainSpec>
513{
514    type DB = DatabaseMock;
515    type Provider = Self;
516    type ProviderRW = Self;
517
518    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
519        if self.database_provider_available.load(Ordering::Relaxed) {
520            Ok(self.clone())
521        } else {
522            Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
523        }
524    }
525
526    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
527        if self.database_provider_available.load(Ordering::Relaxed) {
528            Ok(self.clone())
529        } else {
530            Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
531        }
532    }
533}
534
535impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HistoryReader
536    for MockEthProvider<T, ChainSpec>
537{
538    fn account_history_info(
539        &self,
540        _address: Address,
541        _block_number: BlockNumber,
542        _lowest_available_block_number: Option<BlockNumber>,
543    ) -> ProviderResult<HistoryInfo> {
544        Ok(HistoryInfo::InPlainState)
545    }
546
547    fn storage_history_info(
548        &self,
549        _address: Address,
550        _storage_key: B256,
551        _block_number: BlockNumber,
552        _lowest_available_block_number: Option<BlockNumber>,
553    ) -> ProviderResult<HistoryInfo> {
554        Ok(HistoryInfo::InPlainState)
555    }
556}
557
558impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DbTxProvider
559    for MockEthProvider<T, ChainSpec>
560{
561    type Tx = TxMock;
562
563    fn tx(&self) -> &Self::Tx {
564        &self.tx
565    }
566}
567
568impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DBProvider
569    for MockEthProvider<T, ChainSpec>
570{
571    fn tx_mut(&mut self) -> &mut Self::Tx {
572        &mut self.tx
573    }
574
575    fn into_tx(self) -> Self::Tx {
576        self.tx
577    }
578
579    fn commit(self) -> ProviderResult<()> {
580        Ok(self.tx.commit()?)
581    }
582
583    fn prune_modes_ref(&self) -> &PruneModes {
584        &self.prune_modes
585    }
586}
587
588impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> HeaderProvider
589    for MockEthProvider<T, ChainSpec>
590{
591    type Header = <T::Block as Block>::Header;
592
593    fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
594        let lock = self.headers.lock();
595        Ok(lock.get(&block_hash).cloned())
596    }
597
598    fn header_by_number(&self, num: u64) -> ProviderResult<Option<Self::Header>> {
599        let lock = self.headers.lock();
600        Ok(lock.values().find(|h| h.number() == num).cloned())
601    }
602
603    fn headers_range(
604        &self,
605        range: impl RangeBounds<BlockNumber>,
606    ) -> ProviderResult<Vec<Self::Header>> {
607        let lock = self.headers.lock();
608
609        let mut headers: Vec<_> =
610            lock.values().filter(|header| range.contains(&header.number())).cloned().collect();
611        headers.sort_by_key(|header| header.number());
612
613        Ok(headers)
614    }
615
616    fn sealed_header(
617        &self,
618        number: BlockNumber,
619    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
620        Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
621    }
622
623    fn sealed_headers_while(
624        &self,
625        range: impl RangeBounds<BlockNumber>,
626        mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
627    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
628        Ok(self
629            .headers_range(range)?
630            .into_iter()
631            .map(SealedHeader::seal_slow)
632            .take_while(|h| predicate(h))
633            .collect())
634    }
635}
636
637impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
638where
639    T: NodePrimitives,
640    ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
641{
642    type ChainSpec = ChainSpec;
643
644    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
645        self.chain_spec.clone()
646    }
647}
648
649impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> TransactionsProvider
650    for MockEthProvider<T, ChainSpec>
651{
652    type Transaction = T::SignedTx;
653
654    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
655        let lock = self.blocks.lock();
656        let tx_number = lock
657            .values()
658            .flat_map(|block| block.body().transactions())
659            .position(|tx| *tx.tx_hash() == tx_hash)
660            .map(|pos| pos as TxNumber);
661
662        Ok(tx_number)
663    }
664
665    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
666        let lock = self.blocks.lock();
667        let transaction =
668            lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
669
670        Ok(transaction)
671    }
672
673    fn transaction_by_id_unhashed(
674        &self,
675        id: TxNumber,
676    ) -> ProviderResult<Option<Self::Transaction>> {
677        let lock = self.blocks.lock();
678        let transaction =
679            lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
680
681        Ok(transaction)
682    }
683
684    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
685        Ok(self.blocks.lock().iter().find_map(|(_, block)| {
686            block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned()
687        }))
688    }
689
690    fn transaction_by_hash_with_meta(
691        &self,
692        hash: TxHash,
693    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
694        let lock = self.blocks.lock();
695        for (block_hash, block) in lock.iter() {
696            for (index, tx) in block.body().transactions_iter().enumerate() {
697                if *tx.tx_hash() == hash {
698                    let meta = TransactionMeta {
699                        tx_hash: hash,
700                        index: index as u64,
701                        block_hash: *block_hash,
702                        block_number: block.header().number(),
703                        base_fee: block.header().base_fee_per_gas(),
704                        excess_blob_gas: block.header().excess_blob_gas(),
705                        timestamp: block.header().timestamp(),
706                    };
707                    return Ok(Some((tx.clone(), meta)))
708                }
709            }
710        }
711        Ok(None)
712    }
713
714    fn transactions_by_block(
715        &self,
716        id: BlockHashOrNumber,
717    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
718        Ok(self.block(id)?.map(|b| b.body().clone_transactions()))
719    }
720
721    fn transactions_by_block_range(
722        &self,
723        range: impl RangeBounds<alloy_primitives::BlockNumber>,
724    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
725        // init btreemap so we can return in order
726        let mut map = BTreeMap::new();
727        for block in self.blocks.lock().values() {
728            if range.contains(&block.header().number()) {
729                map.insert(block.header().number(), block.body().clone_transactions());
730            }
731        }
732
733        Ok(map.into_values().collect())
734    }
735
736    fn transactions_by_tx_range(
737        &self,
738        range: impl RangeBounds<TxNumber>,
739    ) -> ProviderResult<Vec<Self::Transaction>> {
740        let lock = self.blocks.lock();
741        let transactions = lock
742            .values()
743            .flat_map(|block| block.body().transactions())
744            .enumerate()
745            .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
746            .map(|(_, tx)| tx.clone())
747            .collect();
748
749        Ok(transactions)
750    }
751
752    fn senders_by_tx_range(
753        &self,
754        range: impl RangeBounds<TxNumber>,
755    ) -> ProviderResult<Vec<Address>> {
756        let lock = self.blocks.lock();
757        let transactions = lock
758            .values()
759            .flat_map(|block| block.body().transactions())
760            .enumerate()
761            .filter_map(|(tx_number, tx)| {
762                if range.contains(&(tx_number as TxNumber)) {
763                    tx.recover_signer().ok()
764                } else {
765                    None
766                }
767            })
768            .collect();
769
770        Ok(transactions)
771    }
772
773    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
774        self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
775    }
776}
777
778impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
779where
780    T: NodePrimitives,
781    ChainSpec: Send + Sync + 'static,
782{
783    type Receipt = T::Receipt;
784
785    fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
786        Ok(None)
787    }
788
789    fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
790        Ok(None)
791    }
792
793    fn receipts_by_block(
794        &self,
795        block: BlockHashOrNumber,
796    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
797        let receipts_lock = self.receipts.lock();
798
799        match block {
800            BlockHashOrNumber::Hash(hash) => {
801                // Find block number by hash first
802                let headers_lock = self.headers.lock();
803                if let Some(header) = headers_lock.get(&hash) {
804                    Ok(receipts_lock.get(&header.number()).cloned())
805                } else {
806                    Ok(None)
807                }
808            }
809            BlockHashOrNumber::Number(number) => Ok(receipts_lock.get(&number).cloned()),
810        }
811    }
812
813    fn receipts_by_tx_range(
814        &self,
815        _range: impl RangeBounds<TxNumber>,
816    ) -> ProviderResult<Vec<Self::Receipt>> {
817        Ok(vec![])
818    }
819
820    fn receipts_by_block_range(
821        &self,
822        block_range: RangeInclusive<BlockNumber>,
823    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
824        let receipts_lock = self.receipts.lock();
825        let headers_lock = self.headers.lock();
826
827        let mut result = Vec::new();
828        for block_number in block_range {
829            // Only include blocks that exist in headers (i.e., have been added to the provider)
830            if headers_lock.values().any(|header| header.number() == block_number) {
831                if let Some(block_receipts) = receipts_lock.get(&block_number) {
832                    result.push(block_receipts.clone());
833                } else {
834                    // If block exists but no receipts found, add empty vec
835                    result.push(vec![]);
836                }
837            }
838        }
839
840        Ok(result)
841    }
842}
843
844impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
845where
846    T: NodePrimitives,
847    Self: ReceiptProvider + BlockIdReader,
848{
849}
850
851impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
852    for MockEthProvider<T, ChainSpec>
853{
854    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
855        let lock = self.headers.lock();
856        let hash =
857            lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash));
858        Ok(hash)
859    }
860
861    fn canonical_hashes_range(
862        &self,
863        start: BlockNumber,
864        end: BlockNumber,
865    ) -> ProviderResult<Vec<B256>> {
866        let lock = self.headers.lock();
867        let mut hashes: Vec<_> =
868            lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect();
869
870        hashes.sort_by_key(|(_, header)| header.number());
871
872        Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
873    }
874}
875
876impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
877    for MockEthProvider<T, ChainSpec>
878{
879    fn chain_info(&self) -> ProviderResult<ChainInfo> {
880        let best_block_number = self.best_block_number()?;
881        let lock = self.headers.lock();
882
883        Ok(lock
884            .iter()
885            .find(|(_, header)| header.number() == best_block_number)
886            .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() })
887            .unwrap_or_default())
888    }
889
890    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
891        let lock = self.headers.lock();
892        lock.iter()
893            .max_by_key(|h| h.1.number())
894            .map(|(_, header)| header.number())
895            .ok_or(ProviderError::BestBlockNotFound)
896    }
897
898    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
899        self.best_block_number()
900    }
901
902    fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
903        let lock = self.headers.lock();
904        Ok(lock.get(&hash).map(|header| header.number()))
905    }
906}
907
908impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
909    for MockEthProvider<T, ChainSpec>
910{
911    fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
912        Ok(*self.pending_block_num_hash.lock())
913    }
914
915    fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
916        Ok(None)
917    }
918
919    fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
920        Ok(None)
921    }
922}
923
924//look
925impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
926    for MockEthProvider<T, ChainSpec>
927{
928    type Block = T::Block;
929
930    fn find_block_by_hash(
931        &self,
932        hash: B256,
933        _source: BlockSource,
934    ) -> ProviderResult<Option<Self::Block>> {
935        self.block(hash.into())
936    }
937
938    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
939        let lock = self.blocks.lock();
940        match id {
941            BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
942            BlockHashOrNumber::Number(num) => {
943                Ok(lock.values().find(|b| b.header().number() == num).cloned())
944            }
945        }
946    }
947
948    fn pending_block(&self) -> ProviderResult<Option<Arc<RecoveredBlock<Self::Block>>>> {
949        Ok(None)
950    }
951
952    fn pending_block_and_receipts(
953        &self,
954    ) -> ProviderResult<Option<RecoveredBlockAndExecutionOutput<Self::Block, T::Receipt>>> {
955        Ok(None)
956    }
957
958    fn recovered_block(
959        &self,
960        id: BlockHashOrNumber,
961        _transaction_kind: TransactionVariant,
962    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
963        self.block(id)?
964            .map(|block| block.try_into_recovered().map_err(ProviderError::other))
965            .transpose()
966    }
967
968    fn sealed_block_with_senders(
969        &self,
970        id: BlockHashOrNumber,
971        transaction_kind: TransactionVariant,
972    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
973        self.recovered_block(id, transaction_kind)
974    }
975
976    fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
977        let lock = self.blocks.lock();
978
979        let mut blocks: Vec<_> = lock
980            .values()
981            .filter(|block| range.contains(&block.header().number()))
982            .cloned()
983            .collect();
984        blocks.sort_by_key(|block| block.header().number());
985
986        Ok(blocks)
987    }
988
989    fn block_with_senders_range(
990        &self,
991        _range: RangeInclusive<BlockNumber>,
992    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
993        Ok(vec![])
994    }
995
996    fn recovered_block_range(
997        &self,
998        _range: RangeInclusive<BlockNumber>,
999    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
1000        Ok(vec![])
1001    }
1002
1003    fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
1004        Ok(None)
1005    }
1006}
1007
1008impl<T, ChainSpec> BlockReaderIdExt for MockEthProvider<T, ChainSpec>
1009where
1010    ChainSpec: EthChainSpec + Send + Sync + 'static,
1011    T: NodePrimitives,
1012{
1013    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<T::Block>> {
1014        match id {
1015            BlockId::Number(num) => self.block_by_number_or_tag(num),
1016            BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
1017        }
1018    }
1019
1020    fn sealed_header_by_id(
1021        &self,
1022        id: BlockId,
1023    ) -> ProviderResult<Option<SealedHeader<<T::Block as Block>::Header>>> {
1024        self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
1025    }
1026
1027    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<<T::Block as Block>::Header>> {
1028        match self.block_by_id(id)? {
1029            None => Ok(None),
1030            Some(block) => Ok(Some(block.into_header())),
1031        }
1032    }
1033}
1034
1035impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
1036    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
1037        Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
1038    }
1039}
1040
1041impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
1042    for MockEthProvider<T, ChainSpec>
1043{
1044    fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
1045        Ok(self.stage_checkpoints.lock().get(&id).copied())
1046    }
1047
1048    fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
1049        Ok(None)
1050    }
1051
1052    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
1053        Ok(self
1054            .stage_checkpoints
1055            .lock()
1056            .iter()
1057            .map(|(id, checkpoint)| (id.to_string(), *checkpoint))
1058            .collect())
1059    }
1060}
1061
1062impl<T: NodePrimitives, ChainSpec: Send + Sync> PruneCheckpointReader
1063    for MockEthProvider<T, ChainSpec>
1064{
1065    fn get_prune_checkpoint(
1066        &self,
1067        _segment: PruneSegment,
1068    ) -> ProviderResult<Option<PruneCheckpoint>> {
1069        Ok(None)
1070    }
1071
1072    fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
1073        Ok(vec![])
1074    }
1075}
1076
1077impl<T, ChainSpec> StateRootProvider for MockEthProvider<T, ChainSpec>
1078where
1079    T: NodePrimitives,
1080    ChainSpec: Send + Sync,
1081{
1082    fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
1083        Ok(self.state_roots.lock().pop().unwrap_or_default())
1084    }
1085
1086    fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1087        Ok(self.state_roots.lock().pop().unwrap_or_default())
1088    }
1089
1090    fn state_root_with_updates(
1091        &self,
1092        _state: HashedPostState,
1093    ) -> ProviderResult<(B256, TrieUpdates)> {
1094        let state_root = self.state_roots.lock().pop().unwrap_or_default();
1095        Ok((state_root, Default::default()))
1096    }
1097
1098    fn state_root_from_nodes_with_updates(
1099        &self,
1100        _input: TrieInput,
1101    ) -> ProviderResult<(B256, TrieUpdates)> {
1102        let state_root = self.state_roots.lock().pop().unwrap_or_default();
1103        Ok((state_root, Default::default()))
1104    }
1105}
1106
1107impl<T, ChainSpec> StorageRootProvider for MockEthProvider<T, ChainSpec>
1108where
1109    T: NodePrimitives,
1110    ChainSpec: Send + Sync,
1111{
1112    fn storage_root(
1113        &self,
1114        _address: Address,
1115        _hashed_storage: HashedStorage,
1116    ) -> ProviderResult<B256> {
1117        Ok(EMPTY_ROOT_HASH)
1118    }
1119
1120    fn storage_proof(
1121        &self,
1122        _address: Address,
1123        slot: B256,
1124        _hashed_storage: HashedStorage,
1125    ) -> ProviderResult<reth_trie::StorageProof> {
1126        Ok(StorageProof::new(slot))
1127    }
1128
1129    fn storage_multiproof(
1130        &self,
1131        _address: Address,
1132        _slots: &[B256],
1133        _hashed_storage: HashedStorage,
1134    ) -> ProviderResult<StorageMultiProof> {
1135        Ok(StorageMultiProof::empty())
1136    }
1137}
1138
1139impl<T, ChainSpec> StateProofProvider for MockEthProvider<T, ChainSpec>
1140where
1141    T: NodePrimitives,
1142    ChainSpec: Send + Sync,
1143{
1144    fn proof(
1145        &self,
1146        _input: TrieInput,
1147        address: Address,
1148        _slots: &[B256],
1149    ) -> ProviderResult<AccountProof> {
1150        Ok(AccountProof::new(address))
1151    }
1152
1153    fn multiproof(
1154        &self,
1155        _input: TrieInput,
1156        _targets: MultiProofTargets,
1157    ) -> ProviderResult<MultiProof> {
1158        Ok(MultiProof::default())
1159    }
1160
1161    fn multiproof_v2(
1162        &self,
1163        _input: TrieInput,
1164        _targets: reth_trie::MultiProofTargetsV2,
1165    ) -> ProviderResult<reth_trie::DecodedMultiProofV2> {
1166        Ok(reth_trie::DecodedMultiProofV2::default())
1167    }
1168
1169    fn witness(
1170        &self,
1171        _input: TrieInput,
1172        _target: HashedPostState,
1173        _mode: reth_trie::ExecutionWitnessMode,
1174    ) -> ProviderResult<Vec<Bytes>> {
1175        Ok(Vec::default())
1176    }
1177}
1178
1179impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HashedPostStateProvider
1180    for MockEthProvider<T, ChainSpec>
1181{
1182    fn hashed_post_state(
1183        &self,
1184        _bundle_state: &revm::database::BundleState,
1185    ) -> ProviderResult<HashedPostState> {
1186        Ok(HashedPostState::default())
1187    }
1188}
1189
1190impl<T, ChainSpec> StateProvider for MockEthProvider<T, ChainSpec>
1191where
1192    T: NodePrimitives,
1193    ChainSpec: EthChainSpec + Send + Sync + 'static,
1194{
1195    fn storage(
1196        &self,
1197        account: Address,
1198        storage_key: StorageKey,
1199    ) -> ProviderResult<Option<StorageValue>> {
1200        let lock = self.accounts.lock();
1201        Ok(lock.get(&account).and_then(|account| account.storage.get(&storage_key)).copied())
1202    }
1203}
1204
1205impl<T, ChainSpec> BytecodeReader for MockEthProvider<T, ChainSpec>
1206where
1207    T: NodePrimitives,
1208    ChainSpec: Send + Sync,
1209{
1210    fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
1211        let lock = self.accounts.lock();
1212        Ok(lock.values().find_map(|account| {
1213            match (account.account.bytecode_hash.as_ref(), account.bytecode.as_ref()) {
1214                (Some(bytecode_hash), Some(bytecode)) if bytecode_hash == code_hash => {
1215                    Some(bytecode.clone())
1216                }
1217                _ => None,
1218            }
1219        }))
1220    }
1221}
1222
1223impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageSettingsCache
1224    for MockEthProvider<T, ChainSpec>
1225{
1226    fn cached_storage_settings(&self) -> StorageSettings {
1227        StorageSettings::default()
1228    }
1229
1230    fn set_storage_settings_cache(&self, _settings: StorageSettings) {}
1231}
1232
1233impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> StateProviderFactory
1234    for MockEthProvider<T, ChainSpec>
1235{
1236    type Primitives = T;
1237
1238    fn latest(&self) -> ProviderResult<StateProviderBox> {
1239        self.ensure_snap_state_reads_succeed()?;
1240        Ok(Box::new(self.clone()))
1241    }
1242
1243    fn state_with_block_appended(
1244        &self,
1245        _parent_hash: BlockHash,
1246        _block: ExecutedBlock<T>,
1247    ) -> ProviderResult<StateProviderBox> {
1248        Err(ProviderError::UnsupportedProvider)
1249    }
1250
1251    fn state_by_block_number_or_tag(
1252        &self,
1253        number_or_tag: BlockNumberOrTag,
1254    ) -> ProviderResult<StateProviderBox> {
1255        match number_or_tag {
1256            BlockNumberOrTag::Latest => self.latest(),
1257            BlockNumberOrTag::Finalized => {
1258                // we can only get the finalized state by hash, not by num
1259                let hash =
1260                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
1261
1262                // only look at historical state
1263                self.history_by_block_hash(hash)
1264            }
1265            BlockNumberOrTag::Safe => {
1266                // we can only get the safe state by hash, not by num
1267                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
1268
1269                self.history_by_block_hash(hash)
1270            }
1271            BlockNumberOrTag::Earliest => {
1272                self.history_by_block_number(self.earliest_block_number()?)
1273            }
1274            BlockNumberOrTag::Pending => self.pending(),
1275            BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
1276        }
1277    }
1278
1279    fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
1280        Ok(Box::new(self.clone()))
1281    }
1282
1283    fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
1284        Ok(Box::new(self.clone()))
1285    }
1286
1287    fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
1288        Ok(Box::new(self.clone()))
1289    }
1290
1291    fn pending(&self) -> ProviderResult<StateProviderBox> {
1292        Ok(Box::new(self.clone()))
1293    }
1294
1295    fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
1296        Ok(Some(Box::new(self.clone())))
1297    }
1298
1299    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
1300        Ok(Some(Box::new(self.clone())))
1301    }
1302}
1303
1304impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
1305    for MockEthProvider<T, ChainSpec>
1306{
1307    fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
1308        Ok(self.block_body_indices.lock().get(&num).copied())
1309    }
1310    fn block_body_indices_range(
1311        &self,
1312        _range: RangeInclusive<BlockNumber>,
1313    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
1314        Ok(vec![])
1315    }
1316}
1317
1318impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
1319    fn account_block_changeset(
1320        &self,
1321        _block_number: BlockNumber,
1322    ) -> ProviderResult<Vec<AccountBeforeTx>> {
1323        Ok(Vec::default())
1324    }
1325
1326    fn get_account_before_block(
1327        &self,
1328        _block_number: BlockNumber,
1329        _address: Address,
1330    ) -> ProviderResult<Option<AccountBeforeTx>> {
1331        Ok(None)
1332    }
1333
1334    fn account_changesets_range(
1335        &self,
1336        _range: impl core::ops::RangeBounds<BlockNumber>,
1337    ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
1338        Ok(Vec::default())
1339    }
1340}
1341
1342impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageChangeSetReader
1343    for MockEthProvider<T, ChainSpec>
1344{
1345    fn storage_changeset(
1346        &self,
1347        _block_number: BlockNumber,
1348    ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1349        Ok(Vec::default())
1350    }
1351
1352    fn get_storage_before_block(
1353        &self,
1354        _block_number: BlockNumber,
1355        _address: Address,
1356        _storage_key: B256,
1357    ) -> ProviderResult<Option<StorageEntry>> {
1358        Ok(None)
1359    }
1360
1361    fn storage_changesets_range(
1362        &self,
1363        _range: impl RangeBounds<BlockNumber>,
1364    ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1365        Ok(Vec::default())
1366    }
1367}
1368
1369impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
1370    type Receipt = T::Receipt;
1371
1372    fn get_state(
1373        &self,
1374        _block: BlockNumber,
1375    ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1376        Ok(None)
1377    }
1378}
1379
1380impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
1381    for MockEthProvider<T, ChainSpec>
1382{
1383    type Primitives = T;
1384
1385    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
1386        broadcast::channel(1).1
1387    }
1388}
1389
1390impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
1391    for MockEthProvider<T, ChainSpec>
1392{
1393    type Primitives = T;
1394}
1395
1396#[cfg(test)]
1397mod tests {
1398    use super::*;
1399    use alloy_consensus::Header;
1400    use alloy_primitives::BlockHash;
1401    use reth_ethereum_primitives::Receipt;
1402
1403    #[test]
1404    fn test_mock_provider_receipts() {
1405        let provider = MockEthProvider::<EthPrimitives>::new();
1406
1407        let block_hash = BlockHash::random();
1408        let block_number = 1u64;
1409        let header = Header { number: block_number, ..Default::default() };
1410
1411        let receipt1 = Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() };
1412        let receipt2 = Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() };
1413        let receipts = vec![receipt1, receipt2];
1414
1415        provider.add_header(block_hash, header);
1416        provider.add_receipts(block_number, receipts.clone());
1417
1418        let result = provider.receipts_by_block(block_hash.into()).unwrap();
1419        assert_eq!(result, Some(receipts.clone()));
1420
1421        let result = provider.receipts_by_block(block_number.into()).unwrap();
1422        assert_eq!(result, Some(receipts.clone()));
1423
1424        let range_result = provider.receipts_by_block_range(1..=1).unwrap();
1425        assert_eq!(range_result, vec![receipts]);
1426
1427        let non_existent = provider.receipts_by_block(BlockHash::random().into()).unwrap();
1428        assert_eq!(non_existent, None);
1429
1430        let empty_range = provider.receipts_by_block_range(10..=20).unwrap();
1431        assert_eq!(empty_range, Vec::<Vec<Receipt>>::new());
1432    }
1433
1434    #[test]
1435    fn test_mock_provider_receipts_multiple_blocks() {
1436        let provider = MockEthProvider::<EthPrimitives>::new();
1437
1438        let block1_hash = BlockHash::random();
1439        let block2_hash = BlockHash::random();
1440        let block1_number = 1u64;
1441        let block2_number = 2u64;
1442
1443        let header1 = Header { number: block1_number, ..Default::default() };
1444        let header2 = Header { number: block2_number, ..Default::default() };
1445
1446        let receipts1 =
1447            vec![Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() }];
1448        let receipts2 =
1449            vec![Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() }];
1450
1451        provider.add_header(block1_hash, header1);
1452        provider.add_header(block2_hash, header2);
1453        provider.add_receipts(block1_number, receipts1.clone());
1454        provider.add_receipts(block2_number, receipts2.clone());
1455
1456        let range_result = provider.receipts_by_block_range(1..=2).unwrap();
1457        assert_eq!(range_result.len(), 2);
1458        assert_eq!(range_result[0], receipts1);
1459        assert_eq!(range_result[1], receipts2);
1460
1461        let partial_range = provider.receipts_by_block_range(1..=1).unwrap();
1462        assert_eq!(partial_range.len(), 1);
1463        assert_eq!(partial_range[0], receipts1);
1464    }
1465}