reth_provider/providers/
blockchain_provider.rs

1use crate::{
2    providers::{
3        ConsistentProvider, ProviderNodeTypes, StaticFileProvider, StaticFileProviderRWRefMut,
4    },
5    AccountReader, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader, BlockReaderIdExt,
6    BlockSource, CanonChainTracker, CanonStateNotifications, CanonStateSubscriptions,
7    ChainSpecProvider, ChainStateBlockReader, ChangeSetReader, DatabaseProviderFactory,
8    HashedPostStateProvider, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader,
9    ReceiptProvider, ReceiptProviderIdExt, StageCheckpointReader, StateProviderBox,
10    StateProviderFactory, StateReader, StaticFileProviderFactory, TransactionVariant,
11    TransactionsProvider, TrieReader,
12};
13use alloy_consensus::transaction::TransactionMeta;
14use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
15use alloy_primitives::{Address, BlockHash, BlockNumber, TxHash, TxNumber, B256};
16use alloy_rpc_types_engine::ForkchoiceState;
17use reth_chain_state::{
18    BlockState, CanonicalInMemoryState, ForkChoiceNotifications, ForkChoiceSubscriptions,
19    MemoryOverlayStateProvider,
20};
21use reth_chainspec::ChainInfo;
22use reth_db_api::models::{AccountBeforeTx, BlockNumberAddress, StoredBlockBodyIndices};
23use reth_execution_types::ExecutionOutcome;
24use reth_node_types::{BlockTy, HeaderTy, NodeTypesWithDB, ReceiptTy, TxTy};
25use reth_primitives_traits::{Account, RecoveredBlock, SealedHeader, StorageEntry};
26use reth_prune_types::{PruneCheckpoint, PruneSegment};
27use reth_stages_types::{StageCheckpoint, StageId};
28use reth_static_file_types::StaticFileSegment;
29use reth_storage_api::{BlockBodyIndicesProvider, NodePrimitivesProvider, StorageChangeSetReader};
30use reth_storage_errors::provider::ProviderResult;
31use reth_trie::{updates::TrieUpdatesSorted, HashedPostState, KeccakKeyHasher};
32use revm_database::BundleState;
33use std::{
34    ops::{RangeBounds, RangeInclusive},
35    sync::Arc,
36    time::Instant,
37};
38use tracing::trace;
39
40/// The main type for interacting with the blockchain.
41///
42/// This type serves as the main entry point for interacting with the blockchain and provides data
43/// from database storage and from the blockchain tree (pending state etc.) It is a simple wrapper
44/// type that holds an instance of the database and the blockchain tree.
45#[derive(Debug)]
46pub struct BlockchainProvider<N: NodeTypesWithDB> {
47    /// Provider factory used to access the database.
48    pub(crate) database: ProviderFactory<N>,
49    /// Tracks the chain info wrt forkchoice updates and in memory canonical
50    /// state.
51    pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
52}
53
54impl<N: NodeTypesWithDB> Clone for BlockchainProvider<N> {
55    fn clone(&self) -> Self {
56        Self {
57            database: self.database.clone(),
58            canonical_in_memory_state: self.canonical_in_memory_state.clone(),
59        }
60    }
61}
62
63impl<N: ProviderNodeTypes> BlockchainProvider<N> {
64    /// Create a new [`BlockchainProvider`] using only the storage, fetching the latest
65    /// header from the database to initialize the provider.
66    pub fn new(storage: ProviderFactory<N>) -> ProviderResult<Self> {
67        let provider = storage.provider()?;
68        let best = provider.chain_info()?;
69        match provider.header_by_number(best.best_number)? {
70            Some(header) => {
71                drop(provider);
72                Ok(Self::with_latest(storage, SealedHeader::new(header, best.best_hash))?)
73            }
74            None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
75        }
76    }
77
78    /// Create new provider instance that wraps the database and the blockchain tree, using the
79    /// provided latest header to initialize the chain info tracker.
80    ///
81    /// This returns a `ProviderResult` since it tries the retrieve the last finalized header from
82    /// `database`.
83    pub fn with_latest(
84        storage: ProviderFactory<N>,
85        latest: SealedHeader<HeaderTy<N>>,
86    ) -> ProviderResult<Self> {
87        let provider = storage.provider()?;
88        let finalized_header = provider
89            .last_finalized_block_number()?
90            .map(|num| provider.sealed_header(num))
91            .transpose()?
92            .flatten();
93        let safe_header = provider
94            .last_safe_block_number()?
95            .or_else(|| {
96                // for the purpose of this we can also use the finalized block if we don't have the
97                // safe block
98                provider.last_finalized_block_number().ok().flatten()
99            })
100            .map(|num| provider.sealed_header(num))
101            .transpose()?
102            .flatten();
103        Ok(Self {
104            database: storage,
105            canonical_in_memory_state: CanonicalInMemoryState::with_head(
106                latest,
107                finalized_header,
108                safe_header,
109            ),
110        })
111    }
112
113    /// Gets a clone of `canonical_in_memory_state`.
114    pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState<N::Primitives> {
115        self.canonical_in_memory_state.clone()
116    }
117
118    /// Returns a provider with a created `DbTx` inside, which allows fetching data from the
119    /// database using different types of providers. Example: [`HeaderProvider`]
120    /// [`BlockHashReader`]. This may fail if the inner read database transaction fails to open.
121    #[track_caller]
122    pub fn consistent_provider(&self) -> ProviderResult<ConsistentProvider<N>> {
123        ConsistentProvider::new(self.database.clone(), self.canonical_in_memory_state())
124    }
125
126    /// This uses a given [`BlockState`] to initialize a state provider for that block.
127    fn block_state_provider(
128        &self,
129        state: &BlockState<N::Primitives>,
130    ) -> ProviderResult<MemoryOverlayStateProvider<N::Primitives>> {
131        let anchor_hash = state.anchor().hash;
132        let latest_historical = self.database.history_by_block_hash(anchor_hash)?;
133        Ok(state.state_provider(latest_historical))
134    }
135
136    /// Return the last N blocks of state, recreating the [`ExecutionOutcome`].
137    ///
138    /// If the range is empty, or there are no blocks for the given range, then this returns `None`.
139    pub fn get_state(
140        &self,
141        range: RangeInclusive<BlockNumber>,
142    ) -> ProviderResult<Option<ExecutionOutcome<ReceiptTy<N>>>> {
143        self.consistent_provider()?.get_state(range)
144    }
145}
146
147impl<N: NodeTypesWithDB> NodePrimitivesProvider for BlockchainProvider<N> {
148    type Primitives = N::Primitives;
149}
150
151impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
152    type DB = N::DB;
153    type Provider = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
154    type ProviderRW = <ProviderFactory<N> as DatabaseProviderFactory>::ProviderRW;
155
156    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
157        self.database.database_provider_ro()
158    }
159
160    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
161        self.database.database_provider_rw()
162    }
163}
164
165impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> {
166    fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
167        self.database.static_file_provider()
168    }
169
170    fn get_static_file_writer(
171        &self,
172        block: BlockNumber,
173        segment: StaticFileSegment,
174    ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
175        self.database.get_static_file_writer(block, segment)
176    }
177}
178
179impl<N: ProviderNodeTypes> HeaderProvider for BlockchainProvider<N> {
180    type Header = HeaderTy<N>;
181
182    fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
183        self.consistent_provider()?.header(block_hash)
184    }
185
186    fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
187        self.consistent_provider()?.header_by_number(num)
188    }
189
190    fn headers_range(
191        &self,
192        range: impl RangeBounds<BlockNumber>,
193    ) -> ProviderResult<Vec<Self::Header>> {
194        self.consistent_provider()?.headers_range(range)
195    }
196
197    fn sealed_header(
198        &self,
199        number: BlockNumber,
200    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
201        self.consistent_provider()?.sealed_header(number)
202    }
203
204    fn sealed_headers_range(
205        &self,
206        range: impl RangeBounds<BlockNumber>,
207    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
208        self.consistent_provider()?.sealed_headers_range(range)
209    }
210
211    fn sealed_headers_while(
212        &self,
213        range: impl RangeBounds<BlockNumber>,
214        predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
215    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
216        self.consistent_provider()?.sealed_headers_while(range, predicate)
217    }
218}
219
220impl<N: ProviderNodeTypes> BlockHashReader for BlockchainProvider<N> {
221    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
222        self.consistent_provider()?.block_hash(number)
223    }
224
225    fn canonical_hashes_range(
226        &self,
227        start: BlockNumber,
228        end: BlockNumber,
229    ) -> ProviderResult<Vec<B256>> {
230        self.consistent_provider()?.canonical_hashes_range(start, end)
231    }
232}
233
234impl<N: ProviderNodeTypes> BlockNumReader for BlockchainProvider<N> {
235    fn chain_info(&self) -> ProviderResult<ChainInfo> {
236        Ok(self.canonical_in_memory_state.chain_info())
237    }
238
239    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
240        Ok(self.canonical_in_memory_state.get_canonical_block_number())
241    }
242
243    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
244        self.database.last_block_number()
245    }
246
247    fn earliest_block_number(&self) -> ProviderResult<BlockNumber> {
248        self.database.earliest_block_number()
249    }
250
251    fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
252        self.consistent_provider()?.block_number(hash)
253    }
254}
255
256impl<N: ProviderNodeTypes> BlockIdReader for BlockchainProvider<N> {
257    fn pending_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
258        Ok(self.canonical_in_memory_state.pending_block_num_hash())
259    }
260
261    fn safe_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
262        Ok(self.canonical_in_memory_state.get_safe_num_hash())
263    }
264
265    fn finalized_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
266        Ok(self.canonical_in_memory_state.get_finalized_num_hash())
267    }
268}
269
270impl<N: ProviderNodeTypes> BlockReader for BlockchainProvider<N> {
271    type Block = BlockTy<N>;
272
273    fn find_block_by_hash(
274        &self,
275        hash: B256,
276        source: BlockSource,
277    ) -> ProviderResult<Option<Self::Block>> {
278        self.consistent_provider()?.find_block_by_hash(hash, source)
279    }
280
281    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
282        self.consistent_provider()?.block(id)
283    }
284
285    fn pending_block(&self) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
286        Ok(self.canonical_in_memory_state.pending_recovered_block())
287    }
288
289    fn pending_block_and_receipts(
290        &self,
291    ) -> ProviderResult<Option<(RecoveredBlock<Self::Block>, Vec<Self::Receipt>)>> {
292        Ok(self.canonical_in_memory_state.pending_block_and_receipts())
293    }
294
295    /// Returns the block with senders with matching number or hash from database.
296    ///
297    /// **NOTE: If [`TransactionVariant::NoHash`] is provided then the transactions have invalid
298    /// hashes, since they would need to be calculated on the spot, and we want fast querying.**
299    ///
300    /// Returns `None` if block is not found.
301    fn recovered_block(
302        &self,
303        id: BlockHashOrNumber,
304        transaction_kind: TransactionVariant,
305    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
306        self.consistent_provider()?.recovered_block(id, transaction_kind)
307    }
308
309    fn sealed_block_with_senders(
310        &self,
311        id: BlockHashOrNumber,
312        transaction_kind: TransactionVariant,
313    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
314        self.consistent_provider()?.sealed_block_with_senders(id, transaction_kind)
315    }
316
317    fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
318        self.consistent_provider()?.block_range(range)
319    }
320
321    fn block_with_senders_range(
322        &self,
323        range: RangeInclusive<BlockNumber>,
324    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
325        self.consistent_provider()?.block_with_senders_range(range)
326    }
327
328    fn recovered_block_range(
329        &self,
330        range: RangeInclusive<BlockNumber>,
331    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
332        self.consistent_provider()?.recovered_block_range(range)
333    }
334
335    fn block_by_transaction_id(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
336        self.consistent_provider()?.block_by_transaction_id(id)
337    }
338}
339
340impl<N: ProviderNodeTypes> TransactionsProvider for BlockchainProvider<N> {
341    type Transaction = TxTy<N>;
342
343    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
344        self.consistent_provider()?.transaction_id(tx_hash)
345    }
346
347    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
348        self.consistent_provider()?.transaction_by_id(id)
349    }
350
351    fn transaction_by_id_unhashed(
352        &self,
353        id: TxNumber,
354    ) -> ProviderResult<Option<Self::Transaction>> {
355        self.consistent_provider()?.transaction_by_id_unhashed(id)
356    }
357
358    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
359        self.consistent_provider()?.transaction_by_hash(hash)
360    }
361
362    fn transaction_by_hash_with_meta(
363        &self,
364        tx_hash: TxHash,
365    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
366        self.consistent_provider()?.transaction_by_hash_with_meta(tx_hash)
367    }
368
369    fn transactions_by_block(
370        &self,
371        id: BlockHashOrNumber,
372    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
373        self.consistent_provider()?.transactions_by_block(id)
374    }
375
376    fn transactions_by_block_range(
377        &self,
378        range: impl RangeBounds<BlockNumber>,
379    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
380        self.consistent_provider()?.transactions_by_block_range(range)
381    }
382
383    fn transactions_by_tx_range(
384        &self,
385        range: impl RangeBounds<TxNumber>,
386    ) -> ProviderResult<Vec<Self::Transaction>> {
387        self.consistent_provider()?.transactions_by_tx_range(range)
388    }
389
390    fn senders_by_tx_range(
391        &self,
392        range: impl RangeBounds<TxNumber>,
393    ) -> ProviderResult<Vec<Address>> {
394        self.consistent_provider()?.senders_by_tx_range(range)
395    }
396
397    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
398        self.consistent_provider()?.transaction_sender(id)
399    }
400}
401
402impl<N: ProviderNodeTypes> ReceiptProvider for BlockchainProvider<N> {
403    type Receipt = ReceiptTy<N>;
404
405    fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
406        self.consistent_provider()?.receipt(id)
407    }
408
409    fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
410        self.consistent_provider()?.receipt_by_hash(hash)
411    }
412
413    fn receipts_by_block(
414        &self,
415        block: BlockHashOrNumber,
416    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
417        self.consistent_provider()?.receipts_by_block(block)
418    }
419
420    fn receipts_by_tx_range(
421        &self,
422        range: impl RangeBounds<TxNumber>,
423    ) -> ProviderResult<Vec<Self::Receipt>> {
424        self.consistent_provider()?.receipts_by_tx_range(range)
425    }
426
427    fn receipts_by_block_range(
428        &self,
429        block_range: RangeInclusive<BlockNumber>,
430    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
431        self.consistent_provider()?.receipts_by_block_range(block_range)
432    }
433}
434
435impl<N: ProviderNodeTypes> ReceiptProviderIdExt for BlockchainProvider<N> {
436    fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult<Option<Vec<Self::Receipt>>> {
437        self.consistent_provider()?.receipts_by_block_id(block)
438    }
439}
440
441impl<N: ProviderNodeTypes> BlockBodyIndicesProvider for BlockchainProvider<N> {
442    fn block_body_indices(
443        &self,
444        number: BlockNumber,
445    ) -> ProviderResult<Option<StoredBlockBodyIndices>> {
446        self.consistent_provider()?.block_body_indices(number)
447    }
448
449    fn block_body_indices_range(
450        &self,
451        range: RangeInclusive<BlockNumber>,
452    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
453        self.consistent_provider()?.block_body_indices_range(range)
454    }
455}
456
457impl<N: ProviderNodeTypes> StageCheckpointReader for BlockchainProvider<N> {
458    fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
459        self.consistent_provider()?.get_stage_checkpoint(id)
460    }
461
462    fn get_stage_checkpoint_progress(&self, id: StageId) -> ProviderResult<Option<Vec<u8>>> {
463        self.consistent_provider()?.get_stage_checkpoint_progress(id)
464    }
465
466    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
467        self.consistent_provider()?.get_all_checkpoints()
468    }
469}
470
471impl<N: ProviderNodeTypes> PruneCheckpointReader for BlockchainProvider<N> {
472    fn get_prune_checkpoint(
473        &self,
474        segment: PruneSegment,
475    ) -> ProviderResult<Option<PruneCheckpoint>> {
476        self.consistent_provider()?.get_prune_checkpoint(segment)
477    }
478
479    fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
480        self.consistent_provider()?.get_prune_checkpoints()
481    }
482}
483
484impl<N: NodeTypesWithDB> ChainSpecProvider for BlockchainProvider<N> {
485    type ChainSpec = N::ChainSpec;
486
487    fn chain_spec(&self) -> Arc<N::ChainSpec> {
488        self.database.chain_spec()
489    }
490}
491
492impl<N: ProviderNodeTypes> StateProviderFactory for BlockchainProvider<N> {
493    /// Storage provider for latest block
494    fn latest(&self) -> ProviderResult<StateProviderBox> {
495        trace!(target: "providers::blockchain", "Getting latest block state provider");
496        // use latest state provider if the head state exists
497        if let Some(state) = self.canonical_in_memory_state.head_state() {
498            trace!(target: "providers::blockchain", "Using head state for latest state provider");
499            Ok(self.block_state_provider(&state)?.boxed())
500        } else {
501            trace!(target: "providers::blockchain", "Using database state for latest state provider");
502            self.database.latest()
503        }
504    }
505
506    /// Returns a [`StateProviderBox`] indexed by the given block number or tag.
507    fn state_by_block_number_or_tag(
508        &self,
509        number_or_tag: BlockNumberOrTag,
510    ) -> ProviderResult<StateProviderBox> {
511        match number_or_tag {
512            BlockNumberOrTag::Latest => self.latest(),
513            BlockNumberOrTag::Finalized => {
514                // we can only get the finalized state by hash, not by num
515                let hash =
516                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
517                self.state_by_block_hash(hash)
518            }
519            BlockNumberOrTag::Safe => {
520                // we can only get the safe state by hash, not by num
521                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
522                self.state_by_block_hash(hash)
523            }
524            BlockNumberOrTag::Earliest => {
525                self.history_by_block_number(self.earliest_block_number()?)
526            }
527            BlockNumberOrTag::Pending => self.pending(),
528            BlockNumberOrTag::Number(num) => {
529                let hash = self
530                    .block_hash(num)?
531                    .ok_or_else(|| ProviderError::HeaderNotFound(num.into()))?;
532                self.state_by_block_hash(hash)
533            }
534        }
535    }
536
537    fn history_by_block_number(
538        &self,
539        block_number: BlockNumber,
540    ) -> ProviderResult<StateProviderBox> {
541        trace!(target: "providers::blockchain", ?block_number, "Getting history by block number");
542        let provider = self.consistent_provider()?;
543        provider.ensure_canonical_block(block_number)?;
544        let hash = provider
545            .block_hash(block_number)?
546            .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
547        provider.into_state_provider_at_block_hash(hash)
548    }
549
550    fn history_by_block_hash(&self, block_hash: BlockHash) -> ProviderResult<StateProviderBox> {
551        trace!(target: "providers::blockchain", ?block_hash, "Getting history by block hash");
552        self.consistent_provider()?.into_state_provider_at_block_hash(block_hash)
553    }
554
555    fn state_by_block_hash(&self, hash: BlockHash) -> ProviderResult<StateProviderBox> {
556        trace!(target: "providers::blockchain", ?hash, "Getting state by block hash");
557        if let Ok(state) = self.history_by_block_hash(hash) {
558            // This could be tracked by a historical block
559            Ok(state)
560        } else if let Ok(Some(pending)) = self.pending_state_by_hash(hash) {
561            // .. or this could be the pending state
562            Ok(pending)
563        } else {
564            // if we couldn't find it anywhere, then we should return an error
565            Err(ProviderError::StateForHashNotFound(hash))
566        }
567    }
568
569    /// Returns the state provider for pending state.
570    ///
571    /// If there's no pending block available then the latest state provider is returned:
572    /// [`Self::latest`]
573    fn pending(&self) -> ProviderResult<StateProviderBox> {
574        trace!(target: "providers::blockchain", "Getting provider for pending state");
575
576        if let Some(pending) = self.canonical_in_memory_state.pending_state() {
577            // we have a pending block
578            return Ok(Box::new(self.block_state_provider(&pending)?));
579        }
580
581        // fallback to latest state if the pending block is not available
582        self.latest()
583    }
584
585    fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
586        if let Some(pending) = self.canonical_in_memory_state.pending_state() &&
587            pending.hash() == block_hash
588        {
589            return Ok(Some(Box::new(self.block_state_provider(&pending)?)));
590        }
591        Ok(None)
592    }
593
594    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
595        if let Some(pending) = self.canonical_in_memory_state.pending_state() {
596            return Ok(Some(Box::new(self.block_state_provider(&pending)?)))
597        }
598
599        Ok(None)
600    }
601}
602
603impl<N: NodeTypesWithDB> HashedPostStateProvider for BlockchainProvider<N> {
604    fn hashed_post_state(&self, bundle_state: &BundleState) -> HashedPostState {
605        HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
606    }
607}
608
609impl<N: ProviderNodeTypes> CanonChainTracker for BlockchainProvider<N> {
610    type Header = HeaderTy<N>;
611
612    fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
613        // update timestamp
614        self.canonical_in_memory_state.on_forkchoice_update_received();
615    }
616
617    fn last_received_update_timestamp(&self) -> Option<Instant> {
618        self.canonical_in_memory_state.last_received_update_timestamp()
619    }
620
621    fn set_canonical_head(&self, header: SealedHeader<Self::Header>) {
622        self.canonical_in_memory_state.set_canonical_head(header);
623    }
624
625    fn set_safe(&self, header: SealedHeader<Self::Header>) {
626        self.canonical_in_memory_state.set_safe(header);
627    }
628
629    fn set_finalized(&self, header: SealedHeader<Self::Header>) {
630        self.canonical_in_memory_state.set_finalized(header);
631    }
632}
633
634impl<N: ProviderNodeTypes> BlockReaderIdExt for BlockchainProvider<N>
635where
636    Self: ReceiptProviderIdExt,
637{
638    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
639        self.consistent_provider()?.block_by_id(id)
640    }
641
642    fn header_by_number_or_tag(
643        &self,
644        id: BlockNumberOrTag,
645    ) -> ProviderResult<Option<Self::Header>> {
646        self.consistent_provider()?.header_by_number_or_tag(id)
647    }
648
649    fn sealed_header_by_number_or_tag(
650        &self,
651        id: BlockNumberOrTag,
652    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
653        self.consistent_provider()?.sealed_header_by_number_or_tag(id)
654    }
655
656    fn sealed_header_by_id(
657        &self,
658        id: BlockId,
659    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
660        self.consistent_provider()?.sealed_header_by_id(id)
661    }
662
663    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Header>> {
664        self.consistent_provider()?.header_by_id(id)
665    }
666}
667
668impl<N: ProviderNodeTypes> CanonStateSubscriptions for BlockchainProvider<N> {
669    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<Self::Primitives> {
670        self.canonical_in_memory_state.subscribe_canon_state()
671    }
672}
673
674impl<N: ProviderNodeTypes> ForkChoiceSubscriptions for BlockchainProvider<N> {
675    type Header = HeaderTy<N>;
676
677    fn subscribe_safe_block(&self) -> ForkChoiceNotifications<Self::Header> {
678        let receiver = self.canonical_in_memory_state.subscribe_safe_block();
679        ForkChoiceNotifications(receiver)
680    }
681
682    fn subscribe_finalized_block(&self) -> ForkChoiceNotifications<Self::Header> {
683        let receiver = self.canonical_in_memory_state.subscribe_finalized_block();
684        ForkChoiceNotifications(receiver)
685    }
686}
687
688impl<N: ProviderNodeTypes> StorageChangeSetReader for BlockchainProvider<N> {
689    fn storage_changeset(
690        &self,
691        block_number: BlockNumber,
692    ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
693        self.consistent_provider()?.storage_changeset(block_number)
694    }
695}
696
697impl<N: ProviderNodeTypes> ChangeSetReader for BlockchainProvider<N> {
698    fn account_block_changeset(
699        &self,
700        block_number: BlockNumber,
701    ) -> ProviderResult<Vec<AccountBeforeTx>> {
702        self.consistent_provider()?.account_block_changeset(block_number)
703    }
704
705    fn get_account_before_block(
706        &self,
707        block_number: BlockNumber,
708        address: Address,
709    ) -> ProviderResult<Option<AccountBeforeTx>> {
710        self.consistent_provider()?.get_account_before_block(block_number, address)
711    }
712}
713
714impl<N: ProviderNodeTypes> AccountReader for BlockchainProvider<N> {
715    /// Get basic account information.
716    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
717        self.consistent_provider()?.basic_account(address)
718    }
719}
720
721impl<N: ProviderNodeTypes> StateReader for BlockchainProvider<N> {
722    type Receipt = ReceiptTy<N>;
723
724    /// Re-constructs the [`ExecutionOutcome`] from in-memory and database state, if necessary.
725    ///
726    /// If data for the block does not exist, this will return [`None`].
727    ///
728    /// NOTE: This cannot be called safely in a loop outside of the blockchain tree thread. This is
729    /// because the [`CanonicalInMemoryState`] could change during a reorg, causing results to be
730    /// inconsistent. Currently this can safely be called within the blockchain tree thread,
731    /// because the tree thread is responsible for modifying the [`CanonicalInMemoryState`] in the
732    /// first place.
733    fn get_state(
734        &self,
735        block: BlockNumber,
736    ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
737        StateReader::get_state(&self.consistent_provider()?, block)
738    }
739}
740
741impl<N: ProviderNodeTypes> TrieReader for BlockchainProvider<N> {
742    fn trie_reverts(&self, from: BlockNumber) -> ProviderResult<TrieUpdatesSorted> {
743        self.consistent_provider()?.trie_reverts(from)
744    }
745
746    fn get_block_trie_updates(
747        &self,
748        block_number: BlockNumber,
749    ) -> ProviderResult<TrieUpdatesSorted> {
750        self.consistent_provider()?.get_block_trie_updates(block_number)
751    }
752}
753
754#[cfg(test)]
755mod tests {
756    use crate::{
757        providers::BlockchainProvider,
758        test_utils::{
759            create_test_provider_factory, create_test_provider_factory_with_chain_spec,
760            MockNodeTypesWithDB,
761        },
762        BlockWriter, CanonChainTracker, ProviderFactory,
763    };
764    use alloy_eips::{BlockHashOrNumber, BlockNumHash, BlockNumberOrTag};
765    use alloy_primitives::{BlockNumber, TxNumber, B256};
766    use itertools::Itertools;
767    use rand::Rng;
768    use reth_chain_state::{
769        test_utils::TestBlockBuilder, CanonStateNotification, CanonStateSubscriptions,
770        CanonicalInMemoryState, ExecutedBlock, NewCanonicalChain,
771    };
772    use reth_chainspec::{ChainSpec, MAINNET};
773    use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
774    use reth_errors::ProviderError;
775    use reth_ethereum_primitives::{Block, Receipt};
776    use reth_execution_types::{Chain, ExecutionOutcome};
777    use reth_primitives_traits::{RecoveredBlock, SealedBlock, SignerRecoverable};
778    use reth_storage_api::{
779        BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader,
780        BlockReaderIdExt, BlockSource, ChangeSetReader, DBProvider, DatabaseProviderFactory,
781        HeaderProvider, ReceiptProvider, ReceiptProviderIdExt, StateProviderFactory, StateWriter,
782        TransactionVariant, TransactionsProvider,
783    };
784    use reth_testing_utils::generators::{
785        self, random_block, random_block_range, random_changeset_range, random_eoa_accounts,
786        random_receipt, BlockParams, BlockRangeParams,
787    };
788    use revm_database::{BundleState, OriginalValuesKnown};
789    use std::{
790        ops::{Bound, Range, RangeBounds},
791        sync::Arc,
792    };
793
794    const TEST_BLOCKS_COUNT: usize = 5;
795
796    const TEST_TRANSACTIONS_COUNT: u8 = 4;
797
798    fn random_blocks(
799        rng: &mut impl Rng,
800        database_blocks: usize,
801        in_memory_blocks: usize,
802        requests_count: Option<Range<u8>>,
803        withdrawals_count: Option<Range<u8>>,
804        tx_count: impl RangeBounds<u8>,
805    ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
806        let block_range = (database_blocks + in_memory_blocks - 1) as u64;
807
808        let tx_start = match tx_count.start_bound() {
809            Bound::Included(&n) | Bound::Excluded(&n) => n,
810            Bound::Unbounded => u8::MIN,
811        };
812        let tx_end = match tx_count.end_bound() {
813            Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
814            Bound::Unbounded => u8::MAX,
815        };
816
817        let blocks = random_block_range(
818            rng,
819            0..=block_range,
820            BlockRangeParams {
821                parent: Some(B256::ZERO),
822                tx_count: tx_start..tx_end,
823                requests_count,
824                withdrawals_count,
825            },
826        );
827        let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
828        (database_blocks.to_vec(), in_memory_blocks.to_vec())
829    }
830
831    #[expect(clippy::type_complexity)]
832    fn provider_with_chain_spec_and_random_blocks(
833        rng: &mut impl Rng,
834        chain_spec: Arc<ChainSpec>,
835        database_blocks: usize,
836        in_memory_blocks: usize,
837        block_range_params: BlockRangeParams,
838    ) -> eyre::Result<(
839        BlockchainProvider<MockNodeTypesWithDB>,
840        Vec<SealedBlock<Block>>,
841        Vec<SealedBlock<Block>>,
842        Vec<Vec<Receipt>>,
843    )> {
844        let (database_blocks, in_memory_blocks) = random_blocks(
845            rng,
846            database_blocks,
847            in_memory_blocks,
848            block_range_params.requests_count,
849            block_range_params.withdrawals_count,
850            block_range_params.tx_count,
851        );
852
853        let receipts: Vec<Vec<_>> = database_blocks
854            .iter()
855            .chain(in_memory_blocks.iter())
856            .map(|block| block.body().transactions.iter())
857            .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2), None)).collect())
858            .collect();
859
860        let factory = create_test_provider_factory_with_chain_spec(chain_spec);
861        let provider_rw = factory.database_provider_rw()?;
862
863        // Insert blocks into the database
864        for block in &database_blocks {
865            provider_rw.insert_block(
866                block.clone().try_recover().expect("failed to seal block with senders"),
867            )?;
868        }
869
870        // Insert receipts into the database
871        if let Some(first_block) = database_blocks.first() {
872            provider_rw.write_state(
873                &ExecutionOutcome {
874                    first_block: first_block.number,
875                    receipts: receipts.iter().take(database_blocks.len()).cloned().collect(),
876                    ..Default::default()
877                },
878                OriginalValuesKnown::No,
879            )?;
880        }
881
882        provider_rw.commit()?;
883
884        let provider = BlockchainProvider::new(factory)?;
885
886        // Insert the rest of the blocks and receipts into the in-memory state
887        let chain = NewCanonicalChain::Commit {
888            new: in_memory_blocks
889                .iter()
890                .map(|block| {
891                    let senders = block.senders().expect("failed to recover senders");
892                    let block_receipts = receipts.get(block.number as usize).unwrap().clone();
893                    let execution_outcome =
894                        ExecutionOutcome { receipts: vec![block_receipts], ..Default::default() };
895
896                    ExecutedBlock {
897                        recovered_block: Arc::new(RecoveredBlock::new_sealed(
898                            block.clone(),
899                            senders,
900                        )),
901                        execution_output: execution_outcome.into(),
902                        ..Default::default()
903                    }
904                })
905                .collect(),
906        };
907        provider.canonical_in_memory_state.update_chain(chain);
908
909        // Get canonical, safe, and finalized blocks
910        let blocks = database_blocks.iter().chain(in_memory_blocks.iter()).collect::<Vec<_>>();
911        let block_count = blocks.len();
912        let canonical_block = blocks.get(block_count - 1).unwrap();
913        let safe_block = blocks.get(block_count - 2).unwrap();
914        let finalized_block = blocks.get(block_count - 3).unwrap();
915
916        // Set the canonical head, safe, and finalized blocks
917        provider.set_canonical_head(canonical_block.clone_sealed_header());
918        provider.set_safe(safe_block.clone_sealed_header());
919        provider.set_finalized(finalized_block.clone_sealed_header());
920
921        Ok((provider, database_blocks.clone(), in_memory_blocks.clone(), receipts))
922    }
923
924    #[expect(clippy::type_complexity)]
925    fn provider_with_random_blocks(
926        rng: &mut impl Rng,
927        database_blocks: usize,
928        in_memory_blocks: usize,
929        block_range_params: BlockRangeParams,
930    ) -> eyre::Result<(
931        BlockchainProvider<MockNodeTypesWithDB>,
932        Vec<SealedBlock<Block>>,
933        Vec<SealedBlock<Block>>,
934        Vec<Vec<Receipt>>,
935    )> {
936        provider_with_chain_spec_and_random_blocks(
937            rng,
938            MAINNET.clone(),
939            database_blocks,
940            in_memory_blocks,
941            block_range_params,
942        )
943    }
944
945    /// This will persist the last block in-memory and delete it from
946    /// `canonical_in_memory_state` right after a database read transaction is created.
947    ///
948    /// This simulates a RPC method having a different view than when its database transaction was
949    /// created.
950    fn persist_block_after_db_tx_creation(
951        provider: BlockchainProvider<MockNodeTypesWithDB>,
952        block_number: BlockNumber,
953    ) {
954        let hook_provider = provider.clone();
955        provider.database.db_ref().set_post_transaction_hook(Box::new(move || {
956            if let Some(state) = hook_provider.canonical_in_memory_state.head_state() &&
957                state.anchor().number + 1 == block_number
958            {
959                let mut lowest_memory_block =
960                    state.parent_state_chain().last().expect("qed").block();
961                let num_hash = lowest_memory_block.recovered_block().num_hash();
962
963                let mut execution_output = (*lowest_memory_block.execution_output).clone();
964                execution_output.first_block = lowest_memory_block.recovered_block().number;
965                lowest_memory_block.execution_output = Arc::new(execution_output);
966
967                // Push to disk
968                let provider_rw = hook_provider.database_provider_rw().unwrap();
969                provider_rw.save_blocks(vec![lowest_memory_block]).unwrap();
970                provider_rw.commit().unwrap();
971
972                // Remove from memory
973                hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);
974            }
975        }));
976    }
977
978    #[test]
979    fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
980        // Initialize random number generator and provider factory
981        let mut rng = generators::rng();
982        let factory = create_test_provider_factory();
983
984        // Generate 10 random blocks and split into database and in-memory blocks
985        let blocks = random_block_range(
986            &mut rng,
987            0..=10,
988            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
989        );
990        let (database_blocks, in_memory_blocks) = blocks.split_at(5);
991
992        // Insert first 5 blocks into the database
993        let provider_rw = factory.provider_rw()?;
994        for block in database_blocks {
995            provider_rw.insert_block(
996                block.clone().try_recover().expect("failed to seal block with senders"),
997            )?;
998        }
999        provider_rw.commit()?;
1000
1001        // Create a new provider
1002        let provider = BlockchainProvider::new(factory)?;
1003
1004        // Useful blocks
1005        let first_db_block = database_blocks.first().unwrap();
1006        let first_in_mem_block = in_memory_blocks.first().unwrap();
1007        let last_in_mem_block = in_memory_blocks.last().unwrap();
1008
1009        // No block in memory before setting in memory state
1010        assert_eq!(provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?, None);
1011        assert_eq!(
1012            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1013            None
1014        );
1015        // No pending block in memory
1016        assert_eq!(
1017            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1018            None
1019        );
1020
1021        // Insert first block into the in-memory state
1022        let in_memory_block_senders =
1023            first_in_mem_block.senders().expect("failed to recover senders");
1024        let chain = NewCanonicalChain::Commit {
1025            new: vec![ExecutedBlock {
1026                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1027                    first_in_mem_block.clone(),
1028                    in_memory_block_senders,
1029                )),
1030                ..Default::default()
1031            }],
1032        };
1033        provider.canonical_in_memory_state.update_chain(chain);
1034
1035        // Now the block should be found in memory
1036        assert_eq!(
1037            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1038            Some(first_in_mem_block.clone().into_block())
1039        );
1040        assert_eq!(
1041            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1042            Some(first_in_mem_block.clone().into_block())
1043        );
1044
1045        // Find the first block in database by hash
1046        assert_eq!(
1047            provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1048            Some(first_db_block.clone().into_block())
1049        );
1050        assert_eq!(
1051            provider.find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1052            Some(first_db_block.clone().into_block())
1053        );
1054
1055        // No pending block in database
1056        assert_eq!(provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?, None);
1057
1058        // Insert the last block into the pending state
1059        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1060            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1061                last_in_mem_block.clone(),
1062                Default::default(),
1063            )),
1064            ..Default::default()
1065        });
1066
1067        // Now the last block should be found in memory
1068        assert_eq!(
1069            provider.find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1070            Some(last_in_mem_block.clone().into_block())
1071        );
1072
1073        Ok(())
1074    }
1075
1076    #[test]
1077    fn test_block_reader_block() -> eyre::Result<()> {
1078        // Initialize random number generator and provider factory
1079        let mut rng = generators::rng();
1080        let factory = create_test_provider_factory();
1081
1082        // Generate 10 random blocks and split into database and in-memory blocks
1083        let blocks = random_block_range(
1084            &mut rng,
1085            0..=10,
1086            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1087        );
1088        let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1089
1090        // Insert first 5 blocks into the database
1091        let provider_rw = factory.provider_rw()?;
1092        for block in database_blocks {
1093            provider_rw.insert_block(
1094                block.clone().try_recover().expect("failed to seal block with senders"),
1095            )?;
1096        }
1097        provider_rw.commit()?;
1098
1099        // Create a new provider
1100        let provider = BlockchainProvider::new(factory)?;
1101
1102        // First in memory block
1103        let first_in_mem_block = in_memory_blocks.first().unwrap();
1104        // First database block
1105        let first_db_block = database_blocks.first().unwrap();
1106
1107        // First in memory block should not be found yet as not integrated to the in-memory state
1108        assert_eq!(provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?, None);
1109        assert_eq!(provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?, None);
1110
1111        // Insert first block into the in-memory state
1112        let in_memory_block_senders =
1113            first_in_mem_block.senders().expect("failed to recover senders");
1114        let chain = NewCanonicalChain::Commit {
1115            new: vec![ExecutedBlock {
1116                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1117                    first_in_mem_block.clone(),
1118                    in_memory_block_senders,
1119                )),
1120                ..Default::default()
1121            }],
1122        };
1123        provider.canonical_in_memory_state.update_chain(chain);
1124
1125        // First in memory block should be found
1126        assert_eq!(
1127            provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1128            Some(first_in_mem_block.clone().into_block())
1129        );
1130        assert_eq!(
1131            provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1132            Some(first_in_mem_block.clone().into_block())
1133        );
1134
1135        // First database block should be found
1136        assert_eq!(
1137            provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1138            Some(first_db_block.clone().into_block())
1139        );
1140        assert_eq!(
1141            provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1142            Some(first_db_block.clone().into_block())
1143        );
1144
1145        Ok(())
1146    }
1147
1148    #[test]
1149    fn test_block_reader_pending_block() -> eyre::Result<()> {
1150        let mut rng = generators::rng();
1151        let (provider, _, _, _) = provider_with_random_blocks(
1152            &mut rng,
1153            TEST_BLOCKS_COUNT,
1154            TEST_BLOCKS_COUNT,
1155            BlockRangeParams::default(),
1156        )?;
1157
1158        // Generate a random block
1159        let mut rng = generators::rng();
1160        let block = random_block(
1161            &mut rng,
1162            0,
1163            BlockParams { parent: Some(B256::ZERO), ..Default::default() },
1164        );
1165
1166        // Set the block as pending
1167        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1168            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1169                block.clone(),
1170                block.senders().unwrap(),
1171            )),
1172            ..Default::default()
1173        });
1174
1175        // Assertions related to the pending block
1176
1177        assert_eq!(
1178            provider.pending_block()?,
1179            Some(RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()))
1180        );
1181
1182        assert_eq!(
1183            provider.pending_block_and_receipts()?,
1184            Some((RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap()), vec![]))
1185        );
1186
1187        Ok(())
1188    }
1189
1190    #[test]
1191    fn test_block_body_indices() -> eyre::Result<()> {
1192        // Create a new provider
1193        let mut rng = generators::rng();
1194        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1195            &mut rng,
1196            TEST_BLOCKS_COUNT,
1197            TEST_BLOCKS_COUNT,
1198            BlockRangeParams {
1199                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1200                ..Default::default()
1201            },
1202        )?;
1203
1204        let first_in_mem_block = in_memory_blocks.first().unwrap();
1205
1206        // Insert the first block into the in-memory state
1207        let in_memory_block_senders =
1208            first_in_mem_block.senders().expect("failed to recover senders");
1209        let chain = NewCanonicalChain::Commit {
1210            new: vec![ExecutedBlock {
1211                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1212                    first_in_mem_block.clone(),
1213                    in_memory_block_senders,
1214                )),
1215                ..Default::default()
1216            }],
1217        };
1218        provider.canonical_in_memory_state.update_chain(chain);
1219
1220        let first_db_block = database_blocks.first().unwrap().clone();
1221        let first_in_mem_block = in_memory_blocks.first().unwrap().clone();
1222
1223        // First database block body indices should be found
1224        assert_eq!(
1225            provider.block_body_indices(first_db_block.number)?.unwrap(),
1226            StoredBlockBodyIndices { first_tx_num: 0, tx_count: 4 }
1227        );
1228
1229        // First in-memory block body indices should be found with the first tx after the database
1230        // blocks
1231        assert_eq!(
1232            provider.block_body_indices(first_in_mem_block.number)?.unwrap(),
1233            StoredBlockBodyIndices { first_tx_num: 20, tx_count: 4 }
1234        );
1235
1236        // A random block number should return None as the block is not found
1237        let mut rng = rand::rng();
1238        let random_block_number: u64 = rng.random();
1239        assert_eq!(provider.block_body_indices(random_block_number)?, None);
1240
1241        Ok(())
1242    }
1243
1244    #[test]
1245    fn test_block_hash_reader() -> eyre::Result<()> {
1246        let mut rng = generators::rng();
1247        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1248            &mut rng,
1249            TEST_BLOCKS_COUNT,
1250            TEST_BLOCKS_COUNT,
1251            BlockRangeParams::default(),
1252        )?;
1253
1254        let database_block = database_blocks.first().unwrap().clone();
1255        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1256
1257        assert_eq!(provider.block_hash(database_block.number)?, Some(database_block.hash()));
1258        assert_eq!(provider.block_hash(in_memory_block.number)?, Some(in_memory_block.hash()));
1259
1260        assert_eq!(
1261            provider.canonical_hashes_range(0, 10)?,
1262            [database_blocks, in_memory_blocks]
1263                .concat()
1264                .iter()
1265                .map(|block| block.hash())
1266                .collect::<Vec<_>>()
1267        );
1268
1269        Ok(())
1270    }
1271
1272    #[test]
1273    fn test_header_provider() -> eyre::Result<()> {
1274        let mut rng = generators::rng();
1275        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1276            &mut rng,
1277            TEST_BLOCKS_COUNT,
1278            TEST_BLOCKS_COUNT,
1279            BlockRangeParams::default(),
1280        )?;
1281
1282        // make sure that the finalized block is on db
1283        let finalized_block = database_blocks.get(database_blocks.len() - 3).unwrap();
1284        provider.set_finalized(finalized_block.clone_sealed_header());
1285
1286        let blocks = [database_blocks, in_memory_blocks].concat();
1287
1288        assert_eq!(
1289            provider.sealed_headers_while(0..=10, |header| header.number <= 8)?,
1290            blocks
1291                .iter()
1292                .take_while(|header| header.number <= 8)
1293                .map(|b| b.clone_sealed_header())
1294                .collect::<Vec<_>>()
1295        );
1296
1297        Ok(())
1298    }
1299
1300    #[tokio::test]
1301    async fn test_canon_state_subscriptions() -> eyre::Result<()> {
1302        let factory = create_test_provider_factory();
1303
1304        // Generate a random block to initialize the blockchain provider.
1305        let mut test_block_builder = TestBlockBuilder::eth();
1306        let block_1 = test_block_builder.generate_random_block(0, B256::ZERO);
1307        let block_hash_1 = block_1.hash();
1308
1309        // Insert and commit the block.
1310        let provider_rw = factory.provider_rw()?;
1311        provider_rw.insert_block(block_1)?;
1312        provider_rw.commit()?;
1313
1314        let provider = BlockchainProvider::new(factory)?;
1315
1316        // Subscribe twice for canonical state updates.
1317        let in_memory_state = provider.canonical_in_memory_state();
1318        let mut rx_1 = provider.subscribe_to_canonical_state();
1319        let mut rx_2 = provider.subscribe_to_canonical_state();
1320
1321        // Send and receive commit notifications.
1322        let block_2 = test_block_builder.generate_random_block(1, block_hash_1);
1323        let chain = Chain::new(vec![block_2], ExecutionOutcome::default(), None);
1324        let commit = CanonStateNotification::Commit { new: Arc::new(chain.clone()) };
1325        in_memory_state.notify_canon_state(commit.clone());
1326        let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1327        assert_eq!(notification_1, Ok(commit.clone()));
1328        assert_eq!(notification_2, Ok(commit.clone()));
1329
1330        // Send and receive re-org notifications.
1331        let block_3 = test_block_builder.generate_random_block(1, block_hash_1);
1332        let block_4 = test_block_builder.generate_random_block(2, block_3.hash());
1333        let new_chain = Chain::new(vec![block_3, block_4], ExecutionOutcome::default(), None);
1334        let re_org =
1335            CanonStateNotification::Reorg { old: Arc::new(chain), new: Arc::new(new_chain) };
1336        in_memory_state.notify_canon_state(re_org.clone());
1337        let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1338        assert_eq!(notification_1, Ok(re_org.clone()));
1339        assert_eq!(notification_2, Ok(re_org.clone()));
1340
1341        Ok(())
1342    }
1343
1344    #[test]
1345    fn test_block_num_reader() -> eyre::Result<()> {
1346        let mut rng = generators::rng();
1347        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1348            &mut rng,
1349            TEST_BLOCKS_COUNT,
1350            TEST_BLOCKS_COUNT,
1351            BlockRangeParams::default(),
1352        )?;
1353
1354        assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number);
1355        assert_eq!(provider.last_block_number()?, database_blocks.last().unwrap().number);
1356
1357        let database_block = database_blocks.first().unwrap().clone();
1358        let in_memory_block = in_memory_blocks.first().unwrap().clone();
1359        assert_eq!(provider.block_number(database_block.hash())?, Some(database_block.number));
1360        assert_eq!(provider.block_number(in_memory_block.hash())?, Some(in_memory_block.number));
1361
1362        Ok(())
1363    }
1364
1365    #[test]
1366    fn test_block_reader_id_ext_block_by_id() -> eyre::Result<()> {
1367        let mut rng = generators::rng();
1368        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1369            &mut rng,
1370            TEST_BLOCKS_COUNT,
1371            TEST_BLOCKS_COUNT,
1372            BlockRangeParams::default(),
1373        )?;
1374
1375        let database_block = database_blocks.first().unwrap().clone();
1376        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1377
1378        let block_number = database_block.number;
1379        let block_hash = database_block.hash();
1380
1381        assert_eq!(
1382            provider.block_by_id(block_number.into()).unwrap(),
1383            Some(database_block.clone().into_block())
1384        );
1385        assert_eq!(
1386            provider.block_by_id(block_hash.into()).unwrap(),
1387            Some(database_block.into_block())
1388        );
1389
1390        let block_number = in_memory_block.number;
1391        let block_hash = in_memory_block.hash();
1392        assert_eq!(
1393            provider.block_by_id(block_number.into()).unwrap(),
1394            Some(in_memory_block.clone().into_block())
1395        );
1396        assert_eq!(
1397            provider.block_by_id(block_hash.into()).unwrap(),
1398            Some(in_memory_block.into_block())
1399        );
1400
1401        Ok(())
1402    }
1403
1404    #[test]
1405    fn test_block_reader_id_ext_header_by_number_or_tag() -> eyre::Result<()> {
1406        let mut rng = generators::rng();
1407        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1408            &mut rng,
1409            TEST_BLOCKS_COUNT,
1410            TEST_BLOCKS_COUNT,
1411            BlockRangeParams::default(),
1412        )?;
1413
1414        let database_block = database_blocks.first().unwrap().clone();
1415
1416        let in_memory_block_count = in_memory_blocks.len();
1417        let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1418        let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1419        let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1420
1421        let block_number = database_block.number;
1422        assert_eq!(
1423            provider.header_by_number_or_tag(block_number.into()).unwrap(),
1424            Some(database_block.header().clone())
1425        );
1426        assert_eq!(
1427            provider.sealed_header_by_number_or_tag(block_number.into())?,
1428            Some(database_block.clone_sealed_header())
1429        );
1430
1431        assert_eq!(
1432            provider.header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1433            Some(canonical_block.header().clone())
1434        );
1435        assert_eq!(
1436            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1437            Some(canonical_block.clone_sealed_header())
1438        );
1439
1440        assert_eq!(
1441            provider.header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1442            Some(safe_block.header().clone())
1443        );
1444        assert_eq!(
1445            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1446            Some(safe_block.clone_sealed_header())
1447        );
1448
1449        assert_eq!(
1450            provider.header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1451            Some(finalized_block.header().clone())
1452        );
1453        assert_eq!(
1454            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1455            Some(finalized_block.clone_sealed_header())
1456        );
1457
1458        Ok(())
1459    }
1460
1461    #[test]
1462    fn test_block_reader_id_ext_header_by_id() -> eyre::Result<()> {
1463        let mut rng = generators::rng();
1464        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1465            &mut rng,
1466            TEST_BLOCKS_COUNT,
1467            TEST_BLOCKS_COUNT,
1468            BlockRangeParams::default(),
1469        )?;
1470
1471        let database_block = database_blocks.first().unwrap().clone();
1472        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1473
1474        let block_number = database_block.number;
1475        let block_hash = database_block.hash();
1476
1477        assert_eq!(
1478            provider.header_by_id(block_number.into()).unwrap(),
1479            Some(database_block.header().clone())
1480        );
1481        assert_eq!(
1482            provider.sealed_header_by_id(block_number.into()).unwrap(),
1483            Some(database_block.clone_sealed_header())
1484        );
1485
1486        assert_eq!(
1487            provider.header_by_id(block_hash.into()).unwrap(),
1488            Some(database_block.header().clone())
1489        );
1490        assert_eq!(
1491            provider.sealed_header_by_id(block_hash.into()).unwrap(),
1492            Some(database_block.clone_sealed_header())
1493        );
1494
1495        let block_number = in_memory_block.number;
1496        let block_hash = in_memory_block.hash();
1497
1498        assert_eq!(
1499            provider.header_by_id(block_number.into()).unwrap(),
1500            Some(in_memory_block.header().clone())
1501        );
1502        assert_eq!(
1503            provider.sealed_header_by_id(block_number.into()).unwrap(),
1504            Some(in_memory_block.clone_sealed_header())
1505        );
1506
1507        assert_eq!(
1508            provider.header_by_id(block_hash.into()).unwrap(),
1509            Some(in_memory_block.header().clone())
1510        );
1511        assert_eq!(
1512            provider.sealed_header_by_id(block_hash.into()).unwrap(),
1513            Some(in_memory_block.clone_sealed_header())
1514        );
1515
1516        Ok(())
1517    }
1518
1519    #[test]
1520    fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> {
1521        let mut rng = generators::rng();
1522        let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1523            &mut rng,
1524            TEST_BLOCKS_COUNT,
1525            TEST_BLOCKS_COUNT,
1526            BlockRangeParams { tx_count: 1..3, ..Default::default() },
1527        )?;
1528
1529        let database_block = database_blocks.first().unwrap().clone();
1530        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1531
1532        let block_number = database_block.number;
1533        let block_hash = database_block.hash();
1534
1535        assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1536        assert!(!provider
1537            .receipts_by_number_or_tag(database_block.number.into())?
1538            .unwrap()
1539            .is_empty());
1540
1541        assert_eq!(
1542            provider.receipts_by_block_id(block_number.into())?.unwrap(),
1543            receipts.get(block_number as usize).unwrap().clone()
1544        );
1545        assert_eq!(
1546            provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1547            receipts.get(block_number as usize).unwrap().clone()
1548        );
1549
1550        let block_number = in_memory_block.number;
1551        let block_hash = in_memory_block.hash();
1552
1553        assert_eq!(
1554            provider.receipts_by_block_id(block_number.into())?.unwrap(),
1555            receipts.get(block_number as usize).unwrap().clone()
1556        );
1557        assert_eq!(
1558            provider.receipts_by_block_id(block_hash.into())?.unwrap(),
1559            receipts.get(block_number as usize).unwrap().clone()
1560        );
1561
1562        Ok(())
1563    }
1564
1565    #[test]
1566    fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> {
1567        let mut rng = generators::rng();
1568        let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
1569            &mut rng,
1570            TEST_BLOCKS_COUNT,
1571            TEST_BLOCKS_COUNT,
1572            BlockRangeParams { tx_count: 1..3, ..Default::default() },
1573        )?;
1574
1575        let database_block = database_blocks.first().unwrap().clone();
1576
1577        let in_memory_block_count = in_memory_blocks.len();
1578        let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1579        let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1580        let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1581
1582        assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
1583        assert!(!provider
1584            .receipts_by_number_or_tag(database_block.number.into())?
1585            .unwrap()
1586            .is_empty());
1587
1588        assert_eq!(
1589            provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap(),
1590            receipts.get(database_block.number as usize).unwrap().clone()
1591        );
1592        assert_eq!(
1593            provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(),
1594            receipts.get(canonical_block.number as usize).unwrap().clone()
1595        );
1596        assert_eq!(
1597            provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap(),
1598            receipts.get(safe_block.number as usize).unwrap().clone()
1599        );
1600        assert_eq!(
1601            provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap(),
1602            receipts.get(finalized_block.number as usize).unwrap().clone()
1603        );
1604
1605        Ok(())
1606    }
1607
1608    #[test]
1609    fn test_changeset_reader() -> eyre::Result<()> {
1610        let mut rng = generators::rng();
1611
1612        let (database_blocks, in_memory_blocks) =
1613            random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
1614
1615        let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
1616        let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
1617        let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
1618
1619        let accounts = random_eoa_accounts(&mut rng, 2);
1620
1621        let (database_changesets, database_state) = random_changeset_range(
1622            &mut rng,
1623            &database_blocks,
1624            accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
1625            0..0,
1626            0..0,
1627        );
1628        let (in_memory_changesets, in_memory_state) = random_changeset_range(
1629            &mut rng,
1630            &in_memory_blocks,
1631            database_state
1632                .iter()
1633                .map(|(address, (account, storage))| (*address, (*account, storage.clone()))),
1634            0..0,
1635            0..0,
1636        );
1637
1638        let factory = create_test_provider_factory();
1639
1640        let provider_rw = factory.provider_rw()?;
1641        provider_rw.append_blocks_with_state(
1642            database_blocks
1643                .into_iter()
1644                .map(|b| b.try_recover().expect("failed to seal block with senders"))
1645                .collect(),
1646            &ExecutionOutcome {
1647                bundle: BundleState::new(
1648                    database_state.into_iter().map(|(address, (account, _))| {
1649                        (address, None, Some(account.into()), Default::default())
1650                    }),
1651                    database_changesets
1652                        .iter()
1653                        .map(|block_changesets| {
1654                            block_changesets.iter().map(|(address, account, _)| {
1655                                (*address, Some(Some((*account).into())), [])
1656                            })
1657                        })
1658                        .collect::<Vec<_>>(),
1659                    Vec::new(),
1660                ),
1661                first_block: first_database_block,
1662                ..Default::default()
1663            },
1664            Default::default(),
1665        )?;
1666        provider_rw.commit()?;
1667
1668        let provider = BlockchainProvider::new(factory)?;
1669
1670        let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
1671        let chain = NewCanonicalChain::Commit {
1672            new: vec![in_memory_blocks
1673                .first()
1674                .map(|block| {
1675                    let senders = block.senders().expect("failed to recover senders");
1676                    ExecutedBlock {
1677                        recovered_block: Arc::new(RecoveredBlock::new_sealed(
1678                            block.clone(),
1679                            senders,
1680                        )),
1681                        execution_output: Arc::new(ExecutionOutcome {
1682                            bundle: BundleState::new(
1683                                in_memory_state.into_iter().map(|(address, (account, _))| {
1684                                    (address, None, Some(account.into()), Default::default())
1685                                }),
1686                                [in_memory_changesets.iter().map(|(address, account, _)| {
1687                                    (*address, Some(Some((*account).into())), Vec::new())
1688                                })],
1689                                [],
1690                            ),
1691                            first_block: first_in_memory_block,
1692                            ..Default::default()
1693                        }),
1694                        ..Default::default()
1695                    }
1696                })
1697                .unwrap()],
1698        };
1699        provider.canonical_in_memory_state.update_chain(chain);
1700
1701        assert_eq!(
1702            provider.account_block_changeset(last_database_block).unwrap(),
1703            database_changesets
1704                .into_iter()
1705                .next_back()
1706                .unwrap()
1707                .into_iter()
1708                .sorted_by_key(|(address, _, _)| *address)
1709                .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1710                .collect::<Vec<_>>()
1711        );
1712        assert_eq!(
1713            provider.account_block_changeset(first_in_memory_block).unwrap(),
1714            in_memory_changesets
1715                .into_iter()
1716                .sorted_by_key(|(address, _, _)| *address)
1717                .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
1718                .collect::<Vec<_>>()
1719        );
1720
1721        Ok(())
1722    }
1723
1724    #[test]
1725    fn test_state_provider_factory() -> eyre::Result<()> {
1726        let mut rng = generators::rng();
1727
1728        // test in-memory state use-cases
1729        let (in_memory_provider, _, in_memory_blocks, _) = provider_with_random_blocks(
1730            &mut rng,
1731            TEST_BLOCKS_COUNT,
1732            TEST_BLOCKS_COUNT,
1733            BlockRangeParams::default(),
1734        )?;
1735
1736        // test database state use-cases
1737        let (only_database_provider, database_blocks, _, _) = provider_with_random_blocks(
1738            &mut rng,
1739            TEST_BLOCKS_COUNT,
1740            0,
1741            BlockRangeParams::default(),
1742        )?;
1743
1744        let blocks = [database_blocks.clone(), in_memory_blocks.clone()].concat();
1745        let first_in_memory_block = in_memory_blocks.first().unwrap();
1746        let first_db_block = database_blocks.first().unwrap();
1747
1748        // test latest state
1749        assert_eq!(
1750            first_in_memory_block.hash(),
1751            in_memory_provider.latest().unwrap().block_hash(first_in_memory_block.number)?.unwrap()
1752        );
1753        // test latest falls back to database state when there's no in-memory block
1754        assert_eq!(
1755            first_db_block.hash(),
1756            only_database_provider.latest().unwrap().block_hash(first_db_block.number)?.unwrap()
1757        );
1758
1759        // test history by block number
1760        assert_eq!(
1761            first_in_memory_block.hash(),
1762            in_memory_provider
1763                .history_by_block_number(first_in_memory_block.number)?
1764                .block_hash(first_in_memory_block.number)?
1765                .unwrap()
1766        );
1767        assert_eq!(
1768            first_db_block.hash(),
1769            only_database_provider
1770                .history_by_block_number(first_db_block.number)?
1771                .block_hash(first_db_block.number)?
1772                .unwrap()
1773        );
1774        assert_eq!(
1775            first_in_memory_block.hash(),
1776            in_memory_provider
1777                .history_by_block_hash(first_in_memory_block.hash())?
1778                .block_hash(first_in_memory_block.number)?
1779                .unwrap()
1780        );
1781        assert!(only_database_provider.history_by_block_hash(B256::random()).is_err());
1782
1783        // test state by block hash
1784        assert_eq!(
1785            first_in_memory_block.hash(),
1786            in_memory_provider
1787                .state_by_block_hash(first_in_memory_block.hash())?
1788                .block_hash(first_in_memory_block.number)?
1789                .unwrap()
1790        );
1791        assert_eq!(
1792            first_db_block.hash(),
1793            only_database_provider
1794                .state_by_block_hash(first_db_block.hash())?
1795                .block_hash(first_db_block.number)?
1796                .unwrap()
1797        );
1798        assert!(only_database_provider.state_by_block_hash(B256::random()).is_err());
1799
1800        // test pending without pending state- falls back to latest
1801        assert_eq!(
1802            first_in_memory_block.hash(),
1803            in_memory_provider
1804                .pending()
1805                .unwrap()
1806                .block_hash(first_in_memory_block.number)
1807                .unwrap()
1808                .unwrap()
1809        );
1810
1811        // adding a pending block to state can test pending() and  pending_state_by_hash() function
1812        let pending_block = database_blocks[database_blocks.len() - 1].clone();
1813        only_database_provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1814            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1815                pending_block.clone(),
1816                Default::default(),
1817            )),
1818            ..Default::default()
1819        });
1820
1821        assert_eq!(
1822            pending_block.hash(),
1823            only_database_provider
1824                .pending()
1825                .unwrap()
1826                .block_hash(pending_block.number)
1827                .unwrap()
1828                .unwrap()
1829        );
1830
1831        assert_eq!(
1832            pending_block.hash(),
1833            only_database_provider
1834                .pending_state_by_hash(pending_block.hash())?
1835                .unwrap()
1836                .block_hash(pending_block.number)?
1837                .unwrap()
1838        );
1839
1840        // test state by block number or tag
1841        assert_eq!(
1842            first_in_memory_block.hash(),
1843            in_memory_provider
1844                .state_by_block_number_or_tag(BlockNumberOrTag::Number(
1845                    first_in_memory_block.number
1846                ))?
1847                .block_hash(first_in_memory_block.number)?
1848                .unwrap()
1849        );
1850        assert_eq!(
1851            first_in_memory_block.hash(),
1852            in_memory_provider
1853                .state_by_block_number_or_tag(BlockNumberOrTag::Latest)?
1854                .block_hash(first_in_memory_block.number)?
1855                .unwrap()
1856        );
1857        // test state by block tag for safe block
1858        let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
1859        in_memory_provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
1860        assert_eq!(
1861            safe_block.hash(),
1862            in_memory_provider
1863                .state_by_block_number_or_tag(BlockNumberOrTag::Safe)?
1864                .block_hash(safe_block.number)?
1865                .unwrap()
1866        );
1867        // test state by block tag for finalized block
1868        let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
1869        in_memory_provider
1870            .canonical_in_memory_state
1871            .set_finalized(finalized_block.clone_sealed_header());
1872        assert_eq!(
1873            finalized_block.hash(),
1874            in_memory_provider
1875                .state_by_block_number_or_tag(BlockNumberOrTag::Finalized)?
1876                .block_hash(finalized_block.number)?
1877                .unwrap()
1878        );
1879        // test state by block tag for earliest block
1880        let earliest_block = blocks.first().unwrap().clone();
1881        assert_eq!(
1882            earliest_block.hash(),
1883            only_database_provider
1884                .state_by_block_number_or_tag(BlockNumberOrTag::Earliest)?
1885                .block_hash(earliest_block.number)?
1886                .unwrap()
1887        );
1888
1889        Ok(())
1890    }
1891
1892    #[test]
1893    fn test_block_id_reader() -> eyre::Result<()> {
1894        // Create a new provider
1895        let mut rng = generators::rng();
1896        let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
1897            &mut rng,
1898            TEST_BLOCKS_COUNT,
1899            TEST_BLOCKS_COUNT,
1900            BlockRangeParams::default(),
1901        )?;
1902
1903        // Set the pending block in memory
1904        let pending_block = in_memory_blocks.last().unwrap();
1905        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1906            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1907                pending_block.clone(),
1908                Default::default(),
1909            )),
1910            ..Default::default()
1911        });
1912
1913        // Set the safe block in memory
1914        let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
1915        provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
1916
1917        // Set the finalized block in memory
1918        let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
1919        provider.canonical_in_memory_state.set_finalized(finalized_block.clone_sealed_header());
1920
1921        // Verify the pending block number and hash
1922        assert_eq!(
1923            provider.pending_block_num_hash()?,
1924            Some(BlockNumHash { number: pending_block.number, hash: pending_block.hash() })
1925        );
1926
1927        // Verify the safe block number and hash
1928        assert_eq!(
1929            provider.safe_block_num_hash()?,
1930            Some(BlockNumHash { number: safe_block.number, hash: safe_block.hash() })
1931        );
1932
1933        // Verify the finalized block number and hash
1934        assert_eq!(
1935            provider.finalized_block_num_hash()?,
1936            Some(BlockNumHash { number: finalized_block.number, hash: finalized_block.hash() })
1937        );
1938
1939        Ok(())
1940    }
1941
1942    macro_rules! test_by_tx_range {
1943        ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
1944
1945            // Get the number methods being tested.
1946            // Since each method tested will move a block from memory to storage, this ensures we have enough.
1947            let extra_blocks = [$(stringify!($method)),*].len();
1948
1949            let mut rng = generators::rng();
1950            let (provider, mut database_blocks, mut in_memory_blocks, receipts) = provider_with_random_blocks(
1951                &mut rng,
1952                TEST_BLOCKS_COUNT,
1953                TEST_BLOCKS_COUNT + extra_blocks,
1954                BlockRangeParams {
1955                    tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1956                    ..Default::default()
1957                },
1958            )?;
1959
1960            $(
1961                // Since data moves for each tried method, need to recalculate everything
1962                let db_tx_count =
1963                    database_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
1964                let in_mem_tx_count =
1965                    in_memory_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
1966
1967                let db_range = 0..=(db_tx_count - 1);
1968                let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end());
1969
1970                // Retrieve the expected database data
1971                let database_data =
1972                    database_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
1973                assert_eq!(provider.$method(db_range.clone())?, database_data, "full db data");
1974
1975                // Retrieve the expected in-memory data
1976                let in_memory_data =
1977                    in_memory_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
1978                assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data, "full mem data");
1979
1980                // Test partial in-memory range
1981                assert_eq!(
1982                    &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
1983                    &in_memory_data[1..in_memory_data.len() - 1],
1984                    "partial mem data"
1985                );
1986
1987                // Test range in memory to unbounded end
1988                assert_eq!(provider.$method(in_mem_range.start() + 1..)?, &in_memory_data[1..], "unbounded mem data");
1989
1990                // Test last element in-memory
1991                assert_eq!(provider.$method(in_mem_range.end()..)?, &in_memory_data[in_memory_data.len() -1 ..], "last mem data");
1992
1993                // Test range that spans database and in-memory with unbounded end
1994                assert_eq!(
1995                    provider.$method(in_mem_range.start() - 2..)?,
1996                    database_data[database_data.len() - 2..]
1997                        .iter()
1998                        .chain(&in_memory_data[..])
1999                        .cloned()
2000                        .collect::<Vec<_>>(),
2001                    "unbounded span data"
2002                );
2003
2004                // Test range that spans database and in-memory
2005                {
2006                    // This block will be persisted to disk and removed from memory AFTER the first database query. This ensures that we query the in-memory state before the database avoiding any race condition.
2007                    persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2008
2009                    assert_eq!(
2010                        provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2011                        database_data[database_data.len() - 2..]
2012                            .iter()
2013                            .chain(&in_memory_data[..in_memory_data.len() - 1])
2014                            .cloned()
2015                            .collect::<Vec<_>>(),
2016                        "span data"
2017                    );
2018
2019                    // Adjust our blocks accordingly
2020                    database_blocks.push(in_memory_blocks.remove(0));
2021                }
2022
2023                // Test invalid range
2024                let start_tx_num = u64::MAX;
2025                let end_tx_num = u64::MAX;
2026                let result = provider.$method(start_tx_num..end_tx_num)?;
2027                assert!(result.is_empty(), "No data should be found for an invalid transaction range");
2028
2029                // Test empty range
2030                let result = provider.$method(in_mem_range.end()+10..in_mem_range.end()+20)?;
2031                assert!(result.is_empty(), "No data should be found for an empty transaction range");
2032            )*
2033        }};
2034    }
2035
2036    #[test]
2037    fn test_methods_by_tx_range() -> eyre::Result<()> {
2038        test_by_tx_range!([
2039            (senders_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2040                .senders()
2041                .unwrap()),
2042            (transactions_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2043                .body()
2044                .transactions
2045                .clone()),
2046            (receipts_by_tx_range, |block: &SealedBlock<Block>, receipts: &Vec<Vec<Receipt>>| {
2047                receipts[block.number as usize].clone()
2048            })
2049        ]);
2050
2051        Ok(())
2052    }
2053
2054    macro_rules! test_by_block_range {
2055        ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2056            // Get the number methods being tested.
2057            // Since each method tested will move a block from memory to storage, this ensures we have enough.
2058            let extra_blocks = [$(stringify!($method)),*].len();
2059
2060            let mut rng = generators::rng();
2061            let (provider, mut database_blocks, mut in_memory_blocks, _) = provider_with_random_blocks(
2062                &mut rng,
2063                TEST_BLOCKS_COUNT,
2064                TEST_BLOCKS_COUNT + extra_blocks,
2065                BlockRangeParams {
2066                    tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2067                    ..Default::default()
2068                },
2069            )?;
2070
2071            $(
2072                // Since data moves for each tried method, need to recalculate everything
2073                let db_block_count = database_blocks.len() as u64;
2074                let in_mem_block_count = in_memory_blocks.len() as u64;
2075
2076                let db_range = 0..=db_block_count - 1;
2077                let in_mem_range = db_block_count..=(in_mem_block_count + db_range.end());
2078
2079                // Retrieve the expected database data
2080                let database_data =
2081                    database_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2082                assert_eq!(provider.$method(db_range.clone())?, database_data);
2083
2084                // Retrieve the expected in-memory data
2085                let in_memory_data =
2086                    in_memory_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2087                assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data);
2088
2089                // Test partial in-memory range
2090                assert_eq!(
2091                    &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2092                    &in_memory_data[1..in_memory_data.len() - 1]
2093                );
2094
2095                // Test range that spans database and in-memory
2096                {
2097
2098                    // This block will be persisted to disk and removed from memory AFTER the first database query. This ensures that we query the in-memory state before the database avoiding any race condition.
2099                    persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2100
2101                    assert_eq!(
2102                        provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2103                        database_data[database_data.len() - 2..]
2104                            .iter()
2105                            .chain(&in_memory_data[..in_memory_data.len() - 1])
2106                            .cloned()
2107                            .collect::<Vec<_>>()
2108                    );
2109
2110                    // Adjust our blocks accordingly
2111                    database_blocks.push(in_memory_blocks.remove(0));
2112                }
2113
2114                // Test invalid range
2115                let start_block_num = u64::MAX;
2116                let end_block_num = u64::MAX;
2117                let result = provider.$method(start_block_num..=end_block_num-1)?;
2118                assert!(result.is_empty(), "No data should be found for an invalid block range");
2119
2120                // Test valid range with empty results
2121                let result = provider.$method(in_mem_range.end() + 10..=in_mem_range.end() + 20)?;
2122                assert!(result.is_empty(), "No data should be found for an empty block range");
2123            )*
2124        }};
2125    }
2126
2127    #[test]
2128    fn test_methods_by_block_range() -> eyre::Result<()> {
2129        // todo(joshie) add canonical_hashes_range below after changing its interface into range
2130        // instead start end
2131        test_by_block_range!([
2132            (headers_range, |block: &SealedBlock<Block>| block.header().clone()),
2133            (sealed_headers_range, |block: &SealedBlock<Block>| block.clone_sealed_header()),
2134            (block_range, |block: &SealedBlock<Block>| block.clone().into_block()),
2135            (block_with_senders_range, |block: &SealedBlock<Block>| block
2136                .clone()
2137                .try_recover()
2138                .unwrap()),
2139            (recovered_block_range, |block: &SealedBlock<Block>| block
2140                .clone()
2141                .try_recover()
2142                .unwrap()),
2143            (transactions_by_block_range, |block: &SealedBlock<Block>| block
2144                .body()
2145                .transactions
2146                .clone()),
2147        ]);
2148
2149        Ok(())
2150    }
2151
2152    /// Helper macro to call a provider method based on argument count and check its result
2153    macro_rules! call_method {
2154        ($provider:expr, $method:ident, ($($args:expr),*), $expected_item:expr) => {{
2155            let result = $provider.$method($($args),*)?;
2156            assert_eq!(
2157                result,
2158                $expected_item,
2159                "{}: item does not match the expected item for arguments {:?}",
2160                stringify!($method),
2161                ($($args),*)
2162            );
2163        }};
2164
2165        // Handle valid or invalid arguments for one argument
2166        (ONE, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2167            let (arg, expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2168            call_method!($provider, $method, (arg), expected_item);
2169        }};
2170
2171        // Handle valid or invalid arguments for two arguments
2172        (TWO, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2173            let ((arg1, arg2), expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2174            call_method!($provider, $method, (arg1, arg2), expected_item);
2175        }};
2176    }
2177
2178    /// Macro to test non-range methods.
2179    ///
2180    /// ( `NUMBER_ARGUMENTS`, METHOD, FN -> ((`METHOD_ARGUMENT(s)`,...), `EXPECTED_RESULT`),
2181    /// `INVALID_ARGUMENTS`)
2182    macro_rules! test_non_range {
2183    ([$(($arg_count:ident, $method:ident, $item_extractor:expr, $invalid_args:expr)),* $(,)?]) => {{
2184
2185        // Get the number methods being tested.
2186        // Since each method tested will move a block from memory to storage, this ensures we have enough.
2187        let extra_blocks = [$(stringify!($arg_count)),*].len();
2188
2189        let mut rng = generators::rng();
2190        let (provider, mut database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2191            &mut rng,
2192            TEST_BLOCKS_COUNT,
2193            TEST_BLOCKS_COUNT + extra_blocks,
2194            BlockRangeParams {
2195                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2196                ..Default::default()
2197            },
2198        )?;
2199
2200        let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
2201
2202        $(
2203            let tx_hash = |block: &SealedBlock<Block>| *block.body().transactions[0].tx_hash();
2204            let tx_num = |block: &SealedBlock<Block>| {
2205                database_blocks
2206                    .iter()
2207                    .chain(in_memory_blocks.iter())
2208                    .take_while(|b| b.number < block.number)
2209                    .map(|b| b.transaction_count())
2210                    .sum::<usize>() as u64
2211            };
2212
2213            // Ensure that the first generated in-memory block exists
2214            {
2215                // This block will be persisted to disk and removed from memory AFTER the first database query. This ensures that we query the in-memory state before the database avoiding any race condition.
2216                persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2217
2218                call_method!($arg_count, provider, $method, $item_extractor, tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2219
2220                // Move the block as well in our own structures
2221                database_blocks.push(in_memory_blocks.pop_front().unwrap());
2222            }
2223
2224            // database_blocks is changed above
2225            let tx_num = |block: &SealedBlock<Block>| {
2226                database_blocks
2227                    .iter()
2228                    .chain(in_memory_blocks.iter())
2229                    .take_while(|b| b.number < block.number)
2230                    .map(|b| b.transaction_count())
2231                    .sum::<usize>() as u64
2232            };
2233
2234            // Invalid/Non-existent argument should return `None`
2235            {
2236                call_method!($arg_count, provider, $method, |_,_,_,_|  ($invalid_args, None), tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2237            }
2238
2239            // Check that the item is only in memory and not in database
2240            {
2241                let last_mem_block = &in_memory_blocks[in_memory_blocks.len() - 1];
2242
2243                let (args, expected_item) = $item_extractor(last_mem_block, tx_num(last_mem_block), tx_hash(last_mem_block), &receipts);
2244                call_method!($arg_count, provider, $method, |_,_,_,_| (args.clone(), expected_item), tx_num, tx_hash, last_mem_block, &receipts);
2245
2246                // Ensure the item is not in storage
2247                call_method!($arg_count, provider.database, $method, |_,_,_,_|  (args, None), tx_num, tx_hash, last_mem_block, &receipts);
2248            }
2249        )*
2250    }};
2251}
2252
2253    #[test]
2254    fn test_non_range_methods() -> eyre::Result<()> {
2255        let test_tx_index = 0;
2256
2257        test_non_range!([
2258            (
2259                ONE,
2260                header,
2261                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2262                    block.hash(),
2263                    Some(block.header().clone())
2264                ),
2265                B256::random()
2266            ),
2267            (
2268                ONE,
2269                header_by_number,
2270                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2271                    block.number,
2272                    Some(block.header().clone())
2273                ),
2274                u64::MAX
2275            ),
2276            (
2277                ONE,
2278                sealed_header,
2279                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2280                    block.number,
2281                    Some(block.clone_sealed_header())
2282                ),
2283                u64::MAX
2284            ),
2285            (
2286                ONE,
2287                block_hash,
2288                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2289                    block.number,
2290                    Some(block.hash())
2291                ),
2292                u64::MAX
2293            ),
2294            (
2295                ONE,
2296                block_number,
2297                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2298                    block.hash(),
2299                    Some(block.number)
2300                ),
2301                B256::random()
2302            ),
2303            (
2304                ONE,
2305                block,
2306                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2307                    BlockHashOrNumber::Hash(block.hash()),
2308                    Some(block.clone().into_block())
2309                ),
2310                BlockHashOrNumber::Hash(B256::random())
2311            ),
2312            (
2313                ONE,
2314                block,
2315                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2316                    BlockHashOrNumber::Number(block.number),
2317                    Some(block.clone().into_block())
2318                ),
2319                BlockHashOrNumber::Number(u64::MAX)
2320            ),
2321            (
2322                ONE,
2323                block_body_indices,
2324                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2325                    block.number,
2326                    Some(StoredBlockBodyIndices {
2327                        first_tx_num: tx_num,
2328                        tx_count: block.transaction_count() as u64
2329                    })
2330                ),
2331                u64::MAX
2332            ),
2333            (
2334                TWO,
2335                recovered_block,
2336                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2337                    (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2338                    block.clone().try_recover().ok()
2339                ),
2340                (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2341            ),
2342            (
2343                TWO,
2344                recovered_block,
2345                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2346                    (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2347                    block.clone().try_recover().ok()
2348                ),
2349                (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2350            ),
2351            (
2352                TWO,
2353                sealed_block_with_senders,
2354                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2355                    (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2356                    block.clone().try_recover().ok()
2357                ),
2358                (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2359            ),
2360            (
2361                TWO,
2362                sealed_block_with_senders,
2363                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2364                    (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2365                    block.clone().try_recover().ok()
2366                ),
2367                (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2368            ),
2369            (
2370                ONE,
2371                transaction_id,
2372                |_: &SealedBlock<Block>, tx_num: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2373                    tx_hash,
2374                    Some(tx_num)
2375                ),
2376                B256::random()
2377            ),
2378            (
2379                ONE,
2380                transaction_by_id,
2381                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2382                    tx_num,
2383                    Some(block.body().transactions[test_tx_index].clone())
2384                ),
2385                u64::MAX
2386            ),
2387            (
2388                ONE,
2389                transaction_by_id_unhashed,
2390                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2391                    tx_num,
2392                    Some(block.body().transactions[test_tx_index].clone())
2393                ),
2394                u64::MAX
2395            ),
2396            (
2397                ONE,
2398                transaction_by_hash,
2399                |block: &SealedBlock<Block>, _: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2400                    tx_hash,
2401                    Some(block.body().transactions[test_tx_index].clone())
2402                ),
2403                B256::random()
2404            ),
2405            (
2406                ONE,
2407                block_by_transaction_id,
2408                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2409                    tx_num,
2410                    Some(block.number)
2411                ),
2412                u64::MAX
2413            ),
2414            (
2415                ONE,
2416                transactions_by_block,
2417                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2418                    BlockHashOrNumber::Number(block.number),
2419                    Some(block.body().transactions.clone())
2420                ),
2421                BlockHashOrNumber::Number(u64::MAX)
2422            ),
2423            (
2424                ONE,
2425                transactions_by_block,
2426                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2427                    BlockHashOrNumber::Hash(block.hash()),
2428                    Some(block.body().transactions.clone())
2429                ),
2430                BlockHashOrNumber::Number(u64::MAX)
2431            ),
2432            (
2433                ONE,
2434                transaction_sender,
2435                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2436                    tx_num,
2437                    block.body().transactions[test_tx_index].recover_signer().ok()
2438                ),
2439                u64::MAX
2440            ),
2441            (
2442                ONE,
2443                receipt,
2444                |block: &SealedBlock<Block>,
2445                 tx_num: TxNumber,
2446                 _: B256,
2447                 receipts: &Vec<Vec<Receipt>>| (
2448                    tx_num,
2449                    Some(receipts[block.number as usize][test_tx_index].clone())
2450                ),
2451                u64::MAX
2452            ),
2453            (
2454                ONE,
2455                receipt_by_hash,
2456                |block: &SealedBlock<Block>,
2457                 _: TxNumber,
2458                 tx_hash: B256,
2459                 receipts: &Vec<Vec<Receipt>>| (
2460                    tx_hash,
2461                    Some(receipts[block.number as usize][test_tx_index].clone())
2462                ),
2463                B256::random()
2464            ),
2465            (
2466                ONE,
2467                receipts_by_block,
2468                |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2469                    BlockHashOrNumber::Number(block.number),
2470                    Some(receipts[block.number as usize].clone())
2471                ),
2472                BlockHashOrNumber::Number(u64::MAX)
2473            ),
2474            (
2475                ONE,
2476                receipts_by_block,
2477                |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2478                    BlockHashOrNumber::Hash(block.hash()),
2479                    Some(receipts[block.number as usize].clone())
2480                ),
2481                BlockHashOrNumber::Hash(B256::random())
2482            ),
2483            // TODO: withdrawals, requests, ommers
2484        ]);
2485
2486        Ok(())
2487    }
2488
2489    #[test]
2490    fn test_race() -> eyre::Result<()> {
2491        let mut rng = generators::rng();
2492        let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2493            &mut rng,
2494            TEST_BLOCKS_COUNT - 1,
2495            TEST_BLOCKS_COUNT + 1,
2496            BlockRangeParams {
2497                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2498                ..Default::default()
2499            },
2500        )?;
2501
2502        // Old implementation was querying the database first. This is problematic, if there are
2503        // changes AFTER the database transaction is created.
2504        let old_transaction_hash_fn =
2505            |hash: B256,
2506             canonical_in_memory_state: CanonicalInMemoryState,
2507             factory: ProviderFactory<MockNodeTypesWithDB>| {
2508                assert!(factory.transaction_by_hash(hash)?.is_none(), "should not be in database");
2509                Ok::<_, ProviderError>(canonical_in_memory_state.transaction_by_hash(hash))
2510            };
2511
2512        // Correct implementation queries in-memory first
2513        let correct_transaction_hash_fn =
2514            |hash: B256,
2515             canonical_in_memory_state: CanonicalInMemoryState,
2516             _factory: ProviderFactory<MockNodeTypesWithDB>| {
2517                if let Some(tx) = canonical_in_memory_state.transaction_by_hash(hash) {
2518                    return Ok::<_, ProviderError>(Some(tx));
2519                }
2520                panic!("should not be in database");
2521                // _factory.transaction_by_hash(hash)
2522            };
2523
2524        // OLD BEHAVIOUR
2525        {
2526            // This will persist block 1 AFTER a database is created. Moving it from memory to
2527            // storage.
2528            persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2529            let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone();
2530
2531            // Even though the block exists, given the order of provider queries done in the method
2532            // above, we do not see it.
2533            assert!(matches!(
2534                old_transaction_hash_fn(
2535                    *to_be_persisted_tx.tx_hash(),
2536                    provider.canonical_in_memory_state(),
2537                    provider.database.clone()
2538                ),
2539                Ok(None)
2540            ));
2541        }
2542
2543        // CORRECT BEHAVIOUR
2544        {
2545            // This will persist block 1 AFTER a database is created. Moving it from memory to
2546            // storage.
2547            persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number);
2548            let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone();
2549
2550            assert_eq!(
2551                correct_transaction_hash_fn(
2552                    *to_be_persisted_tx.tx_hash(),
2553                    provider.canonical_in_memory_state(),
2554                    provider.database
2555                )
2556                .unwrap(),
2557                Some(to_be_persisted_tx)
2558            );
2559        }
2560
2561        Ok(())
2562    }
2563}