reth_provider/providers/
blockchain_provider.rs

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