Skip to main content

reth_provider/providers/
blockchain_provider.rs

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