Skip to main content

reth_provider/providers/
blockchain_provider.rs

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