Skip to main content

reth_provider/providers/
blockchain_provider.rs

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