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