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};
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;
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, bytecode_hash: None },
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
501impl<T: NodePrimitives, ChainSpec: EthChainSpec + Clone + 'static> DatabaseProviderFactory
502    for MockEthProvider<T, ChainSpec>
503{
504    type DB = DatabaseMock;
505    type Provider = Self;
506    type ProviderRW = Self;
507
508    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
509        if self.database_provider_available.load(Ordering::Relaxed) {
510            Ok(self.clone())
511        } else {
512            Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
513        }
514    }
515
516    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
517        if self.database_provider_available.load(Ordering::Relaxed) {
518            Ok(self.clone())
519        } else {
520            Err(ConsistentViewError::Syncing { best_block: GotExpected::new(0, 0) }.into())
521        }
522    }
523}
524
525impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HistoryReader
526    for MockEthProvider<T, ChainSpec>
527{
528    fn account_history_info(
529        &self,
530        _address: Address,
531        _block_number: BlockNumber,
532        _lowest_available_block_number: Option<BlockNumber>,
533    ) -> ProviderResult<HistoryInfo> {
534        Ok(HistoryInfo::InPlainState)
535    }
536
537    fn storage_history_info(
538        &self,
539        _address: Address,
540        _storage_key: B256,
541        _block_number: BlockNumber,
542        _lowest_available_block_number: Option<BlockNumber>,
543    ) -> ProviderResult<HistoryInfo> {
544        Ok(HistoryInfo::InPlainState)
545    }
546}
547
548impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DbTxProvider
549    for MockEthProvider<T, ChainSpec>
550{
551    type Tx = TxMock;
552
553    fn tx(&self) -> &Self::Tx {
554        &self.tx
555    }
556}
557
558impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> DBProvider
559    for MockEthProvider<T, ChainSpec>
560{
561    fn tx_mut(&mut self) -> &mut Self::Tx {
562        &mut self.tx
563    }
564
565    fn into_tx(self) -> Self::Tx {
566        self.tx
567    }
568
569    fn commit(self) -> ProviderResult<()> {
570        Ok(self.tx.commit()?)
571    }
572
573    fn prune_modes_ref(&self) -> &PruneModes {
574        &self.prune_modes
575    }
576}
577
578impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> HeaderProvider
579    for MockEthProvider<T, ChainSpec>
580{
581    type Header = <T::Block as Block>::Header;
582
583    fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
584        let lock = self.headers.lock();
585        Ok(lock.get(&block_hash).cloned())
586    }
587
588    fn header_by_number(&self, num: u64) -> ProviderResult<Option<Self::Header>> {
589        let lock = self.headers.lock();
590        Ok(lock.values().find(|h| h.number() == num).cloned())
591    }
592
593    fn headers_range(
594        &self,
595        range: impl RangeBounds<BlockNumber>,
596    ) -> ProviderResult<Vec<Self::Header>> {
597        let lock = self.headers.lock();
598
599        let mut headers: Vec<_> =
600            lock.values().filter(|header| range.contains(&header.number())).cloned().collect();
601        headers.sort_by_key(|header| header.number());
602
603        Ok(headers)
604    }
605
606    fn sealed_header(
607        &self,
608        number: BlockNumber,
609    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
610        Ok(self.header_by_number(number)?.map(SealedHeader::seal_slow))
611    }
612
613    fn sealed_headers_while(
614        &self,
615        range: impl RangeBounds<BlockNumber>,
616        mut predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
617    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
618        Ok(self
619            .headers_range(range)?
620            .into_iter()
621            .map(SealedHeader::seal_slow)
622            .take_while(|h| predicate(h))
623            .collect())
624    }
625}
626
627impl<T, ChainSpec> ChainSpecProvider for MockEthProvider<T, ChainSpec>
628where
629    T: NodePrimitives,
630    ChainSpec: EthChainSpec + 'static + Debug + Send + Sync,
631{
632    type ChainSpec = ChainSpec;
633
634    fn chain_spec(&self) -> Arc<Self::ChainSpec> {
635        self.chain_spec.clone()
636    }
637}
638
639impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> TransactionsProvider
640    for MockEthProvider<T, ChainSpec>
641{
642    type Transaction = T::SignedTx;
643
644    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
645        let lock = self.blocks.lock();
646        let tx_number = lock
647            .values()
648            .flat_map(|block| block.body().transactions())
649            .position(|tx| *tx.tx_hash() == tx_hash)
650            .map(|pos| pos as TxNumber);
651
652        Ok(tx_number)
653    }
654
655    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
656        let lock = self.blocks.lock();
657        let transaction =
658            lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
659
660        Ok(transaction)
661    }
662
663    fn transaction_by_id_unhashed(
664        &self,
665        id: TxNumber,
666    ) -> ProviderResult<Option<Self::Transaction>> {
667        let lock = self.blocks.lock();
668        let transaction =
669            lock.values().flat_map(|block| block.body().transactions()).nth(id as usize).cloned();
670
671        Ok(transaction)
672    }
673
674    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
675        Ok(self.blocks.lock().iter().find_map(|(_, block)| {
676            block.body().transactions_iter().find(|tx| *tx.tx_hash() == hash).cloned()
677        }))
678    }
679
680    fn transaction_by_hash_with_meta(
681        &self,
682        hash: TxHash,
683    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
684        let lock = self.blocks.lock();
685        for (block_hash, block) in lock.iter() {
686            for (index, tx) in block.body().transactions_iter().enumerate() {
687                if *tx.tx_hash() == hash {
688                    let meta = TransactionMeta {
689                        tx_hash: hash,
690                        index: index as u64,
691                        block_hash: *block_hash,
692                        block_number: block.header().number(),
693                        base_fee: block.header().base_fee_per_gas(),
694                        excess_blob_gas: block.header().excess_blob_gas(),
695                        timestamp: block.header().timestamp(),
696                    };
697                    return Ok(Some((tx.clone(), meta)))
698                }
699            }
700        }
701        Ok(None)
702    }
703
704    fn transactions_by_block(
705        &self,
706        id: BlockHashOrNumber,
707    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
708        Ok(self.block(id)?.map(|b| b.body().clone_transactions()))
709    }
710
711    fn transactions_by_block_range(
712        &self,
713        range: impl RangeBounds<alloy_primitives::BlockNumber>,
714    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
715        // init btreemap so we can return in order
716        let mut map = BTreeMap::new();
717        for block in self.blocks.lock().values() {
718            if range.contains(&block.header().number()) {
719                map.insert(block.header().number(), block.body().clone_transactions());
720            }
721        }
722
723        Ok(map.into_values().collect())
724    }
725
726    fn transactions_by_tx_range(
727        &self,
728        range: impl RangeBounds<TxNumber>,
729    ) -> ProviderResult<Vec<Self::Transaction>> {
730        let lock = self.blocks.lock();
731        let transactions = lock
732            .values()
733            .flat_map(|block| block.body().transactions())
734            .enumerate()
735            .filter(|&(tx_number, _)| range.contains(&(tx_number as TxNumber)))
736            .map(|(_, tx)| tx.clone())
737            .collect();
738
739        Ok(transactions)
740    }
741
742    fn senders_by_tx_range(
743        &self,
744        range: impl RangeBounds<TxNumber>,
745    ) -> ProviderResult<Vec<Address>> {
746        let lock = self.blocks.lock();
747        let transactions = lock
748            .values()
749            .flat_map(|block| block.body().transactions())
750            .enumerate()
751            .filter_map(|(tx_number, tx)| {
752                if range.contains(&(tx_number as TxNumber)) {
753                    tx.recover_signer().ok()
754                } else {
755                    None
756                }
757            })
758            .collect();
759
760        Ok(transactions)
761    }
762
763    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
764        self.transaction_by_id(id).map(|tx_option| tx_option.map(|tx| tx.recover_signer().unwrap()))
765    }
766}
767
768impl<T, ChainSpec> ReceiptProvider for MockEthProvider<T, ChainSpec>
769where
770    T: NodePrimitives,
771    ChainSpec: Send + Sync + 'static,
772{
773    type Receipt = T::Receipt;
774
775    fn receipt(&self, _id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
776        Ok(None)
777    }
778
779    fn receipt_by_hash(&self, _hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
780        Ok(None)
781    }
782
783    fn receipts_by_block(
784        &self,
785        block: BlockHashOrNumber,
786    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
787        let receipts_lock = self.receipts.lock();
788
789        match block {
790            BlockHashOrNumber::Hash(hash) => {
791                // Find block number by hash first
792                let headers_lock = self.headers.lock();
793                if let Some(header) = headers_lock.get(&hash) {
794                    Ok(receipts_lock.get(&header.number()).cloned())
795                } else {
796                    Ok(None)
797                }
798            }
799            BlockHashOrNumber::Number(number) => Ok(receipts_lock.get(&number).cloned()),
800        }
801    }
802
803    fn receipts_by_tx_range(
804        &self,
805        _range: impl RangeBounds<TxNumber>,
806    ) -> ProviderResult<Vec<Self::Receipt>> {
807        Ok(vec![])
808    }
809
810    fn receipts_by_block_range(
811        &self,
812        block_range: RangeInclusive<BlockNumber>,
813    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
814        let receipts_lock = self.receipts.lock();
815        let headers_lock = self.headers.lock();
816
817        let mut result = Vec::new();
818        for block_number in block_range {
819            // Only include blocks that exist in headers (i.e., have been added to the provider)
820            if headers_lock.values().any(|header| header.number() == block_number) {
821                if let Some(block_receipts) = receipts_lock.get(&block_number) {
822                    result.push(block_receipts.clone());
823                } else {
824                    // If block exists but no receipts found, add empty vec
825                    result.push(vec![]);
826                }
827            }
828        }
829
830        Ok(result)
831    }
832}
833
834impl<T, ChainSpec> ReceiptProviderIdExt for MockEthProvider<T, ChainSpec>
835where
836    T: NodePrimitives,
837    Self: ReceiptProvider + BlockIdReader,
838{
839}
840
841impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockHashReader
842    for MockEthProvider<T, ChainSpec>
843{
844    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
845        let lock = self.headers.lock();
846        let hash =
847            lock.iter().find_map(|(hash, header)| (header.number() == number).then_some(*hash));
848        Ok(hash)
849    }
850
851    fn canonical_hashes_range(
852        &self,
853        start: BlockNumber,
854        end: BlockNumber,
855    ) -> ProviderResult<Vec<B256>> {
856        let lock = self.headers.lock();
857        let mut hashes: Vec<_> =
858            lock.iter().filter(|(_, header)| (start..end).contains(&header.number())).collect();
859
860        hashes.sort_by_key(|(_, header)| header.number());
861
862        Ok(hashes.into_iter().map(|(hash, _)| *hash).collect())
863    }
864}
865
866impl<T: NodePrimitives, ChainSpec: Send + Sync + 'static> BlockNumReader
867    for MockEthProvider<T, ChainSpec>
868{
869    fn chain_info(&self) -> ProviderResult<ChainInfo> {
870        let best_block_number = self.best_block_number()?;
871        let lock = self.headers.lock();
872
873        Ok(lock
874            .iter()
875            .find(|(_, header)| header.number() == best_block_number)
876            .map(|(hash, header)| ChainInfo { best_hash: *hash, best_number: header.number() })
877            .unwrap_or_default())
878    }
879
880    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
881        let lock = self.headers.lock();
882        lock.iter()
883            .max_by_key(|h| h.1.number())
884            .map(|(_, header)| header.number())
885            .ok_or(ProviderError::BestBlockNotFound)
886    }
887
888    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
889        self.best_block_number()
890    }
891
892    fn block_number(&self, hash: B256) -> ProviderResult<Option<alloy_primitives::BlockNumber>> {
893        let lock = self.headers.lock();
894        Ok(lock.get(&hash).map(|header| header.number()))
895    }
896}
897
898impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockIdReader
899    for MockEthProvider<T, ChainSpec>
900{
901    fn pending_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
902        Ok(*self.pending_block_num_hash.lock())
903    }
904
905    fn safe_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
906        Ok(None)
907    }
908
909    fn finalized_block_num_hash(&self) -> ProviderResult<Option<alloy_eips::BlockNumHash>> {
910        Ok(None)
911    }
912}
913
914//look
915impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> BlockReader
916    for MockEthProvider<T, ChainSpec>
917{
918    type Block = T::Block;
919
920    fn find_block_by_hash(
921        &self,
922        hash: B256,
923        _source: BlockSource,
924    ) -> ProviderResult<Option<Self::Block>> {
925        self.block(hash.into())
926    }
927
928    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
929        let lock = self.blocks.lock();
930        match id {
931            BlockHashOrNumber::Hash(hash) => Ok(lock.get(&hash).cloned()),
932            BlockHashOrNumber::Number(num) => {
933                Ok(lock.values().find(|b| b.header().number() == num).cloned())
934            }
935        }
936    }
937
938    fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
939        Ok(None)
940    }
941
942    fn pending_block_and_receipts(
943        &self,
944    ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<T::Receipt>)>> {
945        Ok(None)
946    }
947
948    fn recovered_block(
949        &self,
950        _id: BlockHashOrNumber,
951        _transaction_kind: TransactionVariant,
952    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
953        Ok(None)
954    }
955
956    fn sealed_block_with_senders(
957        &self,
958        _id: BlockHashOrNumber,
959        _transaction_kind: TransactionVariant,
960    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
961        Ok(None)
962    }
963
964    fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
965        let lock = self.blocks.lock();
966
967        let mut blocks: Vec<_> = lock
968            .values()
969            .filter(|block| range.contains(&block.header().number()))
970            .cloned()
971            .collect();
972        blocks.sort_by_key(|block| block.header().number());
973
974        Ok(blocks)
975    }
976
977    fn block_with_senders_range(
978        &self,
979        _range: RangeInclusive<BlockNumber>,
980    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
981        Ok(vec![])
982    }
983
984    fn recovered_block_range(
985        &self,
986        _range: RangeInclusive<BlockNumber>,
987    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
988        Ok(vec![])
989    }
990
991    fn block_by_transaction_id(&self, _id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
992        Ok(None)
993    }
994}
995
996impl<T, ChainSpec> BlockReaderIdExt for MockEthProvider<T, ChainSpec>
997where
998    ChainSpec: EthChainSpec + Send + Sync + 'static,
999    T: NodePrimitives,
1000{
1001    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<T::Block>> {
1002        match id {
1003            BlockId::Number(num) => self.block_by_number_or_tag(num),
1004            BlockId::Hash(hash) => self.block_by_hash(hash.block_hash),
1005        }
1006    }
1007
1008    fn sealed_header_by_id(
1009        &self,
1010        id: BlockId,
1011    ) -> ProviderResult<Option<SealedHeader<<T::Block as Block>::Header>>> {
1012        self.header_by_id(id)?.map_or_else(|| Ok(None), |h| Ok(Some(SealedHeader::seal_slow(h))))
1013    }
1014
1015    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<<T::Block as Block>::Header>> {
1016        match self.block_by_id(id)? {
1017            None => Ok(None),
1018            Some(block) => Ok(Some(block.into_header())),
1019        }
1020    }
1021}
1022
1023impl<T: NodePrimitives, ChainSpec: Send + Sync> AccountReader for MockEthProvider<T, ChainSpec> {
1024    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
1025        Ok(self.accounts.lock().get(address).cloned().map(|a| a.account))
1026    }
1027}
1028
1029impl<T: NodePrimitives, ChainSpec: Send + Sync> StageCheckpointReader
1030    for MockEthProvider<T, ChainSpec>
1031{
1032    fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
1033        Ok(self.stage_checkpoints.lock().get(&id).copied())
1034    }
1035
1036    fn get_stage_checkpoint_progress(&self, _id: StageId) -> ProviderResult<Option<Vec<u8>>> {
1037        Ok(None)
1038    }
1039
1040    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
1041        Ok(self
1042            .stage_checkpoints
1043            .lock()
1044            .iter()
1045            .map(|(id, checkpoint)| (id.to_string(), *checkpoint))
1046            .collect())
1047    }
1048}
1049
1050impl<T: NodePrimitives, ChainSpec: Send + Sync> PruneCheckpointReader
1051    for MockEthProvider<T, ChainSpec>
1052{
1053    fn get_prune_checkpoint(
1054        &self,
1055        _segment: PruneSegment,
1056    ) -> ProviderResult<Option<PruneCheckpoint>> {
1057        Ok(None)
1058    }
1059
1060    fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
1061        Ok(vec![])
1062    }
1063}
1064
1065impl<T, ChainSpec> StateRootProvider for MockEthProvider<T, ChainSpec>
1066where
1067    T: NodePrimitives,
1068    ChainSpec: Send + Sync,
1069{
1070    fn state_root(&self, _state: HashedPostState) -> ProviderResult<B256> {
1071        Ok(self.state_roots.lock().pop().unwrap_or_default())
1072    }
1073
1074    fn state_root_from_nodes(&self, _input: TrieInput) -> ProviderResult<B256> {
1075        Ok(self.state_roots.lock().pop().unwrap_or_default())
1076    }
1077
1078    fn state_root_with_updates(
1079        &self,
1080        _state: HashedPostState,
1081    ) -> ProviderResult<(B256, TrieUpdates)> {
1082        let state_root = self.state_roots.lock().pop().unwrap_or_default();
1083        Ok((state_root, Default::default()))
1084    }
1085
1086    fn state_root_from_nodes_with_updates(
1087        &self,
1088        _input: TrieInput,
1089    ) -> ProviderResult<(B256, TrieUpdates)> {
1090        let state_root = self.state_roots.lock().pop().unwrap_or_default();
1091        Ok((state_root, Default::default()))
1092    }
1093}
1094
1095impl<T, ChainSpec> StorageRootProvider for MockEthProvider<T, ChainSpec>
1096where
1097    T: NodePrimitives,
1098    ChainSpec: Send + Sync,
1099{
1100    fn storage_root(
1101        &self,
1102        _address: Address,
1103        _hashed_storage: HashedStorage,
1104    ) -> ProviderResult<B256> {
1105        Ok(EMPTY_ROOT_HASH)
1106    }
1107
1108    fn storage_proof(
1109        &self,
1110        _address: Address,
1111        slot: B256,
1112        _hashed_storage: HashedStorage,
1113    ) -> ProviderResult<reth_trie::StorageProof> {
1114        Ok(StorageProof::new(slot))
1115    }
1116
1117    fn storage_multiproof(
1118        &self,
1119        _address: Address,
1120        _slots: &[B256],
1121        _hashed_storage: HashedStorage,
1122    ) -> ProviderResult<StorageMultiProof> {
1123        Ok(StorageMultiProof::empty())
1124    }
1125}
1126
1127impl<T, ChainSpec> StateProofProvider for MockEthProvider<T, ChainSpec>
1128where
1129    T: NodePrimitives,
1130    ChainSpec: Send + Sync,
1131{
1132    fn proof(
1133        &self,
1134        _input: TrieInput,
1135        address: Address,
1136        _slots: &[B256],
1137    ) -> ProviderResult<AccountProof> {
1138        Ok(AccountProof::new(address))
1139    }
1140
1141    fn multiproof(
1142        &self,
1143        _input: TrieInput,
1144        _targets: MultiProofTargets,
1145    ) -> ProviderResult<MultiProof> {
1146        Ok(MultiProof::default())
1147    }
1148
1149    fn multiproof_v2(
1150        &self,
1151        _input: TrieInput,
1152        _targets: reth_trie::MultiProofTargetsV2,
1153    ) -> ProviderResult<reth_trie::DecodedMultiProofV2> {
1154        Ok(reth_trie::DecodedMultiProofV2::default())
1155    }
1156
1157    fn witness(
1158        &self,
1159        _input: TrieInput,
1160        _target: HashedPostState,
1161        _mode: reth_trie::ExecutionWitnessMode,
1162    ) -> ProviderResult<Vec<Bytes>> {
1163        Ok(Vec::default())
1164    }
1165}
1166
1167impl<T: NodePrimitives, ChainSpec: EthChainSpec + 'static> HashedPostStateProvider
1168    for MockEthProvider<T, ChainSpec>
1169{
1170    fn hashed_post_state(
1171        &self,
1172        _bundle_state: &revm::database::BundleState,
1173    ) -> ProviderResult<HashedPostState> {
1174        Ok(HashedPostState::default())
1175    }
1176}
1177
1178impl<T, ChainSpec> StateProvider for MockEthProvider<T, ChainSpec>
1179where
1180    T: NodePrimitives,
1181    ChainSpec: EthChainSpec + Send + Sync + 'static,
1182{
1183    fn storage(
1184        &self,
1185        account: Address,
1186        storage_key: StorageKey,
1187    ) -> ProviderResult<Option<StorageValue>> {
1188        let lock = self.accounts.lock();
1189        Ok(lock.get(&account).and_then(|account| account.storage.get(&storage_key)).copied())
1190    }
1191}
1192
1193impl<T, ChainSpec> BytecodeReader for MockEthProvider<T, ChainSpec>
1194where
1195    T: NodePrimitives,
1196    ChainSpec: Send + Sync,
1197{
1198    fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
1199        let lock = self.accounts.lock();
1200        Ok(lock.values().find_map(|account| {
1201            match (account.account.bytecode_hash.as_ref(), account.bytecode.as_ref()) {
1202                (Some(bytecode_hash), Some(bytecode)) if bytecode_hash == code_hash => {
1203                    Some(bytecode.clone())
1204                }
1205                _ => None,
1206            }
1207        }))
1208    }
1209}
1210
1211impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageSettingsCache
1212    for MockEthProvider<T, ChainSpec>
1213{
1214    fn cached_storage_settings(&self) -> StorageSettings {
1215        StorageSettings::default()
1216    }
1217
1218    fn set_storage_settings_cache(&self, _settings: StorageSettings) {}
1219}
1220
1221impl<T: NodePrimitives, ChainSpec: EthChainSpec + Send + Sync + 'static> StateProviderFactory
1222    for MockEthProvider<T, ChainSpec>
1223{
1224    fn latest(&self) -> ProviderResult<StateProviderBox> {
1225        self.ensure_snap_state_reads_succeed()?;
1226        Ok(Box::new(self.clone()))
1227    }
1228
1229    fn state_by_block_number_or_tag(
1230        &self,
1231        number_or_tag: BlockNumberOrTag,
1232    ) -> ProviderResult<StateProviderBox> {
1233        match number_or_tag {
1234            BlockNumberOrTag::Latest => self.latest(),
1235            BlockNumberOrTag::Finalized => {
1236                // we can only get the finalized state by hash, not by num
1237                let hash =
1238                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
1239
1240                // only look at historical state
1241                self.history_by_block_hash(hash)
1242            }
1243            BlockNumberOrTag::Safe => {
1244                // we can only get the safe state by hash, not by num
1245                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
1246
1247                self.history_by_block_hash(hash)
1248            }
1249            BlockNumberOrTag::Earliest => {
1250                self.history_by_block_number(self.earliest_block_number()?)
1251            }
1252            BlockNumberOrTag::Pending => self.pending(),
1253            BlockNumberOrTag::Number(num) => self.history_by_block_number(num),
1254        }
1255    }
1256
1257    fn history_by_block_number(&self, _block: BlockNumber) -> ProviderResult<StateProviderBox> {
1258        Ok(Box::new(self.clone()))
1259    }
1260
1261    fn history_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
1262        Ok(Box::new(self.clone()))
1263    }
1264
1265    fn state_by_block_hash(&self, _block: BlockHash) -> ProviderResult<StateProviderBox> {
1266        Ok(Box::new(self.clone()))
1267    }
1268
1269    fn pending(&self) -> ProviderResult<StateProviderBox> {
1270        Ok(Box::new(self.clone()))
1271    }
1272
1273    fn pending_state_by_hash(&self, _block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
1274        Ok(Some(Box::new(self.clone())))
1275    }
1276
1277    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
1278        Ok(Some(Box::new(self.clone())))
1279    }
1280}
1281
1282impl<T: NodePrimitives, ChainSpec: Send + Sync> BlockBodyIndicesProvider
1283    for MockEthProvider<T, ChainSpec>
1284{
1285    fn block_body_indices(&self, num: u64) -> ProviderResult<Option<StoredBlockBodyIndices>> {
1286        Ok(self.block_body_indices.lock().get(&num).copied())
1287    }
1288    fn block_body_indices_range(
1289        &self,
1290        _range: RangeInclusive<BlockNumber>,
1291    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
1292        Ok(vec![])
1293    }
1294}
1295
1296impl<T: NodePrimitives, ChainSpec: Send + Sync> ChangeSetReader for MockEthProvider<T, ChainSpec> {
1297    fn account_block_changeset(
1298        &self,
1299        _block_number: BlockNumber,
1300    ) -> ProviderResult<Vec<AccountBeforeTx>> {
1301        Ok(Vec::default())
1302    }
1303
1304    fn get_account_before_block(
1305        &self,
1306        _block_number: BlockNumber,
1307        _address: Address,
1308    ) -> ProviderResult<Option<AccountBeforeTx>> {
1309        Ok(None)
1310    }
1311
1312    fn account_changesets_range(
1313        &self,
1314        _range: impl core::ops::RangeBounds<BlockNumber>,
1315    ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
1316        Ok(Vec::default())
1317    }
1318}
1319
1320impl<T: NodePrimitives, ChainSpec: Send + Sync> StorageChangeSetReader
1321    for MockEthProvider<T, ChainSpec>
1322{
1323    fn storage_changeset(
1324        &self,
1325        _block_number: BlockNumber,
1326    ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1327        Ok(Vec::default())
1328    }
1329
1330    fn get_storage_before_block(
1331        &self,
1332        _block_number: BlockNumber,
1333        _address: Address,
1334        _storage_key: B256,
1335    ) -> ProviderResult<Option<StorageEntry>> {
1336        Ok(None)
1337    }
1338
1339    fn storage_changesets_range(
1340        &self,
1341        _range: impl RangeBounds<BlockNumber>,
1342    ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, StorageEntry)>> {
1343        Ok(Vec::default())
1344    }
1345}
1346
1347impl<T: NodePrimitives, ChainSpec: Send + Sync> StateReader for MockEthProvider<T, ChainSpec> {
1348    type Receipt = T::Receipt;
1349
1350    fn get_state(
1351        &self,
1352        _block: BlockNumber,
1353    ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1354        Ok(None)
1355    }
1356}
1357
1358impl<T: NodePrimitives, ChainSpec: Send + Sync> CanonStateSubscriptions
1359    for MockEthProvider<T, ChainSpec>
1360{
1361    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<T> {
1362        broadcast::channel(1).1
1363    }
1364}
1365
1366impl<T: NodePrimitives, ChainSpec: Send + Sync> NodePrimitivesProvider
1367    for MockEthProvider<T, ChainSpec>
1368{
1369    type Primitives = T;
1370}
1371
1372#[cfg(test)]
1373mod tests {
1374    use super::*;
1375    use alloy_consensus::Header;
1376    use alloy_primitives::BlockHash;
1377    use reth_ethereum_primitives::Receipt;
1378
1379    #[test]
1380    fn test_mock_provider_receipts() {
1381        let provider = MockEthProvider::<EthPrimitives>::new();
1382
1383        let block_hash = BlockHash::random();
1384        let block_number = 1u64;
1385        let header = Header { number: block_number, ..Default::default() };
1386
1387        let receipt1 = Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() };
1388        let receipt2 = Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() };
1389        let receipts = vec![receipt1, receipt2];
1390
1391        provider.add_header(block_hash, header);
1392        provider.add_receipts(block_number, receipts.clone());
1393
1394        let result = provider.receipts_by_block(block_hash.into()).unwrap();
1395        assert_eq!(result, Some(receipts.clone()));
1396
1397        let result = provider.receipts_by_block(block_number.into()).unwrap();
1398        assert_eq!(result, Some(receipts.clone()));
1399
1400        let range_result = provider.receipts_by_block_range(1..=1).unwrap();
1401        assert_eq!(range_result, vec![receipts]);
1402
1403        let non_existent = provider.receipts_by_block(BlockHash::random().into()).unwrap();
1404        assert_eq!(non_existent, None);
1405
1406        let empty_range = provider.receipts_by_block_range(10..=20).unwrap();
1407        assert_eq!(empty_range, Vec::<Vec<Receipt>>::new());
1408    }
1409
1410    #[test]
1411    fn test_mock_provider_receipts_multiple_blocks() {
1412        let provider = MockEthProvider::<EthPrimitives>::new();
1413
1414        let block1_hash = BlockHash::random();
1415        let block2_hash = BlockHash::random();
1416        let block1_number = 1u64;
1417        let block2_number = 2u64;
1418
1419        let header1 = Header { number: block1_number, ..Default::default() };
1420        let header2 = Header { number: block2_number, ..Default::default() };
1421
1422        let receipts1 =
1423            vec![Receipt { cumulative_gas_used: 21000, success: true, ..Default::default() }];
1424        let receipts2 =
1425            vec![Receipt { cumulative_gas_used: 42000, success: true, ..Default::default() }];
1426
1427        provider.add_header(block1_hash, header1);
1428        provider.add_header(block2_hash, header2);
1429        provider.add_receipts(block1_number, receipts1.clone());
1430        provider.add_receipts(block2_number, receipts2.clone());
1431
1432        let range_result = provider.receipts_by_block_range(1..=2).unwrap();
1433        assert_eq!(range_result.len(), 2);
1434        assert_eq!(range_result[0], receipts1);
1435        assert_eq!(range_result[1], receipts2);
1436
1437        let partial_range = provider.receipts_by_block_range(1..=1).unwrap();
1438        assert_eq!(partial_range.len(), 1);
1439        assert_eq!(partial_range[0], receipts1);
1440    }
1441}