Skip to main content

reth_provider/providers/
blockchain_provider.rs

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