Skip to main content

reth_provider/providers/
blockchain_provider.rs

1use crate::{
2    providers::{
3        ConsistentProvider, ProviderNodeTypes, RocksDBProvider, StaticFileProvider,
4        StaticFileProviderRWRefMut,
5    },
6    AccountReader, BalProvider, BalStoreHandle, BlockHashReader, BlockIdReader, BlockNumReader,
7    BlockReader, BlockReaderIdExt, BlockSource, CanonChainTracker, CanonStateNotifications,
8    CanonStateSubscriptions, ChainSpecProvider, ChainStateBlockReader, ChangeSetReader,
9    DatabaseProviderFactory, HeaderProvider, ProviderError, ProviderFactory, PruneCheckpointReader,
10    ReceiptProvider, ReceiptProviderIdExt, RocksDBProviderFactory, StageCheckpointReader,
11    StateProvider, StateProviderBox, StateProviderFactory, StateReader, StaticFileProviderFactory,
12    TransactionVariant, TransactionsProvider,
13};
14use alloy_consensus::{transaction::TransactionMeta, BlockHeader};
15use alloy_eips::{BlockHashOrNumber, BlockId, BlockNumHash, BlockNumberOrTag};
16use alloy_primitives::{Address, BlockHash, BlockNumber, Bytes, TxHash, TxNumber, B256};
17use alloy_rpc_types_engine::ForkchoiceState;
18use reth_chain_state::{
19    BlockState, CanonicalInMemoryState, ExecutedBlock, ForkChoiceNotifications,
20    ForkChoiceSubscriptions, PersistedBlockNotifications, PersistedBlockSubscriptions,
21};
22use reth_chainspec::ChainInfo;
23use reth_db_api::models::{AccountBeforeTx, BlockNumberAddress, StoredBlockBodyIndices};
24use reth_execution_types::{ExecutionOutcome, RecoveredBlockAndExecutionOutput};
25use reth_node_types::{BlockTy, HeaderTy, NodeTypes, NodeTypesWithDB, ReceiptTy, TxTy};
26use reth_primitives_traits::{
27    Account, RecoveredBlock, SealedHeader, SealedOrRecoveredBlock, StorageEntry,
28};
29use reth_prune_types::{PruneCheckpoint, PruneSegment};
30use reth_stages_types::{StageCheckpoint, StageId};
31use reth_static_file_types::StaticFileSegment;
32use reth_storage_api::{
33    BlockBodyIndicesProvider, DatabaseProviderROFactory, NodePrimitivesProvider, RangeEnd,
34    RangeResponse, RangeResult, StateRangeProvider, StateRangeProviderFactory, StateRangeView,
35    StorageChangeSetReader, StorageRangeResult,
36};
37use reth_storage_errors::provider::ProviderResult;
38use reth_storage_overlay::{OverlayStateProvider, OverlayStateProviderFactory, OwnedProvider};
39use reth_trie::{
40    hashed_cursor::{HashedCursor, HashedCursorFactory},
41    metrics::TrieRootMetrics,
42    proof::{Proof, StorageProof},
43    MultiProofTargets, StorageRoot, TrieType,
44};
45use std::{
46    ops::{RangeBounds, RangeInclusive},
47    sync::Arc,
48    time::Instant,
49};
50use tracing::trace;
51
52/// Number of most-recent blocks whose state roots remain resolvable via
53/// [`StateRangeProviderFactory::state_range_provider`].
54pub const SNAPSHOT_STATE_RETENTION: u64 = 128;
55
56type StateRangeDbProvider<N> = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
57type HistoricalStateRangeProvider<N> =
58    OverlayStateProvider<OwnedProvider<StateRangeDbProvider<N>>, <N as NodeTypes>::Primitives>;
59
60/// The main type for interacting with the blockchain.
61///
62/// This type serves as the main entry point for interacting with the blockchain and provides data
63/// from database storage and from the blockchain tree (pending state etc.) It is a simple wrapper
64/// type that holds an instance of the database and the blockchain tree.
65#[derive(Debug)]
66pub struct BlockchainProvider<N: NodeTypesWithDB> {
67    /// Provider factory used to access the database.
68    pub(crate) database: ProviderFactory<N>,
69    /// Tracks the chain info wrt forkchoice updates and in memory canonical
70    /// state.
71    pub(crate) canonical_in_memory_state: CanonicalInMemoryState<N::Primitives>,
72    /// Store for BALs associated with this provider view.
73    pub(crate) bal_store: BalStoreHandle,
74}
75
76impl<N: NodeTypesWithDB> Clone for BlockchainProvider<N> {
77    fn clone(&self) -> Self {
78        Self {
79            database: self.database.clone(),
80            canonical_in_memory_state: self.canonical_in_memory_state.clone(),
81            bal_store: self.bal_store.clone(),
82        }
83    }
84}
85
86impl<N: ProviderNodeTypes> BlockchainProvider<N> {
87    /// Create a new [`BlockchainProvider`] using only the storage, fetching the latest
88    /// header from the database to initialize the provider.
89    pub fn new(storage: ProviderFactory<N>) -> ProviderResult<Self> {
90        let provider = storage.provider()?;
91        let best = provider.chain_info()?;
92        match provider.header_by_number(best.best_number)? {
93            Some(header) => {
94                drop(provider);
95                Ok(Self::with_latest(storage, SealedHeader::new(header, best.best_hash))?)
96            }
97            None => Err(ProviderError::HeaderNotFound(best.best_number.into())),
98        }
99    }
100
101    /// Create new provider instance that wraps the database and the blockchain tree, using the
102    /// provided latest header to initialize the chain info tracker.
103    ///
104    /// This returns a `ProviderResult` since it tries the retrieve the last finalized header from
105    /// `database`.
106    pub fn with_latest(
107        storage: ProviderFactory<N>,
108        latest: SealedHeader<HeaderTy<N>>,
109    ) -> ProviderResult<Self> {
110        let provider = storage.provider()?;
111        let finalized_header = provider
112            .last_finalized_block_number()?
113            .map(|num| provider.sealed_header(num))
114            .transpose()?
115            .flatten();
116        let safe_header = provider
117            .last_safe_block_number()?
118            .or_else(|| {
119                // for the purpose of this we can also use the finalized block if we don't have the
120                // safe block
121                provider.last_finalized_block_number().ok().flatten()
122            })
123            .map(|num| provider.sealed_header(num))
124            .transpose()?
125            .flatten();
126        let bal_store = storage.bal_store().clone();
127
128        Ok(Self {
129            database: storage,
130            canonical_in_memory_state: CanonicalInMemoryState::with_head(
131                latest,
132                finalized_header,
133                safe_header,
134            ),
135            bal_store,
136        })
137    }
138
139    /// Gets a clone of `canonical_in_memory_state`.
140    pub fn canonical_in_memory_state(&self) -> CanonicalInMemoryState<N::Primitives> {
141        self.canonical_in_memory_state.clone()
142    }
143
144    /// Returns a provider with a created `DbTx` inside, which allows fetching data from the
145    /// database using different types of providers. Example: [`HeaderProvider`]
146    /// [`BlockHashReader`]. This may fail if the inner read database transaction fails to open.
147    #[track_caller]
148    pub fn consistent_provider(&self) -> ProviderResult<ConsistentProvider<N>> {
149        ConsistentProvider::new(self.database.clone(), self.canonical_in_memory_state())
150    }
151
152    /// Returns a state provider for the post-state of an already resolved in-memory chain.
153    ///
154    /// This is the post-state of `state.hash()`. Because the caller already holds the in-memory
155    /// chain, the overlay manager does not have to rebuild an identical one from its block graph.
156    fn state_provider_for_state(
157        &self,
158        state: Arc<BlockState<N::Primitives>>,
159    ) -> ProviderResult<StateProviderBox> {
160        let state_provider_factory = OverlayStateProviderFactory::new(
161            self.database.clone(),
162            self.database.overlay_manager().overlay_builder_for_state(state),
163        );
164        Ok(Box::new(state_provider_factory.database_provider_ro()?))
165    }
166
167    /// Returns a historical state provider using an existing database snapshot.
168    pub fn state_provider_from_database(
169        &self,
170        provider: StateRangeDbProvider<N>,
171        block_hash: B256,
172    ) -> StateProviderBox {
173        Box::new(OverlayStateProvider::new(
174            provider,
175            self.database.overlay_manager().overlay_builder(block_hash),
176        ))
177    }
178
179    /// Returns a cursor-backed state view for a state root still in canonical in-memory blocks.
180    fn block_state_range_provider(
181        &self,
182        state_root: B256,
183    ) -> ProviderResult<Option<HistoricalStateRangeProvider<N>>> {
184        let Some(matched) = self
185            .canonical_in_memory_state
186            .canonical_chain()
187            .find(|state| state.state_root() == state_root)
188        else {
189            return Ok(None)
190        };
191
192        let state_provider_factory = OverlayStateProviderFactory::new(
193            self.database.clone(),
194            self.database.overlay_manager().overlay_builder_for_state(matched),
195        );
196        state_provider_factory.database_provider_ro().map(Some)
197    }
198
199    /// Returns a cursor-backed state view for a retained canonical state root.
200    fn historical_state_range_provider(
201        &self,
202        state_root: B256,
203    ) -> ProviderResult<Option<HistoricalStateRangeProvider<N>>> {
204        let provider = self.database.provider()?;
205        let Some(finish) = provider.get_stage_checkpoint(StageId::Finish)? else { return Ok(None) };
206        let oldest = finish.block_number.saturating_sub(SNAPSHOT_STATE_RETENTION - 1);
207        let mut block_hash = None;
208
209        for number in (oldest..=finish.block_number).rev() {
210            let Some(header) = provider.sealed_header(number)? else { continue };
211            if header.state_root() == state_root {
212                block_hash = Some(header.hash());
213                break
214            }
215        }
216        drop(provider);
217
218        let Some(block_hash) = block_hash else { return Ok(None) };
219        let state_provider_factory = OverlayStateProviderFactory::new(
220            self.database.clone(),
221            self.database.overlay_manager().overlay_builder(block_hash),
222        );
223        state_provider_factory.database_provider_ro().map(Some)
224    }
225}
226
227impl<N: NodeTypesWithDB> NodePrimitivesProvider for BlockchainProvider<N> {
228    type Primitives = N::Primitives;
229}
230
231impl<N: ProviderNodeTypes> BalProvider for BlockchainProvider<N> {
232    fn bal_store(&self) -> &BalStoreHandle {
233        &self.bal_store
234    }
235}
236
237/// State range view backed by one resolved historical overlay.
238struct HistoricalStateRangeView<N: ProviderNodeTypes> {
239    provider: HistoricalStateRangeProvider<N>,
240}
241
242impl<N: ProviderNodeTypes> StateRangeProviderFactory for BlockchainProvider<N> {
243    /// Resolves a retained canonical state root into a pinned range view, preferring a still
244    /// in-memory block over the persisted-history fallback.
245    fn state_range_provider(&self, state_root: B256) -> ProviderResult<Option<StateRangeView>> {
246        let provider = match self.block_state_range_provider(state_root)? {
247            Some(provider) => Some(provider),
248            None => self.historical_state_range_provider(state_root)?,
249        };
250        Ok(provider
251            .map(|provider| Box::new(HistoricalStateRangeView { provider }) as StateRangeView))
252    }
253}
254
255impl<N: ProviderNodeTypes> StateRangeProvider for HistoricalStateRangeView<N> {
256    fn account_range(
257        &self,
258        start: B256,
259        limit: B256,
260        response_bytes: usize,
261    ) -> RangeResult<(B256, Account)> {
262        let mut cursor = self.provider.hashed_account_cursor().map_err(ProviderError::Database)?;
263
264        let mut accounts = Vec::new();
265        let mut total_bytes = 0usize;
266        let mut end = RangeEnd::Exhausted;
267
268        // Append before checking `limit`, so an empty `[start, limit]` still returns the account
269        // right past `limit`, provable as an empty range rather than a skipped one.
270        let mut entry = cursor.seek(start).map_err(ProviderError::Database)?;
271        while let Some((hash, account)) = entry {
272            total_bytes += 32 + 4 * 32; // hash + rough upper bound of the RLP account body
273            accounts.push((hash, account));
274            if hash >= limit {
275                end = RangeEnd::HashLimit;
276                break
277            }
278            if total_bytes > response_bytes {
279                end = RangeEnd::ByteLimit;
280                break
281            }
282            entry = cursor.next().map_err(ProviderError::Database)?;
283        }
284
285        Ok(RangeResponse { items: accounts, end })
286    }
287
288    fn storage_root_by_hash(&self, hashed_address: B256) -> ProviderResult<B256> {
289        let root = StorageRoot::new_hashed(
290            &self.provider,
291            &self.provider,
292            hashed_address,
293            Default::default(),
294            TrieRootMetrics::new(TrieType::Storage),
295        )
296        .root()
297        .map_err(|err| ProviderError::Database(err.into()))?;
298        Ok(root)
299    }
300
301    fn storage_range(
302        &self,
303        hashed_address: B256,
304        start: B256,
305        limit: B256,
306        response_bytes: usize,
307    ) -> StorageRangeResult {
308        // Distinguish an absent account from one with no storage, so callers don't silently
309        // omit it and shift later accounts' positions.
310        let mut account_cursor =
311            self.provider.hashed_account_cursor().map_err(ProviderError::Database)?;
312        let found = account_cursor.seek(hashed_address).map_err(ProviderError::Database)?;
313        if found.map(|(hash, _)| hash) != Some(hashed_address) {
314            return Ok(None)
315        }
316
317        let mut cursor =
318            self.provider.hashed_storage_cursor(hashed_address).map_err(ProviderError::Database)?;
319
320        let mut slots = Vec::new();
321        let mut total_bytes = 0usize;
322        let mut end = RangeEnd::Exhausted;
323
324        // Append before checking `limit`, so an empty `[start, limit]` still returns the slot
325        // right past `limit`, provable as an empty range rather than a skipped one.
326        let mut entry = cursor.seek(start).map_err(ProviderError::Database)?;
327        while let Some((hash, value)) = entry {
328            total_bytes += 64;
329            slots.push((hash, value));
330            if hash >= limit {
331                end = RangeEnd::HashLimit;
332                break
333            }
334            if total_bytes > response_bytes {
335                end = RangeEnd::ByteLimit;
336                break
337            }
338            entry = cursor.next().map_err(ProviderError::Database)?;
339        }
340
341        Ok(Some(RangeResponse { items: slots, end }))
342    }
343
344    fn account_range_proof(&self, keys: &[B256]) -> ProviderResult<Vec<Bytes>> {
345        let multiproof = Proof::new(&self.provider, &self.provider)
346            .multiproof(MultiProofTargets::accounts(keys.iter().copied()))
347            .map_err(ProviderError::from)?;
348        Ok(multiproof
349            .account_subtree
350            .into_nodes_sorted()
351            .into_iter()
352            .map(|(_, bytes)| bytes)
353            .collect())
354    }
355
356    fn storage_range_proof(
357        &self,
358        hashed_address: B256,
359        keys: &[B256],
360    ) -> ProviderResult<Vec<Bytes>> {
361        let multiproof = StorageProof::new_hashed(&self.provider, &self.provider, hashed_address)
362            .storage_multiproof(keys.iter().copied().collect())
363            .map_err(ProviderError::from)?;
364        Ok(multiproof.subtree.into_nodes_sorted().into_iter().map(|(_, bytes)| bytes).collect())
365    }
366}
367
368impl<N: ProviderNodeTypes> DatabaseProviderFactory for BlockchainProvider<N> {
369    type DB = N::DB;
370    type Provider = <ProviderFactory<N> as DatabaseProviderFactory>::Provider;
371    type ProviderRW = <ProviderFactory<N> as DatabaseProviderFactory>::ProviderRW;
372
373    fn database_provider_ro(&self) -> ProviderResult<Self::Provider> {
374        DatabaseProviderFactory::database_provider_ro(&self.database)
375    }
376
377    fn database_provider_rw(&self) -> ProviderResult<Self::ProviderRW> {
378        DatabaseProviderFactory::database_provider_rw(&self.database)
379    }
380}
381
382impl<N: ProviderNodeTypes> AsRef<N::DB> for BlockchainProvider<N> {
383    fn as_ref(&self) -> &N::DB {
384        self.database.db_ref()
385    }
386}
387
388impl<N: ProviderNodeTypes> StaticFileProviderFactory for BlockchainProvider<N> {
389    fn static_file_provider(&self) -> StaticFileProvider<Self::Primitives> {
390        self.database.static_file_provider()
391    }
392
393    fn get_static_file_writer(
394        &self,
395        block: BlockNumber,
396        segment: StaticFileSegment,
397    ) -> ProviderResult<StaticFileProviderRWRefMut<'_, Self::Primitives>> {
398        self.database.get_static_file_writer(block, segment)
399    }
400}
401
402impl<N: ProviderNodeTypes> RocksDBProviderFactory for BlockchainProvider<N> {
403    fn rocksdb_provider(&self) -> RocksDBProvider {
404        self.database.rocksdb_provider()
405    }
406
407    fn set_pending_rocksdb_batch(&self, _batch: rocksdb::WriteBatchWithTransaction<true>) {
408        unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::set_pending_rocksdb_batch instead")
409    }
410
411    fn commit_pending_rocksdb_batches(&self) -> ProviderResult<()> {
412        unimplemented!("BlockchainProvider wraps ProviderFactory - use DatabaseProvider::commit_pending_rocksdb_batches instead")
413    }
414}
415
416impl<N: ProviderNodeTypes> HeaderProvider for BlockchainProvider<N> {
417    type Header = HeaderTy<N>;
418
419    fn header(&self, block_hash: BlockHash) -> ProviderResult<Option<Self::Header>> {
420        self.consistent_provider()?.header(block_hash)
421    }
422
423    fn header_by_number(&self, num: BlockNumber) -> ProviderResult<Option<Self::Header>> {
424        self.consistent_provider()?.header_by_number(num)
425    }
426
427    fn headers_range(
428        &self,
429        range: impl RangeBounds<BlockNumber>,
430    ) -> ProviderResult<Vec<Self::Header>> {
431        self.consistent_provider()?.headers_range(range)
432    }
433
434    fn sealed_header(
435        &self,
436        number: BlockNumber,
437    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
438        self.consistent_provider()?.sealed_header(number)
439    }
440
441    fn sealed_headers_range(
442        &self,
443        range: impl RangeBounds<BlockNumber>,
444    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
445        self.consistent_provider()?.sealed_headers_range(range)
446    }
447
448    fn sealed_headers_while(
449        &self,
450        range: impl RangeBounds<BlockNumber>,
451        predicate: impl FnMut(&SealedHeader<Self::Header>) -> bool,
452    ) -> ProviderResult<Vec<SealedHeader<Self::Header>>> {
453        self.consistent_provider()?.sealed_headers_while(range, predicate)
454    }
455}
456
457impl<N: ProviderNodeTypes> BlockHashReader for BlockchainProvider<N> {
458    fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
459        self.consistent_provider()?.block_hash(number)
460    }
461
462    fn canonical_hashes_range(
463        &self,
464        start: BlockNumber,
465        end: BlockNumber,
466    ) -> ProviderResult<Vec<B256>> {
467        self.consistent_provider()?.canonical_hashes_range(start, end)
468    }
469}
470
471impl<N: ProviderNodeTypes> BlockNumReader for BlockchainProvider<N> {
472    fn chain_info(&self) -> ProviderResult<ChainInfo> {
473        Ok(self.canonical_in_memory_state.chain_info())
474    }
475
476    fn best_block_number(&self) -> ProviderResult<BlockNumber> {
477        Ok(self.canonical_in_memory_state.get_canonical_block_number())
478    }
479
480    fn last_block_number(&self) -> ProviderResult<BlockNumber> {
481        self.database.last_block_number()
482    }
483
484    fn earliest_block_number(&self) -> ProviderResult<BlockNumber> {
485        self.database.earliest_block_number()
486    }
487
488    fn block_number(&self, hash: B256) -> ProviderResult<Option<BlockNumber>> {
489        self.consistent_provider()?.block_number(hash)
490    }
491}
492
493impl<N: ProviderNodeTypes> BlockIdReader for BlockchainProvider<N> {
494    fn pending_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
495        Ok(self.canonical_in_memory_state.pending_block_num_hash())
496    }
497
498    fn safe_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
499        Ok(self.canonical_in_memory_state.get_safe_num_hash())
500    }
501
502    fn finalized_block_num_hash(&self) -> ProviderResult<Option<BlockNumHash>> {
503        Ok(self.canonical_in_memory_state.get_finalized_num_hash())
504    }
505}
506
507impl<N: ProviderNodeTypes> BlockReader for BlockchainProvider<N> {
508    type Block = BlockTy<N>;
509
510    fn find_block_by_hash(
511        &self,
512        hash: B256,
513        source: BlockSource,
514    ) -> ProviderResult<Option<Self::Block>> {
515        self.consistent_provider()?.find_block_by_hash(hash, source)
516    }
517
518    fn find_sealed_or_recovered_block(
519        &self,
520        hash: B256,
521        source: BlockSource,
522    ) -> ProviderResult<Option<SealedOrRecoveredBlock<Self::Block>>> {
523        self.consistent_provider()?.find_sealed_or_recovered_block(hash, source)
524    }
525
526    fn block(&self, id: BlockHashOrNumber) -> ProviderResult<Option<Self::Block>> {
527        self.consistent_provider()?.block(id)
528    }
529
530    fn pending_block(&self) -> ProviderResult<Option<Arc<RecoveredBlock<Self::Block>>>> {
531        Ok(self.canonical_in_memory_state.pending_recovered_block())
532    }
533
534    fn pending_block_and_receipts(
535        &self,
536    ) -> ProviderResult<Option<RecoveredBlockAndExecutionOutput<Self::Block, Self::Receipt>>> {
537        Ok(self.canonical_in_memory_state.pending_block_and_receipts())
538    }
539
540    /// Returns the block with senders with matching number or hash from database.
541    ///
542    /// **NOTE: If [`TransactionVariant::NoHash`] is provided then the transactions have invalid
543    /// hashes, since they would need to be calculated on the spot, and we want fast querying.**
544    ///
545    /// Returns `None` if block is not found.
546    fn recovered_block(
547        &self,
548        id: BlockHashOrNumber,
549        transaction_kind: TransactionVariant,
550    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
551        self.consistent_provider()?.recovered_block(id, transaction_kind)
552    }
553
554    fn sealed_block_with_senders(
555        &self,
556        id: BlockHashOrNumber,
557        transaction_kind: TransactionVariant,
558    ) -> ProviderResult<Option<RecoveredBlock<Self::Block>>> {
559        self.consistent_provider()?.sealed_block_with_senders(id, transaction_kind)
560    }
561
562    fn block_range(&self, range: RangeInclusive<BlockNumber>) -> ProviderResult<Vec<Self::Block>> {
563        self.consistent_provider()?.block_range(range)
564    }
565
566    fn block_with_senders_range(
567        &self,
568        range: RangeInclusive<BlockNumber>,
569    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
570        self.consistent_provider()?.block_with_senders_range(range)
571    }
572
573    fn recovered_block_range(
574        &self,
575        range: RangeInclusive<BlockNumber>,
576    ) -> ProviderResult<Vec<RecoveredBlock<Self::Block>>> {
577        self.consistent_provider()?.recovered_block_range(range)
578    }
579
580    fn block_by_transaction_id(&self, id: TxNumber) -> ProviderResult<Option<BlockNumber>> {
581        self.consistent_provider()?.block_by_transaction_id(id)
582    }
583}
584
585impl<N: ProviderNodeTypes> TransactionsProvider for BlockchainProvider<N> {
586    type Transaction = TxTy<N>;
587
588    fn transaction_id(&self, tx_hash: TxHash) -> ProviderResult<Option<TxNumber>> {
589        self.consistent_provider()?.transaction_id(tx_hash)
590    }
591
592    fn transaction_by_id(&self, id: TxNumber) -> ProviderResult<Option<Self::Transaction>> {
593        self.consistent_provider()?.transaction_by_id(id)
594    }
595
596    fn transaction_by_id_unhashed(
597        &self,
598        id: TxNumber,
599    ) -> ProviderResult<Option<Self::Transaction>> {
600        self.consistent_provider()?.transaction_by_id_unhashed(id)
601    }
602
603    fn transaction_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Transaction>> {
604        self.consistent_provider()?.transaction_by_hash(hash)
605    }
606
607    fn transaction_by_hash_with_meta(
608        &self,
609        tx_hash: TxHash,
610    ) -> ProviderResult<Option<(Self::Transaction, TransactionMeta)>> {
611        self.consistent_provider()?.transaction_by_hash_with_meta(tx_hash)
612    }
613
614    fn transactions_by_block(
615        &self,
616        id: BlockHashOrNumber,
617    ) -> ProviderResult<Option<Vec<Self::Transaction>>> {
618        self.consistent_provider()?.transactions_by_block(id)
619    }
620
621    fn transactions_by_block_range(
622        &self,
623        range: impl RangeBounds<BlockNumber>,
624    ) -> ProviderResult<Vec<Vec<Self::Transaction>>> {
625        self.consistent_provider()?.transactions_by_block_range(range)
626    }
627
628    fn transactions_by_tx_range(
629        &self,
630        range: impl RangeBounds<TxNumber>,
631    ) -> ProviderResult<Vec<Self::Transaction>> {
632        self.consistent_provider()?.transactions_by_tx_range(range)
633    }
634
635    fn senders_by_tx_range(
636        &self,
637        range: impl RangeBounds<TxNumber>,
638    ) -> ProviderResult<Vec<Address>> {
639        self.consistent_provider()?.senders_by_tx_range(range)
640    }
641
642    fn transaction_sender(&self, id: TxNumber) -> ProviderResult<Option<Address>> {
643        self.consistent_provider()?.transaction_sender(id)
644    }
645}
646
647impl<N: ProviderNodeTypes> ReceiptProvider for BlockchainProvider<N> {
648    type Receipt = ReceiptTy<N>;
649
650    fn receipt(&self, id: TxNumber) -> ProviderResult<Option<Self::Receipt>> {
651        self.consistent_provider()?.receipt(id)
652    }
653
654    fn receipt_by_hash(&self, hash: TxHash) -> ProviderResult<Option<Self::Receipt>> {
655        self.consistent_provider()?.receipt_by_hash(hash)
656    }
657
658    fn receipts_by_block(
659        &self,
660        block: BlockHashOrNumber,
661    ) -> ProviderResult<Option<Vec<Self::Receipt>>> {
662        self.consistent_provider()?.receipts_by_block(block)
663    }
664
665    fn receipts_by_tx_range(
666        &self,
667        range: impl RangeBounds<TxNumber>,
668    ) -> ProviderResult<Vec<Self::Receipt>> {
669        self.consistent_provider()?.receipts_by_tx_range(range)
670    }
671
672    fn receipts_by_block_range(
673        &self,
674        block_range: RangeInclusive<BlockNumber>,
675    ) -> ProviderResult<Vec<Vec<Self::Receipt>>> {
676        self.consistent_provider()?.receipts_by_block_range(block_range)
677    }
678}
679
680impl<N: ProviderNodeTypes> ReceiptProviderIdExt for BlockchainProvider<N> {
681    fn receipts_by_block_id(&self, block: BlockId) -> ProviderResult<Option<Vec<Self::Receipt>>> {
682        self.consistent_provider()?.receipts_by_block_id(block)
683    }
684}
685
686impl<N: ProviderNodeTypes> BlockBodyIndicesProvider for BlockchainProvider<N> {
687    fn block_body_indices(
688        &self,
689        number: BlockNumber,
690    ) -> ProviderResult<Option<StoredBlockBodyIndices>> {
691        self.consistent_provider()?.block_body_indices(number)
692    }
693
694    fn block_body_indices_range(
695        &self,
696        range: RangeInclusive<BlockNumber>,
697    ) -> ProviderResult<Vec<StoredBlockBodyIndices>> {
698        self.consistent_provider()?.block_body_indices_range(range)
699    }
700}
701
702impl<N: ProviderNodeTypes> StageCheckpointReader for BlockchainProvider<N> {
703    fn get_stage_checkpoint(&self, id: StageId) -> ProviderResult<Option<StageCheckpoint>> {
704        self.consistent_provider()?.get_stage_checkpoint(id)
705    }
706
707    fn get_stage_checkpoint_progress(&self, id: StageId) -> ProviderResult<Option<Vec<u8>>> {
708        self.consistent_provider()?.get_stage_checkpoint_progress(id)
709    }
710
711    fn get_all_checkpoints(&self) -> ProviderResult<Vec<(String, StageCheckpoint)>> {
712        self.consistent_provider()?.get_all_checkpoints()
713    }
714}
715
716impl<N: ProviderNodeTypes> PruneCheckpointReader for BlockchainProvider<N> {
717    fn get_prune_checkpoint(
718        &self,
719        segment: PruneSegment,
720    ) -> ProviderResult<Option<PruneCheckpoint>> {
721        self.consistent_provider()?.get_prune_checkpoint(segment)
722    }
723
724    fn get_prune_checkpoints(&self) -> ProviderResult<Vec<(PruneSegment, PruneCheckpoint)>> {
725        self.consistent_provider()?.get_prune_checkpoints()
726    }
727}
728
729impl<N: NodeTypesWithDB> ChainSpecProvider for BlockchainProvider<N> {
730    type ChainSpec = N::ChainSpec;
731
732    fn chain_spec(&self) -> Arc<N::ChainSpec> {
733        self.database.chain_spec()
734    }
735}
736
737impl<N: ProviderNodeTypes> StateProviderFactory for BlockchainProvider<N> {
738    type Primitives = N::Primitives;
739
740    /// Storage provider for latest block
741    fn latest(&self) -> ProviderResult<StateProviderBox> {
742        trace!(target: "providers::blockchain", "Getting latest block state provider");
743        // use latest state provider if the head state exists
744        if let Some(state) = self.canonical_in_memory_state.head_state() {
745            trace!(target: "providers::blockchain", "Using head state for latest state provider");
746            self.state_provider_for_state(state)
747        } else {
748            trace!(target: "providers::blockchain", "Using database state for latest state provider");
749            self.database.latest()
750        }
751    }
752
753    fn state_with_block_appended(
754        &self,
755        parent_hash: BlockHash,
756        block: ExecutedBlock<N::Primitives>,
757    ) -> ProviderResult<StateProviderBox> {
758        let state_provider_factory = OverlayStateProviderFactory::new(
759            self.database.clone(),
760            self.database.overlay_manager().overlay_builder(parent_hash).with_appended_block(block),
761        );
762        Ok(Box::new(state_provider_factory.database_provider_ro()?))
763    }
764
765    /// Returns a [`StateProviderBox`] indexed by the given block number or tag.
766    fn state_by_block_number_or_tag(
767        &self,
768        number_or_tag: BlockNumberOrTag,
769    ) -> ProviderResult<StateProviderBox> {
770        match number_or_tag {
771            BlockNumberOrTag::Latest => self.latest(),
772            BlockNumberOrTag::Finalized => {
773                // we can only get the finalized state by hash, not by num
774                let hash =
775                    self.finalized_block_hash()?.ok_or(ProviderError::FinalizedBlockNotFound)?;
776                self.state_by_block_hash(hash)
777            }
778            BlockNumberOrTag::Safe => {
779                // we can only get the safe state by hash, not by num
780                let hash = self.safe_block_hash()?.ok_or(ProviderError::SafeBlockNotFound)?;
781                self.state_by_block_hash(hash)
782            }
783            BlockNumberOrTag::Earliest => {
784                self.history_by_block_number(self.earliest_block_number()?)
785            }
786            BlockNumberOrTag::Pending => self.pending(),
787            BlockNumberOrTag::Number(num) => {
788                let hash = self
789                    .block_hash(num)?
790                    .ok_or_else(|| ProviderError::HeaderNotFound(num.into()))?;
791                self.state_by_block_hash(hash)
792            }
793        }
794    }
795
796    fn history_by_block_number(
797        &self,
798        block_number: BlockNumber,
799    ) -> ProviderResult<StateProviderBox> {
800        trace!(target: "providers::blockchain", ?block_number, "Getting history by block number");
801        let provider = self.consistent_provider()?;
802        let hash = provider
803            .block_hash(block_number)?
804            .ok_or_else(|| ProviderError::HeaderNotFound(block_number.into()))?;
805        Ok(self.state_provider_from_database(provider.into_database_provider(), hash))
806    }
807
808    fn history_by_block_hash(&self, block_hash: BlockHash) -> ProviderResult<StateProviderBox> {
809        trace!(target: "providers::blockchain", ?block_hash, "Getting history by block hash");
810        let provider = self.consistent_provider()?;
811        provider.block_number(block_hash)?.ok_or(ProviderError::BlockHashNotFound(block_hash))?;
812        Ok(self.state_provider_from_database(provider.into_database_provider(), block_hash))
813    }
814
815    fn state_by_block_hash(&self, hash: BlockHash) -> ProviderResult<StateProviderBox> {
816        trace!(target: "providers::blockchain", ?hash, "Getting state by block hash");
817        if let Some(state) = self.canonical_in_memory_state.state_by_hash(hash) {
818            self.state_provider_for_state(state)
819        } else if let Ok(state) = self.history_by_block_hash(hash) {
820            // This could be tracked by a historical block
821            Ok(state)
822        } else if let Ok(Some(pending)) = self.pending_state_by_hash(hash) {
823            // .. or this could be the pending state
824            Ok(pending)
825        } else {
826            // if we couldn't find it anywhere, then we should return an error
827            Err(ProviderError::StateForHashNotFound(hash))
828        }
829    }
830
831    /// Returns the state provider for pending state.
832    ///
833    /// If there's no pending block available then the latest state provider is returned:
834    /// [`Self::latest`]
835    fn pending(&self) -> ProviderResult<StateProviderBox> {
836        trace!(target: "providers::blockchain", "Getting provider for pending state");
837
838        if let Some(pending) = self.canonical_in_memory_state.pending_state() {
839            // we have a pending block
840            return self.state_provider_for_state(Arc::new(pending));
841        }
842
843        // fallback to latest state if the pending block is not available
844        self.latest()
845    }
846
847    fn pending_state_by_hash(&self, block_hash: B256) -> ProviderResult<Option<StateProviderBox>> {
848        if let Some(pending) = self.canonical_in_memory_state.pending_state() &&
849            pending.hash() == block_hash
850        {
851            return self.state_provider_for_state(Arc::new(pending)).map(Some);
852        }
853        Ok(None)
854    }
855
856    fn maybe_pending(&self) -> ProviderResult<Option<StateProviderBox>> {
857        if let Some(pending) = self.canonical_in_memory_state.pending_state() {
858            return self.state_provider_for_state(Arc::new(pending)).map(Some)
859        }
860
861        Ok(None)
862    }
863}
864
865impl<N: ProviderNodeTypes> CanonChainTracker for BlockchainProvider<N> {
866    type Header = HeaderTy<N>;
867
868    fn on_forkchoice_update_received(&self, _update: &ForkchoiceState) {
869        // update timestamp
870        self.canonical_in_memory_state.on_forkchoice_update_received();
871    }
872
873    fn last_received_update_timestamp(&self) -> Option<Instant> {
874        self.canonical_in_memory_state.last_received_update_timestamp()
875    }
876
877    fn set_canonical_head(&self, header: SealedHeader<Self::Header>) {
878        self.canonical_in_memory_state.set_canonical_head(header);
879    }
880
881    fn set_safe(&self, header: SealedHeader<Self::Header>) {
882        self.canonical_in_memory_state.set_safe(header);
883    }
884
885    fn set_finalized(&self, header: SealedHeader<Self::Header>) {
886        self.canonical_in_memory_state.set_finalized(header);
887    }
888}
889
890impl<N: ProviderNodeTypes> BlockReaderIdExt for BlockchainProvider<N>
891where
892    Self: ReceiptProviderIdExt,
893{
894    fn block_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Block>> {
895        self.consistent_provider()?.block_by_id(id)
896    }
897
898    fn header_by_number_or_tag(
899        &self,
900        id: BlockNumberOrTag,
901    ) -> ProviderResult<Option<Self::Header>> {
902        self.consistent_provider()?.header_by_number_or_tag(id)
903    }
904
905    fn sealed_header_by_number_or_tag(
906        &self,
907        id: BlockNumberOrTag,
908    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
909        self.consistent_provider()?.sealed_header_by_number_or_tag(id)
910    }
911
912    fn sealed_header_by_id(
913        &self,
914        id: BlockId,
915    ) -> ProviderResult<Option<SealedHeader<Self::Header>>> {
916        self.consistent_provider()?.sealed_header_by_id(id)
917    }
918
919    fn header_by_id(&self, id: BlockId) -> ProviderResult<Option<Self::Header>> {
920        self.consistent_provider()?.header_by_id(id)
921    }
922}
923
924impl<N: ProviderNodeTypes> CanonStateSubscriptions for BlockchainProvider<N> {
925    type Primitives = N::Primitives;
926
927    fn subscribe_to_canonical_state(&self) -> CanonStateNotifications<Self::Primitives> {
928        self.canonical_in_memory_state.subscribe_canon_state()
929    }
930}
931
932impl<N: ProviderNodeTypes> ForkChoiceSubscriptions for BlockchainProvider<N> {
933    type Header = HeaderTy<N>;
934
935    fn subscribe_safe_block(&self) -> ForkChoiceNotifications<Self::Header> {
936        let receiver = self.canonical_in_memory_state.subscribe_safe_block();
937        ForkChoiceNotifications(receiver)
938    }
939
940    fn subscribe_finalized_block(&self) -> ForkChoiceNotifications<Self::Header> {
941        let receiver = self.canonical_in_memory_state.subscribe_finalized_block();
942        ForkChoiceNotifications(receiver)
943    }
944}
945
946impl<N: ProviderNodeTypes> PersistedBlockSubscriptions for BlockchainProvider<N> {
947    fn subscribe_persisted_block(&self) -> PersistedBlockNotifications {
948        let receiver = self.canonical_in_memory_state.subscribe_persisted_block();
949        PersistedBlockNotifications(receiver)
950    }
951}
952
953impl<N: ProviderNodeTypes> StorageChangeSetReader for BlockchainProvider<N> {
954    fn storage_changeset(
955        &self,
956        block_number: BlockNumber,
957    ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
958        self.consistent_provider()?.storage_changeset(block_number)
959    }
960
961    fn get_storage_before_block(
962        &self,
963        block_number: BlockNumber,
964        address: Address,
965        storage_key: B256,
966    ) -> ProviderResult<Option<StorageEntry>> {
967        self.consistent_provider()?.get_storage_before_block(block_number, address, storage_key)
968    }
969
970    fn storage_changesets_range(
971        &self,
972        range: impl RangeBounds<BlockNumber>,
973    ) -> ProviderResult<Vec<(BlockNumberAddress, StorageEntry)>> {
974        self.consistent_provider()?.storage_changesets_range(range)
975    }
976}
977
978impl<N: ProviderNodeTypes> ChangeSetReader for BlockchainProvider<N> {
979    fn account_block_changeset(
980        &self,
981        block_number: BlockNumber,
982    ) -> ProviderResult<Vec<AccountBeforeTx>> {
983        self.consistent_provider()?.account_block_changeset(block_number)
984    }
985
986    fn get_account_before_block(
987        &self,
988        block_number: BlockNumber,
989        address: Address,
990    ) -> ProviderResult<Option<AccountBeforeTx>> {
991        self.consistent_provider()?.get_account_before_block(block_number, address)
992    }
993
994    fn account_changesets_range(
995        &self,
996        range: impl core::ops::RangeBounds<BlockNumber>,
997    ) -> ProviderResult<Vec<(BlockNumber, AccountBeforeTx)>> {
998        self.consistent_provider()?.account_changesets_range(range)
999    }
1000}
1001
1002impl<N: ProviderNodeTypes> StateReader for BlockchainProvider<N> {
1003    type Receipt = ReceiptTy<N>;
1004
1005    /// Re-constructs the [`ExecutionOutcome`] from in-memory and database state, if necessary.
1006    ///
1007    /// If data for the block does not exist, this will return [`None`].
1008    ///
1009    /// NOTE: This cannot be called safely in a loop outside of the blockchain tree thread. This is
1010    /// because the [`CanonicalInMemoryState`] could change during a reorg, causing results to be
1011    /// inconsistent. Currently this can safely be called within the blockchain tree thread,
1012    /// because the tree thread is responsible for modifying the [`CanonicalInMemoryState`] in the
1013    /// first place.
1014    fn get_state(
1015        &self,
1016        block: BlockNumber,
1017    ) -> ProviderResult<Option<ExecutionOutcome<Self::Receipt>>> {
1018        if let Some(head) = self.canonical_in_memory_state.head_state() &&
1019            let Some(state) = head.block_on_chain(block.into())
1020        {
1021            return Ok(Some(ExecutionOutcome::from((
1022                state.block_ref().execution_outcome().clone(),
1023                block,
1024            ))))
1025        }
1026
1027        let provider = self.database.provider()?;
1028        let Some(block_body) = provider.block_body_indices(block)? else { return Ok(None) };
1029
1030        let account_changeset = provider.account_changesets_range(block..=block)?;
1031        let storage_changeset = provider.storage_changeset(block)?;
1032
1033        let Some(block_hash) = provider.block_hash(block)? else { return Ok(None) };
1034        let state_provider = OverlayStateProvider::<&_, N::Primitives>::new_ref(
1035            &provider,
1036            self.database.overlay_manager().overlay_builder(block_hash),
1037        );
1038        let (state, reverts) = provider.populate_bundle_state(
1039            account_changeset,
1040            storage_changeset,
1041            |address| state_provider.basic_account(&address),
1042            |address, storage_key| state_provider.storage(address, storage_key),
1043        )?;
1044        let receipts = provider.receipts_by_tx_range(block_body.tx_num_range())?;
1045
1046        Ok(Some(ExecutionOutcome::new_init(
1047            state,
1048            reverts,
1049            // We skip new contracts since we never delete them from the database
1050            Vec::new(),
1051            vec![receipts],
1052            block,
1053            Vec::new(),
1054        )))
1055    }
1056}
1057
1058#[cfg(test)]
1059#[allow(clippy::clone_on_copy)]
1060mod tests {
1061    use super::*;
1062    use crate::{
1063        providers::BlockchainProvider,
1064        test_utils::{
1065            create_test_provider_factory, create_test_provider_factory_with_chain_spec,
1066            MockNodeTypesWithDB,
1067        },
1068        BlockWriter, CanonChainTracker, ProviderFactory, SaveBlocksInput,
1069    };
1070    use alloy_consensus::constants::EMPTY_ROOT_HASH;
1071    use alloy_eips::{BlockHashOrNumber, BlockNumHash, BlockNumberOrTag};
1072    use alloy_primitives::{keccak256, Address, BlockNumber, TxNumber, B256, U256};
1073    use evm2::evm::AccountInfo;
1074    use itertools::Itertools;
1075    use rand::Rng;
1076    use reth_chain_state::{
1077        test_utils::TestBlockBuilder, CanonStateNotification, CanonStateSubscriptions,
1078        CanonicalInMemoryState, ExecutedBlock, NewCanonicalChain,
1079    };
1080    use reth_chainspec::{ChainSpec, MAINNET};
1081    use reth_db_api::models::{AccountBeforeTx, StoredBlockBodyIndices};
1082    use reth_errors::ProviderError;
1083    use reth_ethereum_primitives::{Block, Receipt};
1084    use reth_execution_types::{
1085        BlockExecutionOutput, BlockExecutionResult, Chain, ExecutionOutcome,
1086    };
1087    use reth_primitives_traits::{
1088        Account, Block as _, RecoveredBlock, SealedBlock, SignerRecoverable, StorageEntry,
1089    };
1090    use reth_stages_types::{StageCheckpoint, StageId};
1091    use reth_storage_api::{
1092        BlockBodyIndicesProvider, BlockHashReader, BlockIdReader, BlockNumReader, BlockReader,
1093        BlockReaderIdExt, BlockSource, ChangeSetReader, DBProvider, DatabaseProviderFactory,
1094        HashingWriter, HeaderProvider, RangeEnd, ReceiptProvider, ReceiptProviderIdExt,
1095        StageCheckpointWriter, StateProviderFactory, StateRangeProvider, StateRangeProviderFactory,
1096        StateRootProvider, StateWriteConfig, StateWriter, StorageRootProvider, TransactionVariant,
1097        TransactionsProvider,
1098    };
1099    use reth_testing_utils::generators::{
1100        self, random_block, random_block_range, random_changeset_range, random_eoa_accounts,
1101        random_receipt, BlockParams, BlockRangeParams,
1102    };
1103    use reth_trie::{
1104        bundle_state::{BundleState, OriginalValuesKnown},
1105        updates::TrieUpdates,
1106        HashedPostState, HashedStorage, SortedTrieData,
1107    };
1108    use std::{
1109        collections::{BTreeMap, HashMap},
1110        ops::{Bound, Range, RangeBounds},
1111        sync::Arc,
1112    };
1113
1114    #[test]
1115    fn historical_proofs_complete_masked_trie_rows() -> eyre::Result<()> {
1116        use crate::{StaticFileProviderFactory, StaticFileSegment, StaticFileWriter};
1117        use reth_storage_api::{StorageSettings, StorageSettingsCache, TrieWriter};
1118        use reth_trie::{test_utils::TrieTestHarness, MultiProofTargetsV2};
1119
1120        let address = Address::with_last_byte(1);
1121        let other_address = Address::with_last_byte(2);
1122        let hashed_address = keccak256(address);
1123        let account = Account { balance: U256::ONE, ..Default::default() };
1124        // Branches 00, 01 and 02 share the cached row at 0. The first two change
1125        // in different blocks; the third keeps proof-v2's branch-collapse path inactive.
1126        let slots: Vec<B256> = (0..=2u8)
1127            .flat_map(|prefix| {
1128                (0..u64::MAX)
1129                    .map(|slot| B256::from(U256::from(slot)))
1130                    .filter(move |slot| keccak256(slot)[0] == prefix)
1131                    .take(2)
1132            })
1133            .collect();
1134        let mut storage: BTreeMap<_, _> = slots.iter().map(|&slot| (slot, U256::ONE)).collect();
1135        let mut trie = TrieTestHarness::new(
1136            storage.iter().map(|(slot, value)| (keccak256(slot), *value)).collect(),
1137        );
1138        let mut blocks = Vec::<ExecutedBlock>::new();
1139        let mut storage_roots = Vec::new();
1140        for number in 0..=2 {
1141            let mut output = (*ExecutedBlock::<reth_ethereum_primitives::EthPrimitives>::default()
1142                .execution_output)
1143                .clone();
1144            let (state, storage_updates) = if number == 0 {
1145                (
1146                    HashedPostState::default()
1147                        .with_accounts([
1148                            (hashed_address, Some(account.clone())),
1149                            (keccak256(other_address), Some(account.clone())),
1150                        ])
1151                        .with_storages([(
1152                            hashed_address,
1153                            HashedStorage::from_iter(trie.storage().iter().map(|(k, v)| (*k, *v))),
1154                        )]),
1155                    trie.storage_trie_updates().clone(),
1156                )
1157            } else {
1158                let slot = slots[(number as usize - 1) * 2];
1159                let value = U256::from(number + 1);
1160                let changes = BTreeMap::from([(keccak256(slot), value)]);
1161                let (_, updates) = trie.get_root_with_updates(&changes);
1162                trie.apply_changeset(changes);
1163                storage.insert(slot, value);
1164                let info = AccountInfo::default().with_balance(account.balance);
1165                output.state = BundleState::builder(number..=number)
1166                    .state_original_account_info(address, info.clone())
1167                    .state_present_account_info(address, info)
1168                    .state_storage(
1169                        address,
1170                        std::iter::once((U256::from_be_bytes(slot.0), (U256::ONE, value)))
1171                            .collect(),
1172                    )
1173                    .revert_storage(number, address, vec![(U256::from_be_bytes(slot.0), U256::ONE)])
1174                    .build();
1175                (
1176                    HashedPostState::from_hashed_storage(
1177                        hashed_address,
1178                        HashedStorage::from_iter([(keccak256(slot), value)]),
1179                    ),
1180                    updates,
1181                )
1182            };
1183            let mut updates = TrieUpdates::default();
1184            updates.storage_tries.insert(hashed_address, storage_updates);
1185            let state_root = reth_trie::test_utils::state_root([
1186                (address, (account.clone(), storage.clone())),
1187                (other_address, (account.clone(), BTreeMap::new())),
1188            ]);
1189            storage_roots.push(reth_trie::test_utils::storage_root(storage.clone()));
1190            let block = Block {
1191                header: alloy_consensus::Header {
1192                    number,
1193                    parent_hash: blocks
1194                        .last()
1195                        .map(|b| b.recovered_block().hash())
1196                        .unwrap_or_default(),
1197                    state_root,
1198                    ..Default::default()
1199                },
1200                ..Default::default()
1201            };
1202            blocks.push(ExecutedBlock::new(
1203                Arc::new(RecoveredBlock::new_unhashed(block, vec![])),
1204                Arc::new(output),
1205                SortedTrieData::new(Arc::new(state.into_sorted()), Arc::new(updates.into_sorted())),
1206            ));
1207        }
1208
1209        let factory = create_test_provider_factory();
1210        factory.set_storage_settings_cache(StorageSettings::v2());
1211        let writer = factory.provider_rw()?;
1212        writer.insert_block(blocks[0].recovered_block())?;
1213        writer.write_hashed_state(blocks[0].hashed_state_ref())?;
1214        writer.write_trie_updates_sorted(blocks[0].trie_updates_ref())?;
1215        writer.commit()?;
1216        let static_files = factory.static_file_provider();
1217        static_files.get_writer(0, StaticFileSegment::Receipts)?.increment_block(0)?;
1218        static_files
1219            .get_writer(0, StaticFileSegment::AccountChangeSets)?
1220            .append_account_changeset(vec![], 0)?;
1221        static_files
1222            .get_writer(0, StaticFileSegment::StorageChangeSets)?
1223            .append_storage_changeset(vec![], 0)?;
1224        static_files.commit()?;
1225        let writer = factory.provider_rw()?;
1226        writer.save_blocks(&SaveBlocksInput::new(blocks[1..].to_vec(), 0, 0, 2, 1))?;
1227        writer.commit()?;
1228        factory.overlay_manager().insert_block(blocks[2].clone());
1229        let provider = BlockchainProvider::new(factory)?;
1230
1231        for number in [1, 2] {
1232            let state = provider.history_by_block_hash(blocks[number].recovered_block().hash())?;
1233            let root = blocks[number].recovered_block().state_root;
1234            state
1235                .multiproof_v2(
1236                    MultiProofTargetsV2 {
1237                        account_targets: vec![keccak256(other_address).into()],
1238                        ..Default::default()
1239                    },
1240                    false,
1241                )?
1242                .account_proof(other_address, &[])?
1243                .verify(root)?;
1244            assert_eq!(state.state_root(HashedPostState::default())?, root);
1245            assert_eq!(
1246                state.storage_root(address, HashedStorage::default())?,
1247                storage_roots[number]
1248            );
1249            state
1250                .storage_proof(address, slots[2], HashedStorage::default())?
1251                .verify(storage_roots[number])?;
1252            let proof = state.storage_multiproof(address, &[slots[2]], HashedStorage::default())?;
1253            assert_eq!(proof.root, storage_roots[number]);
1254            proof.storage_proof(slots[2])?.verify(storage_roots[number])?;
1255        }
1256        Ok(())
1257    }
1258
1259    const TEST_BLOCKS_COUNT: usize = 5;
1260
1261    const TEST_TRANSACTIONS_COUNT: u8 = 4;
1262
1263    fn random_blocks(
1264        rng: &mut impl Rng,
1265        database_blocks: usize,
1266        in_memory_blocks: usize,
1267        requests_count: Option<Range<u8>>,
1268        withdrawals_count: Option<Range<u8>>,
1269        tx_count: impl RangeBounds<u8>,
1270    ) -> (Vec<SealedBlock<Block>>, Vec<SealedBlock<Block>>) {
1271        let block_range = (database_blocks + in_memory_blocks - 1) as u64;
1272
1273        let tx_start = match tx_count.start_bound() {
1274            Bound::Included(&n) | Bound::Excluded(&n) => n,
1275            Bound::Unbounded => u8::MIN,
1276        };
1277        let tx_end = match tx_count.end_bound() {
1278            Bound::Included(&n) | Bound::Excluded(&n) => n + 1,
1279            Bound::Unbounded => u8::MAX,
1280        };
1281
1282        let blocks = random_block_range(
1283            rng,
1284            0..=block_range,
1285            BlockRangeParams {
1286                parent: Some(B256::ZERO),
1287                tx_count: tx_start..tx_end,
1288                requests_count,
1289                withdrawals_count,
1290            },
1291        );
1292        let (database_blocks, in_memory_blocks) = blocks.split_at(database_blocks);
1293        (database_blocks.to_vec(), in_memory_blocks.to_vec())
1294    }
1295
1296    #[expect(clippy::type_complexity)]
1297    fn provider_with_chain_spec_and_random_blocks(
1298        rng: &mut impl Rng,
1299        chain_spec: Arc<ChainSpec>,
1300        database_blocks: usize,
1301        in_memory_blocks: usize,
1302        block_range_params: BlockRangeParams,
1303    ) -> eyre::Result<(
1304        BlockchainProvider<MockNodeTypesWithDB>,
1305        Vec<SealedBlock<Block>>,
1306        Vec<SealedBlock<Block>>,
1307        Vec<Vec<Receipt>>,
1308    )> {
1309        let (database_blocks, in_memory_blocks) = random_blocks(
1310            rng,
1311            database_blocks,
1312            in_memory_blocks,
1313            block_range_params.requests_count,
1314            block_range_params.withdrawals_count,
1315            block_range_params.tx_count,
1316        );
1317
1318        let receipts: Vec<Vec<_>> = database_blocks
1319            .iter()
1320            .chain(in_memory_blocks.iter())
1321            .map(|block| block.body().transactions.iter())
1322            .map(|tx| tx.map(|tx| random_receipt(rng, tx, Some(2), None)).collect())
1323            .collect();
1324
1325        let factory = create_test_provider_factory_with_chain_spec(chain_spec);
1326        let provider_rw = factory.database_provider_rw()?;
1327
1328        // Insert blocks into the database
1329        for block in &database_blocks {
1330            provider_rw.insert_block(
1331                &block.clone().try_recover().expect("failed to seal block with senders"),
1332            )?;
1333        }
1334
1335        // Insert receipts into the database
1336        if let Some(first_block) = database_blocks.first() {
1337            provider_rw.write_state(
1338                &ExecutionOutcome {
1339                    first_block: first_block.number,
1340                    receipts: receipts.iter().take(database_blocks.len()).cloned().collect(),
1341                    ..Default::default()
1342                },
1343                OriginalValuesKnown::No,
1344                StateWriteConfig::default(),
1345            )?;
1346        }
1347
1348        provider_rw.commit()?;
1349
1350        let provider = BlockchainProvider::new(factory)?;
1351
1352        // Insert the rest of the blocks and receipts into the in-memory state
1353        let chain = NewCanonicalChain::Commit {
1354            new: in_memory_blocks
1355                .iter()
1356                .map(|block| {
1357                    let senders = block.senders().expect("failed to recover senders");
1358                    let block_receipts = receipts.get(block.number as usize).unwrap().clone();
1359                    let execution_outcome = BlockExecutionOutput {
1360                        result: BlockExecutionResult {
1361                            receipts: block_receipts,
1362                            requests: Default::default(),
1363                            gas_used: 0,
1364                            blob_gas_used: 0,
1365                        },
1366                        state: BundleState::default(),
1367                    };
1368
1369                    ExecutedBlock {
1370                        recovered_block: Arc::new(RecoveredBlock::new_sealed(
1371                            block.clone(),
1372                            senders,
1373                        )),
1374                        execution_output: execution_outcome.into(),
1375                        ..Default::default()
1376                    }
1377                })
1378                .collect(),
1379        };
1380        provider.canonical_in_memory_state.update_chain(chain);
1381        for state in provider.canonical_in_memory_state.canonical_chain() {
1382            provider.database.overlay_manager().insert_block(state.block());
1383        }
1384
1385        // Get canonical, safe, and finalized blocks
1386        let blocks = database_blocks.iter().chain(in_memory_blocks.iter()).collect::<Vec<_>>();
1387        let block_count = blocks.len();
1388        let canonical_block = blocks.get(block_count - 1).unwrap();
1389        let safe_block = blocks.get(block_count - 2).unwrap();
1390        let finalized_block = blocks.get(block_count - 3).unwrap();
1391
1392        // Set the canonical head, safe, and finalized blocks
1393        provider.set_canonical_head(canonical_block.clone_sealed_header());
1394        provider.set_safe(safe_block.clone_sealed_header());
1395        provider.set_finalized(finalized_block.clone_sealed_header());
1396
1397        Ok((provider, database_blocks.clone(), in_memory_blocks.clone(), receipts))
1398    }
1399
1400    #[expect(clippy::type_complexity)]
1401    fn provider_with_random_blocks(
1402        rng: &mut impl Rng,
1403        database_blocks: usize,
1404        in_memory_blocks: usize,
1405        block_range_params: BlockRangeParams,
1406    ) -> eyre::Result<(
1407        BlockchainProvider<MockNodeTypesWithDB>,
1408        Vec<SealedBlock<Block>>,
1409        Vec<SealedBlock<Block>>,
1410        Vec<Vec<Receipt>>,
1411    )> {
1412        provider_with_chain_spec_and_random_blocks(
1413            rng,
1414            MAINNET.clone(),
1415            database_blocks,
1416            in_memory_blocks,
1417            block_range_params,
1418        )
1419    }
1420
1421    /// This will persist the last block in-memory and delete it from
1422    /// `canonical_in_memory_state` right after a database read transaction is created.
1423    ///
1424    /// This simulates a RPC method having a different view than when its database transaction was
1425    /// created.
1426    fn persist_block_after_db_tx_creation(
1427        provider: BlockchainProvider<MockNodeTypesWithDB>,
1428        block_number: BlockNumber,
1429    ) {
1430        let hook_provider = provider.clone();
1431        provider.database.db_ref().set_post_transaction_hook(Box::new(move || {
1432            if let Some(state) = hook_provider.canonical_in_memory_state.head_state() &&
1433                state.anchor().number + 1 == block_number
1434            {
1435                let mut lowest_memory_block =
1436                    state.parent_state_chain().last().expect("qed").block();
1437                let num_hash = lowest_memory_block.recovered_block().num_hash();
1438
1439                let execution_output = (*lowest_memory_block.execution_output).clone();
1440                lowest_memory_block.execution_output = Arc::new(execution_output);
1441
1442                // Push to disk
1443                let provider_rw = hook_provider.database_provider_rw().unwrap();
1444                let input = SaveBlocksInput::new(
1445                    vec![lowest_memory_block],
1446                    state.anchor().number,
1447                    state.anchor().number,
1448                    block_number,
1449                    block_number,
1450                );
1451                provider_rw.save_blocks(&input).unwrap();
1452                provider_rw.commit().unwrap();
1453
1454                // Remove from memory
1455                hook_provider.canonical_in_memory_state.remove_persisted_blocks(num_hash);
1456            }
1457        }));
1458    }
1459
1460    #[test]
1461    fn test_block_reader_find_block_by_hash() -> eyre::Result<()> {
1462        // Initialize random number generator and provider factory
1463        let mut rng = generators::rng();
1464        let factory = create_test_provider_factory();
1465
1466        // Generate 10 random blocks and split into database and in-memory blocks
1467        let blocks = random_block_range(
1468            &mut rng,
1469            0..=10,
1470            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1471        );
1472        let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1473
1474        // Insert first 5 blocks into the database
1475        let provider_rw = factory.provider_rw()?;
1476        for block in database_blocks {
1477            provider_rw.insert_block(
1478                &block.clone().try_recover().expect("failed to seal block with senders"),
1479            )?;
1480        }
1481
1482        provider_rw.commit()?;
1483
1484        // Create a new provider
1485        let provider = BlockchainProvider::new(factory)?;
1486
1487        // Useful blocks
1488        let first_db_block = database_blocks.first().unwrap();
1489        let first_in_mem_block = in_memory_blocks.first().unwrap();
1490        let last_in_mem_block = in_memory_blocks.last().unwrap();
1491
1492        // No block in memory before setting in memory state
1493        assert_eq!(provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?, None);
1494        assert_eq!(
1495            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1496            None
1497        );
1498        // No pending block in memory
1499        assert_eq!(
1500            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Pending)?,
1501            None
1502        );
1503
1504        // Insert first block into the in-memory state
1505        let in_memory_block_senders =
1506            first_in_mem_block.senders().expect("failed to recover senders");
1507        let chain = NewCanonicalChain::Commit {
1508            new: vec![ExecutedBlock {
1509                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1510                    first_in_mem_block.clone(),
1511                    in_memory_block_senders,
1512                )),
1513                ..Default::default()
1514            }],
1515        };
1516        provider.canonical_in_memory_state.update_chain(chain);
1517
1518        // Now the block should be found in memory
1519        assert_eq!(
1520            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Any)?,
1521            Some(first_in_mem_block.clone().into_block())
1522        );
1523        assert_eq!(
1524            provider.find_block_by_hash(first_in_mem_block.hash(), BlockSource::Canonical)?,
1525            Some(first_in_mem_block.clone().into_block())
1526        );
1527
1528        // Find the first block in database by hash
1529        assert_eq!(
1530            provider.find_block_by_hash(first_db_block.hash(), BlockSource::Any)?,
1531            Some(first_db_block.clone().into_block())
1532        );
1533        assert_eq!(
1534            provider.find_block_by_hash(first_db_block.hash(), BlockSource::Canonical)?,
1535            Some(first_db_block.clone().into_block())
1536        );
1537
1538        // No pending block in database
1539        assert_eq!(provider.find_block_by_hash(first_db_block.hash(), BlockSource::Pending)?, None);
1540
1541        // Insert the last block into the pending state
1542        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1543            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1544                last_in_mem_block.clone(),
1545                Default::default(),
1546            )),
1547            ..Default::default()
1548        });
1549
1550        // Now the last block should be found in memory
1551        assert_eq!(
1552            provider.find_block_by_hash(last_in_mem_block.hash(), BlockSource::Pending)?,
1553            Some(last_in_mem_block.clone().into_block())
1554        );
1555
1556        Ok(())
1557    }
1558
1559    #[test]
1560    fn test_block_reader_block() -> eyre::Result<()> {
1561        // Initialize random number generator and provider factory
1562        let mut rng = generators::rng();
1563        let factory = create_test_provider_factory();
1564
1565        // Generate 10 random blocks and split into database and in-memory blocks
1566        let blocks = random_block_range(
1567            &mut rng,
1568            0..=10,
1569            BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1570        );
1571        let (database_blocks, in_memory_blocks) = blocks.split_at(5);
1572
1573        // Insert first 5 blocks into the database
1574        let provider_rw = factory.provider_rw()?;
1575        for block in database_blocks {
1576            provider_rw.insert_block(
1577                &block.clone().try_recover().expect("failed to seal block with senders"),
1578            )?;
1579        }
1580        provider_rw.commit()?;
1581
1582        // Create a new provider
1583        let provider = BlockchainProvider::new(factory)?;
1584
1585        // First in memory block
1586        let first_in_mem_block = in_memory_blocks.first().unwrap();
1587        // First database block
1588        let first_db_block = database_blocks.first().unwrap();
1589
1590        // First in memory block should not be found yet as not integrated to the in-memory state
1591        assert_eq!(provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?, None);
1592        assert_eq!(provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?, None);
1593
1594        // Insert first block into the in-memory state
1595        let in_memory_block_senders =
1596            first_in_mem_block.senders().expect("failed to recover senders");
1597        let chain = NewCanonicalChain::Commit {
1598            new: vec![ExecutedBlock {
1599                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1600                    first_in_mem_block.clone(),
1601                    in_memory_block_senders,
1602                )),
1603                ..Default::default()
1604            }],
1605        };
1606        provider.canonical_in_memory_state.update_chain(chain);
1607
1608        // First in memory block should be found
1609        assert_eq!(
1610            provider.block(BlockHashOrNumber::Hash(first_in_mem_block.hash()))?,
1611            Some(first_in_mem_block.clone().into_block())
1612        );
1613        assert_eq!(
1614            provider.block(BlockHashOrNumber::Number(first_in_mem_block.number))?,
1615            Some(first_in_mem_block.clone().into_block())
1616        );
1617
1618        // First database block should be found
1619        assert_eq!(
1620            provider.block(BlockHashOrNumber::Hash(first_db_block.hash()))?,
1621            Some(first_db_block.clone().into_block())
1622        );
1623        assert_eq!(
1624            provider.block(BlockHashOrNumber::Number(first_db_block.number))?,
1625            Some(first_db_block.clone().into_block())
1626        );
1627
1628        Ok(())
1629    }
1630
1631    #[test]
1632    fn test_block_reader_pending_block() -> eyre::Result<()> {
1633        let mut rng = generators::rng();
1634        let (provider, _, _, _) = provider_with_random_blocks(
1635            &mut rng,
1636            TEST_BLOCKS_COUNT,
1637            TEST_BLOCKS_COUNT,
1638            BlockRangeParams::default(),
1639        )?;
1640
1641        // Generate a random block
1642        let mut rng = generators::rng();
1643        let block = random_block(
1644            &mut rng,
1645            0,
1646            BlockParams { parent: Some(B256::ZERO), ..Default::default() },
1647        );
1648
1649        // Set the block as pending
1650        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
1651            recovered_block: Arc::new(RecoveredBlock::new_sealed(
1652                block.clone(),
1653                block.senders().unwrap(),
1654            )),
1655            ..Default::default()
1656        });
1657
1658        // Assertions related to the pending block
1659
1660        let pending_block = provider.pending_block()?.unwrap();
1661        assert_eq!(
1662            *pending_block,
1663            RecoveredBlock::new_sealed(block.clone(), block.senders().unwrap())
1664        );
1665
1666        let pending = provider.pending_block_and_receipts()?.unwrap();
1667        assert!(Arc::ptr_eq(&pending_block, pending.block()));
1668        assert!(pending.execution_output().receipts.is_empty());
1669
1670        Ok(())
1671    }
1672
1673    #[test]
1674    fn test_block_body_indices() -> eyre::Result<()> {
1675        // Create a new provider
1676        let mut rng = generators::rng();
1677        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1678            &mut rng,
1679            TEST_BLOCKS_COUNT,
1680            TEST_BLOCKS_COUNT,
1681            BlockRangeParams {
1682                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
1683                ..Default::default()
1684            },
1685        )?;
1686
1687        let first_in_mem_block = in_memory_blocks.first().unwrap();
1688
1689        // Insert the first block into the in-memory state
1690        let in_memory_block_senders =
1691            first_in_mem_block.senders().expect("failed to recover senders");
1692        let chain = NewCanonicalChain::Commit {
1693            new: vec![ExecutedBlock {
1694                recovered_block: Arc::new(RecoveredBlock::new_sealed(
1695                    first_in_mem_block.clone(),
1696                    in_memory_block_senders,
1697                )),
1698                ..Default::default()
1699            }],
1700        };
1701        provider.canonical_in_memory_state.update_chain(chain);
1702
1703        let first_db_block = database_blocks.first().unwrap().clone();
1704        let first_in_mem_block = in_memory_blocks.first().unwrap().clone();
1705
1706        // First database block body indices should be found
1707        assert_eq!(
1708            provider.block_body_indices(first_db_block.number)?.unwrap(),
1709            StoredBlockBodyIndices { first_tx_num: 0, tx_count: 4 }
1710        );
1711
1712        // First in-memory block body indices should be found with the first tx after the database
1713        // blocks
1714        assert_eq!(
1715            provider.block_body_indices(first_in_mem_block.number)?.unwrap(),
1716            StoredBlockBodyIndices { first_tx_num: 20, tx_count: 4 }
1717        );
1718
1719        // A random block number should return None as the block is not found
1720        let mut rng = rand::rng();
1721        let random_block_number: u64 = rng.random();
1722        assert_eq!(provider.block_body_indices(random_block_number)?, None);
1723
1724        Ok(())
1725    }
1726
1727    #[test]
1728    fn test_block_hash_reader() -> eyre::Result<()> {
1729        let mut rng = generators::rng();
1730        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1731            &mut rng,
1732            TEST_BLOCKS_COUNT,
1733            TEST_BLOCKS_COUNT,
1734            BlockRangeParams::default(),
1735        )?;
1736
1737        let database_block = database_blocks.first().unwrap().clone();
1738        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1739
1740        assert_eq!(provider.block_hash(database_block.number)?, Some(database_block.hash()));
1741        assert_eq!(provider.block_hash(in_memory_block.number)?, Some(in_memory_block.hash()));
1742
1743        assert_eq!(
1744            provider.canonical_hashes_range(0, 10)?,
1745            [database_blocks, in_memory_blocks]
1746                .concat()
1747                .iter()
1748                .map(|block| block.hash())
1749                .collect::<Vec<_>>()
1750        );
1751
1752        Ok(())
1753    }
1754
1755    #[test]
1756    fn test_header_provider() -> eyre::Result<()> {
1757        let mut rng = generators::rng();
1758        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1759            &mut rng,
1760            TEST_BLOCKS_COUNT,
1761            TEST_BLOCKS_COUNT,
1762            BlockRangeParams::default(),
1763        )?;
1764
1765        // make sure that the finalized block is on db
1766        let finalized_block = database_blocks.get(database_blocks.len() - 3).unwrap();
1767        provider.set_finalized(finalized_block.clone_sealed_header());
1768
1769        let blocks = [database_blocks, in_memory_blocks].concat();
1770
1771        assert_eq!(
1772            provider.sealed_headers_while(0..=10, |header| header.number <= 8)?,
1773            blocks
1774                .iter()
1775                .take_while(|header| header.number <= 8)
1776                .map(|b| b.clone_sealed_header())
1777                .collect::<Vec<_>>()
1778        );
1779
1780        Ok(())
1781    }
1782
1783    #[tokio::test]
1784    async fn test_canon_state_subscriptions() -> eyre::Result<()> {
1785        let factory = create_test_provider_factory();
1786
1787        // Generate a random block to initialize the blockchain provider.
1788        let mut test_block_builder = TestBlockBuilder::eth();
1789        let block_1 = test_block_builder.generate_random_block(0, B256::ZERO).try_recover()?;
1790        let block_hash_1 = block_1.hash();
1791
1792        // Insert and commit the block.
1793        let provider_rw = factory.provider_rw()?;
1794        provider_rw.insert_block(&block_1)?;
1795        provider_rw.commit()?;
1796
1797        let provider = BlockchainProvider::new(factory)?;
1798
1799        // Subscribe twice for canonical state updates.
1800        let in_memory_state = provider.canonical_in_memory_state();
1801        let mut rx_1 = provider.subscribe_to_canonical_state();
1802        let mut rx_2 = provider.subscribe_to_canonical_state();
1803
1804        // Send and receive commit notifications.
1805        let block_2 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1806        let chain = Chain::new(vec![block_2], ExecutionOutcome::default(), BTreeMap::new());
1807        let commit = CanonStateNotification::Commit { new: Arc::new(chain.clone()) };
1808        in_memory_state.notify_canon_state(commit.clone());
1809        let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1810        assert_eq!(notification_1, Ok(commit.clone()));
1811        assert_eq!(notification_2, Ok(commit.clone()));
1812
1813        // Send and receive re-org notifications.
1814        let block_3 = test_block_builder.generate_random_block(1, block_hash_1).try_recover()?;
1815        let block_4 = test_block_builder.generate_random_block(2, block_3.hash()).try_recover()?;
1816        let new_chain =
1817            Chain::new(vec![block_3, block_4], ExecutionOutcome::default(), BTreeMap::new());
1818        let re_org =
1819            CanonStateNotification::Reorg { old: Arc::new(chain), new: Arc::new(new_chain) };
1820        in_memory_state.notify_canon_state(re_org.clone());
1821        let (notification_1, notification_2) = tokio::join!(rx_1.recv(), rx_2.recv());
1822        assert_eq!(notification_1, Ok(re_org.clone()));
1823        assert_eq!(notification_2, Ok(re_org.clone()));
1824
1825        Ok(())
1826    }
1827
1828    #[test]
1829    fn test_block_num_reader() -> eyre::Result<()> {
1830        let mut rng = generators::rng();
1831        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1832            &mut rng,
1833            TEST_BLOCKS_COUNT,
1834            TEST_BLOCKS_COUNT,
1835            BlockRangeParams::default(),
1836        )?;
1837
1838        assert_eq!(provider.best_block_number()?, in_memory_blocks.last().unwrap().number);
1839        assert_eq!(provider.last_block_number()?, database_blocks.last().unwrap().number);
1840
1841        let database_block = database_blocks.first().unwrap().clone();
1842        let in_memory_block = in_memory_blocks.first().unwrap().clone();
1843        assert_eq!(provider.block_number(database_block.hash())?, Some(database_block.number));
1844        assert_eq!(provider.block_number(in_memory_block.hash())?, Some(in_memory_block.number));
1845
1846        Ok(())
1847    }
1848
1849    #[test]
1850    fn test_block_reader_id_ext_block_by_id() -> eyre::Result<()> {
1851        let mut rng = generators::rng();
1852        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1853            &mut rng,
1854            TEST_BLOCKS_COUNT,
1855            TEST_BLOCKS_COUNT,
1856            BlockRangeParams::default(),
1857        )?;
1858
1859        let database_block = database_blocks.first().unwrap().clone();
1860        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1861
1862        let block_number = database_block.number;
1863        let block_hash = database_block.hash();
1864
1865        assert_eq!(
1866            provider.block_by_id(block_number.into()).unwrap(),
1867            Some(database_block.clone().into_block())
1868        );
1869        assert_eq!(
1870            provider.block_by_id(block_hash.into()).unwrap(),
1871            Some(database_block.into_block())
1872        );
1873
1874        let block_number = in_memory_block.number;
1875        let block_hash = in_memory_block.hash();
1876        assert_eq!(
1877            provider.block_by_id(block_number.into()).unwrap(),
1878            Some(in_memory_block.clone().into_block())
1879        );
1880        assert_eq!(
1881            provider.block_by_id(block_hash.into()).unwrap(),
1882            Some(in_memory_block.into_block())
1883        );
1884
1885        Ok(())
1886    }
1887
1888    #[test]
1889    fn test_block_reader_id_ext_header_by_number_or_tag() -> eyre::Result<()> {
1890        let mut rng = generators::rng();
1891        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1892            &mut rng,
1893            TEST_BLOCKS_COUNT,
1894            TEST_BLOCKS_COUNT,
1895            BlockRangeParams::default(),
1896        )?;
1897
1898        let database_block = database_blocks.first().unwrap().clone();
1899
1900        let in_memory_block_count = in_memory_blocks.len();
1901        let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
1902        let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
1903        let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
1904
1905        let block_number = database_block.number;
1906        assert_eq!(
1907            provider.header_by_number_or_tag(block_number.into()).unwrap(),
1908            Some(database_block.header().clone())
1909        );
1910        assert_eq!(
1911            provider.sealed_header_by_number_or_tag(block_number.into())?,
1912            Some(database_block.clone_sealed_header())
1913        );
1914
1915        assert_eq!(
1916            provider.header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1917            Some(canonical_block.header().clone())
1918        );
1919        assert_eq!(
1920            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Latest).unwrap(),
1921            Some(canonical_block.clone_sealed_header())
1922        );
1923
1924        assert_eq!(
1925            provider.header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1926            Some(safe_block.header().clone())
1927        );
1928        assert_eq!(
1929            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Safe).unwrap(),
1930            Some(safe_block.clone_sealed_header())
1931        );
1932
1933        assert_eq!(
1934            provider.header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1935            Some(finalized_block.header().clone())
1936        );
1937        assert_eq!(
1938            provider.sealed_header_by_number_or_tag(BlockNumberOrTag::Finalized).unwrap(),
1939            Some(finalized_block.clone_sealed_header())
1940        );
1941
1942        Ok(())
1943    }
1944
1945    #[test]
1946    fn test_block_reader_id_ext_header_by_id() -> eyre::Result<()> {
1947        let mut rng = generators::rng();
1948        let (provider, database_blocks, in_memory_blocks, _) = provider_with_random_blocks(
1949            &mut rng,
1950            TEST_BLOCKS_COUNT,
1951            TEST_BLOCKS_COUNT,
1952            BlockRangeParams::default(),
1953        )?;
1954
1955        let database_block = database_blocks.first().unwrap().clone();
1956        let in_memory_block = in_memory_blocks.last().unwrap().clone();
1957
1958        let block_number = database_block.number;
1959        let block_hash = database_block.hash();
1960
1961        assert_eq!(
1962            provider.header_by_id(block_number.into()).unwrap(),
1963            Some(database_block.header().clone())
1964        );
1965        assert_eq!(
1966            provider.sealed_header_by_id(block_number.into()).unwrap(),
1967            Some(database_block.clone_sealed_header())
1968        );
1969
1970        assert_eq!(
1971            provider.header_by_id(block_hash.into()).unwrap(),
1972            Some(database_block.header().clone())
1973        );
1974        assert_eq!(
1975            provider.sealed_header_by_id(block_hash.into()).unwrap(),
1976            Some(database_block.clone_sealed_header())
1977        );
1978
1979        let block_number = in_memory_block.number;
1980        let block_hash = in_memory_block.hash();
1981
1982        assert_eq!(
1983            provider.header_by_id(block_number.into()).unwrap(),
1984            Some(in_memory_block.header().clone())
1985        );
1986        assert_eq!(
1987            provider.sealed_header_by_id(block_number.into()).unwrap(),
1988            Some(in_memory_block.clone_sealed_header())
1989        );
1990
1991        assert_eq!(
1992            provider.header_by_id(block_hash.into()).unwrap(),
1993            Some(in_memory_block.header().clone())
1994        );
1995        assert_eq!(
1996            provider.sealed_header_by_id(block_hash.into()).unwrap(),
1997            Some(in_memory_block.clone_sealed_header())
1998        );
1999
2000        Ok(())
2001    }
2002
2003    #[test]
2004    fn test_receipt_provider_id_ext_receipts_by_block_id() -> eyre::Result<()> {
2005        let mut rng = generators::rng();
2006        let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2007            &mut rng,
2008            TEST_BLOCKS_COUNT,
2009            TEST_BLOCKS_COUNT,
2010            BlockRangeParams { tx_count: 1..3, ..Default::default() },
2011        )?;
2012
2013        let database_block = database_blocks.first().unwrap().clone();
2014        let in_memory_block = in_memory_blocks.last().unwrap().clone();
2015
2016        let block_number = database_block.number;
2017        let block_hash = database_block.hash();
2018
2019        assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
2020        assert!(!provider
2021            .receipts_by_number_or_tag(database_block.number.into())?
2022            .unwrap()
2023            .is_empty());
2024
2025        assert_eq!(
2026            provider.receipts_by_block_id(block_number.into())?.unwrap(),
2027            receipts.get(block_number as usize).unwrap().clone()
2028        );
2029        assert_eq!(
2030            provider.receipts_by_block_id(block_hash.into())?.unwrap(),
2031            receipts.get(block_number as usize).unwrap().clone()
2032        );
2033
2034        let block_number = in_memory_block.number;
2035        let block_hash = in_memory_block.hash();
2036
2037        assert_eq!(
2038            provider.receipts_by_block_id(block_number.into())?.unwrap(),
2039            receipts.get(block_number as usize).unwrap().clone()
2040        );
2041        assert_eq!(
2042            provider.receipts_by_block_id(block_hash.into())?.unwrap(),
2043            receipts.get(block_number as usize).unwrap().clone()
2044        );
2045
2046        Ok(())
2047    }
2048
2049    #[test]
2050    fn test_receipt_provider_id_ext_receipts_by_block_number_or_tag() -> eyre::Result<()> {
2051        let mut rng = generators::rng();
2052        let (provider, database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2053            &mut rng,
2054            TEST_BLOCKS_COUNT,
2055            TEST_BLOCKS_COUNT,
2056            BlockRangeParams { tx_count: 1..3, ..Default::default() },
2057        )?;
2058
2059        let database_block = database_blocks.first().unwrap().clone();
2060
2061        let in_memory_block_count = in_memory_blocks.len();
2062        let canonical_block = in_memory_blocks.get(in_memory_block_count - 1).unwrap().clone();
2063        let safe_block = in_memory_blocks.get(in_memory_block_count - 2).unwrap().clone();
2064        let finalized_block = in_memory_blocks.get(in_memory_block_count - 3).unwrap().clone();
2065
2066        assert!(!receipts.get(database_block.number as usize).unwrap().is_empty());
2067        assert!(!provider
2068            .receipts_by_number_or_tag(database_block.number.into())?
2069            .unwrap()
2070            .is_empty());
2071
2072        assert_eq!(
2073            provider.receipts_by_number_or_tag(database_block.number.into())?.unwrap(),
2074            receipts.get(database_block.number as usize).unwrap().clone()
2075        );
2076        assert_eq!(
2077            provider.receipts_by_number_or_tag(BlockNumberOrTag::Latest)?.unwrap(),
2078            receipts.get(canonical_block.number as usize).unwrap().clone()
2079        );
2080        assert_eq!(
2081            provider.receipts_by_number_or_tag(BlockNumberOrTag::Safe)?.unwrap(),
2082            receipts.get(safe_block.number as usize).unwrap().clone()
2083        );
2084        assert_eq!(
2085            provider.receipts_by_number_or_tag(BlockNumberOrTag::Finalized)?.unwrap(),
2086            receipts.get(finalized_block.number as usize).unwrap().clone()
2087        );
2088
2089        Ok(())
2090    }
2091
2092    #[test]
2093    fn test_changeset_reader() -> eyre::Result<()> {
2094        let mut rng = generators::rng();
2095
2096        let (database_blocks, in_memory_blocks) =
2097            random_blocks(&mut rng, TEST_BLOCKS_COUNT, 1, None, None, 0..1);
2098
2099        let first_database_block = database_blocks.first().map(|block| block.number).unwrap();
2100        let last_database_block = database_blocks.last().map(|block| block.number).unwrap();
2101        let first_in_memory_block = in_memory_blocks.first().map(|block| block.number).unwrap();
2102
2103        let accounts = random_eoa_accounts(&mut rng, 2);
2104
2105        let (database_changesets, database_state) = random_changeset_range(
2106            &mut rng,
2107            &database_blocks,
2108            accounts.into_iter().map(|(address, account)| (address, (account, Vec::new()))),
2109            0..0,
2110            0..0,
2111        );
2112        let (in_memory_changesets, in_memory_state) = random_changeset_range(
2113            &mut rng,
2114            &in_memory_blocks,
2115            database_state.iter().map(|(address, (account, storage))| {
2116                (*address, (account.clone(), storage.clone()))
2117            }),
2118            0..0,
2119            0..0,
2120        );
2121
2122        let factory = create_test_provider_factory();
2123
2124        let provider_rw = factory.provider_rw()?;
2125        provider_rw.append_blocks_with_state(
2126            database_blocks
2127                .into_iter()
2128                .map(|b| b.try_recover().expect("failed to seal block with senders"))
2129                .collect(),
2130            &ExecutionOutcome {
2131                bundle: BundleState::new(
2132                    database_state.into_iter().map(|(address, (account, _))| {
2133                        (address, None, Some(account.into()), Default::default())
2134                    }),
2135                    database_changesets.iter().map(|block_changesets| {
2136                        block_changesets.iter().map(|(address, account, _)| {
2137                            (*address, Some(Some(account.clone().into())), [])
2138                        })
2139                    }),
2140                    Vec::new(),
2141                ),
2142                first_block: first_database_block,
2143                ..Default::default()
2144            },
2145            Default::default(),
2146        )?;
2147        provider_rw.commit()?;
2148
2149        let provider = BlockchainProvider::new(factory)?;
2150
2151        let in_memory_changesets = in_memory_changesets.into_iter().next().unwrap();
2152        let chain = NewCanonicalChain::Commit {
2153            new: vec![in_memory_blocks
2154                .first()
2155                .map(|block| {
2156                    let senders = block.senders().expect("failed to recover senders");
2157                    ExecutedBlock {
2158                        recovered_block: Arc::new(RecoveredBlock::new_sealed(
2159                            block.clone(),
2160                            senders,
2161                        )),
2162                        execution_output: Arc::new(BlockExecutionOutput {
2163                            state: BundleState::new(
2164                                in_memory_state.into_iter().map(|(address, (account, _))| {
2165                                    (address, None, Some(account.into()), Default::default())
2166                                }),
2167                                [in_memory_changesets.iter().map(|(address, account, _)| {
2168                                    (*address, Some(Some(account.clone().into())), Vec::new())
2169                                })],
2170                                [],
2171                            ),
2172                            result: BlockExecutionResult {
2173                                receipts: Default::default(),
2174                                requests: Default::default(),
2175                                gas_used: 0,
2176                                blob_gas_used: 0,
2177                            },
2178                        }),
2179                        ..Default::default()
2180                    }
2181                })
2182                .unwrap()],
2183        };
2184        provider.canonical_in_memory_state.update_chain(chain);
2185
2186        assert_eq!(
2187            provider.account_block_changeset(last_database_block).unwrap(),
2188            database_changesets
2189                .into_iter()
2190                .next_back()
2191                .unwrap()
2192                .into_iter()
2193                .sorted_by_key(|(address, _, _)| *address)
2194                .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2195                .collect::<Vec<_>>()
2196        );
2197        assert_eq!(
2198            provider.account_block_changeset(first_in_memory_block).unwrap(),
2199            in_memory_changesets
2200                .into_iter()
2201                .sorted_by_key(|(address, _, _)| *address)
2202                .map(|(address, account, _)| AccountBeforeTx { address, info: Some(account) })
2203                .collect::<Vec<_>>()
2204        );
2205
2206        Ok(())
2207    }
2208
2209    #[test]
2210    fn test_state_provider_factory() -> eyre::Result<()> {
2211        let mut rng = generators::rng();
2212
2213        // test in-memory state use-cases
2214        let (in_memory_provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2215            &mut rng,
2216            TEST_BLOCKS_COUNT,
2217            TEST_BLOCKS_COUNT,
2218            BlockRangeParams::default(),
2219        )?;
2220
2221        // test database state use-cases
2222        let (only_database_provider, database_blocks, _, _) = provider_with_random_blocks(
2223            &mut rng,
2224            TEST_BLOCKS_COUNT,
2225            0,
2226            BlockRangeParams::default(),
2227        )?;
2228
2229        let blocks = [database_blocks.clone(), in_memory_blocks.clone()].concat();
2230        let first_in_memory_block = in_memory_blocks.first().unwrap();
2231        let first_db_block = database_blocks.first().unwrap();
2232
2233        // test latest state
2234        assert_eq!(
2235            first_in_memory_block.hash(),
2236            in_memory_provider.latest().unwrap().block_hash(first_in_memory_block.number)?.unwrap()
2237        );
2238        // test latest falls back to database state when there's no in-memory block
2239        assert_eq!(
2240            first_db_block.hash(),
2241            only_database_provider.latest().unwrap().block_hash(first_db_block.number)?.unwrap()
2242        );
2243
2244        // test history by block number
2245        assert_eq!(
2246            first_in_memory_block.hash(),
2247            in_memory_provider
2248                .history_by_block_number(first_in_memory_block.number)?
2249                .block_hash(first_in_memory_block.number)?
2250                .unwrap()
2251        );
2252        assert_eq!(
2253            first_db_block.hash(),
2254            only_database_provider
2255                .history_by_block_number(first_db_block.number)?
2256                .block_hash(first_db_block.number)?
2257                .unwrap()
2258        );
2259        assert_eq!(
2260            first_in_memory_block.hash(),
2261            in_memory_provider
2262                .history_by_block_hash(first_in_memory_block.hash())?
2263                .block_hash(first_in_memory_block.number)?
2264                .unwrap()
2265        );
2266        assert!(only_database_provider.history_by_block_hash(B256::random()).is_err());
2267
2268        // test state by block hash
2269        assert_eq!(
2270            first_in_memory_block.hash(),
2271            in_memory_provider
2272                .state_by_block_hash(first_in_memory_block.hash())?
2273                .block_hash(first_in_memory_block.number)?
2274                .unwrap()
2275        );
2276        assert_eq!(
2277            first_db_block.hash(),
2278            only_database_provider
2279                .state_by_block_hash(first_db_block.hash())?
2280                .block_hash(first_db_block.number)?
2281                .unwrap()
2282        );
2283        assert!(only_database_provider.state_by_block_hash(B256::random()).is_err());
2284
2285        // test pending without pending state- falls back to latest
2286        assert_eq!(
2287            first_in_memory_block.hash(),
2288            in_memory_provider
2289                .pending()
2290                .unwrap()
2291                .block_hash(first_in_memory_block.number)
2292                .unwrap()
2293                .unwrap()
2294        );
2295
2296        // adding a pending block to state can test pending() and  pending_state_by_hash() function
2297        let pending_block = database_blocks[database_blocks.len() - 1].clone();
2298        only_database_provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2299            recovered_block: Arc::new(RecoveredBlock::new_sealed(
2300                pending_block.clone(),
2301                Default::default(),
2302            )),
2303            ..Default::default()
2304        });
2305
2306        assert_eq!(
2307            pending_block.hash(),
2308            only_database_provider
2309                .pending()
2310                .unwrap()
2311                .block_hash(pending_block.number)
2312                .unwrap()
2313                .unwrap()
2314        );
2315
2316        assert_eq!(
2317            pending_block.hash(),
2318            only_database_provider
2319                .pending_state_by_hash(pending_block.hash())?
2320                .unwrap()
2321                .block_hash(pending_block.number)?
2322                .unwrap()
2323        );
2324
2325        // test state by block number or tag
2326        assert_eq!(
2327            first_in_memory_block.hash(),
2328            in_memory_provider
2329                .state_by_block_number_or_tag(BlockNumberOrTag::Number(
2330                    first_in_memory_block.number
2331                ))?
2332                .block_hash(first_in_memory_block.number)?
2333                .unwrap()
2334        );
2335        assert_eq!(
2336            first_in_memory_block.hash(),
2337            in_memory_provider
2338                .state_by_block_number_or_tag(BlockNumberOrTag::Latest)?
2339                .block_hash(first_in_memory_block.number)?
2340                .unwrap()
2341        );
2342        // test state by block tag for safe block
2343        let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2344        in_memory_provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2345        assert_eq!(
2346            safe_block.hash(),
2347            in_memory_provider
2348                .state_by_block_number_or_tag(BlockNumberOrTag::Safe)?
2349                .block_hash(safe_block.number)?
2350                .unwrap()
2351        );
2352        // test state by block tag for finalized block
2353        let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2354        in_memory_provider
2355            .canonical_in_memory_state
2356            .set_finalized(finalized_block.clone_sealed_header());
2357        assert_eq!(
2358            finalized_block.hash(),
2359            in_memory_provider
2360                .state_by_block_number_or_tag(BlockNumberOrTag::Finalized)?
2361                .block_hash(finalized_block.number)?
2362                .unwrap()
2363        );
2364        // test state by block tag for earliest block
2365        let earliest_block = blocks.first().unwrap().clone();
2366        assert_eq!(
2367            earliest_block.hash(),
2368            only_database_provider
2369                .state_by_block_number_or_tag(BlockNumberOrTag::Earliest)?
2370                .block_hash(earliest_block.number)?
2371                .unwrap()
2372        );
2373
2374        Ok(())
2375    }
2376
2377    #[test]
2378    fn test_block_id_reader() -> eyre::Result<()> {
2379        // Create a new provider
2380        let mut rng = generators::rng();
2381        let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2382            &mut rng,
2383            TEST_BLOCKS_COUNT,
2384            TEST_BLOCKS_COUNT,
2385            BlockRangeParams::default(),
2386        )?;
2387
2388        // Set the pending block in memory
2389        let pending_block = in_memory_blocks.last().unwrap();
2390        provider.canonical_in_memory_state.set_pending_block(ExecutedBlock {
2391            recovered_block: Arc::new(RecoveredBlock::new_sealed(
2392                pending_block.clone(),
2393                Default::default(),
2394            )),
2395            ..Default::default()
2396        });
2397
2398        // Set the safe block in memory
2399        let safe_block = in_memory_blocks[in_memory_blocks.len() - 2].clone();
2400        provider.canonical_in_memory_state.set_safe(safe_block.clone_sealed_header());
2401
2402        // Set the finalized block in memory
2403        let finalized_block = in_memory_blocks[in_memory_blocks.len() - 3].clone();
2404        provider.canonical_in_memory_state.set_finalized(finalized_block.clone_sealed_header());
2405
2406        // Verify the pending block number and hash
2407        assert_eq!(
2408            provider.pending_block_num_hash()?,
2409            Some(BlockNumHash { number: pending_block.number, hash: pending_block.hash() })
2410        );
2411
2412        // Verify the safe block number and hash
2413        assert_eq!(
2414            provider.safe_block_num_hash()?,
2415            Some(BlockNumHash { number: safe_block.number, hash: safe_block.hash() })
2416        );
2417
2418        // Verify the finalized block number and hash
2419        assert_eq!(
2420            provider.finalized_block_num_hash()?,
2421            Some(BlockNumHash { number: finalized_block.number, hash: finalized_block.hash() })
2422        );
2423
2424        Ok(())
2425    }
2426
2427    macro_rules! test_by_tx_range {
2428        ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2429
2430            // Get the number methods being tested.
2431            // Since each method tested will move a block from memory to storage, this ensures we have enough.
2432            let extra_blocks = [$(stringify!($method)),*].len();
2433
2434            let mut rng = generators::rng();
2435            let (provider, mut database_blocks, mut in_memory_blocks, receipts) = provider_with_random_blocks(
2436                &mut rng,
2437                TEST_BLOCKS_COUNT,
2438                TEST_BLOCKS_COUNT + extra_blocks,
2439                BlockRangeParams {
2440                    tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2441                    ..Default::default()
2442                },
2443            )?;
2444
2445            $(
2446                // Since data moves for each tried method, need to recalculate everything
2447                let db_tx_count =
2448                    database_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2449                let in_mem_tx_count =
2450                    in_memory_blocks.iter().map(|b| b.transaction_count()).sum::<usize>() as u64;
2451
2452                let db_range = 0..=(db_tx_count - 1);
2453                let in_mem_range = db_tx_count..=(in_mem_tx_count + db_range.end());
2454
2455                // Retrieve the expected database data
2456                let database_data =
2457                    database_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2458                assert_eq!(provider.$method(db_range.clone())?, database_data, "full db data");
2459
2460                // Retrieve the expected in-memory data
2461                let in_memory_data =
2462                    in_memory_blocks.iter().flat_map(|b| $data_extractor(b, &receipts)).collect::<Vec<_>>();
2463                assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data, "full mem data");
2464
2465                // Test partial in-memory range
2466                assert_eq!(
2467                    &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2468                    &in_memory_data[1..in_memory_data.len() - 1],
2469                    "partial mem data"
2470                );
2471
2472                // Test range in memory to unbounded end
2473                assert_eq!(provider.$method(in_mem_range.start() + 1..)?, &in_memory_data[1..], "unbounded mem data");
2474
2475                // Test last element in-memory
2476                assert_eq!(provider.$method(in_mem_range.end()..)?, &in_memory_data[in_memory_data.len() -1 ..], "last mem data");
2477
2478                // Test range that spans database and in-memory with unbounded end
2479                assert_eq!(
2480                    provider.$method(in_mem_range.start() - 2..)?,
2481                    database_data[database_data.len() - 2..]
2482                        .iter()
2483                        .chain(&in_memory_data[..])
2484                        .cloned()
2485                        .collect::<Vec<_>>(),
2486                    "unbounded span data"
2487                );
2488
2489                // Test range that spans database and in-memory
2490                {
2491                    // 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.
2492                    persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2493
2494                    assert_eq!(
2495                        provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2496                        database_data[database_data.len() - 2..]
2497                            .iter()
2498                            .chain(&in_memory_data[..in_memory_data.len() - 1])
2499                            .cloned()
2500                            .collect::<Vec<_>>(),
2501                        "span data"
2502                    );
2503
2504                    // Adjust our blocks accordingly
2505                    database_blocks.push(in_memory_blocks.remove(0));
2506                }
2507
2508                // Test invalid range
2509                let start_tx_num = u64::MAX;
2510                let end_tx_num = u64::MAX;
2511                let result = provider.$method(start_tx_num..end_tx_num)?;
2512                assert!(result.is_empty(), "No data should be found for an invalid transaction range");
2513
2514                // Test empty range
2515                let result = provider.$method(in_mem_range.end()+10..in_mem_range.end()+20)?;
2516                assert!(result.is_empty(), "No data should be found for an empty transaction range");
2517            )*
2518        }};
2519    }
2520
2521    #[test]
2522    fn test_methods_by_tx_range() -> eyre::Result<()> {
2523        test_by_tx_range!([
2524            (senders_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2525                .senders()
2526                .unwrap()),
2527            (transactions_by_tx_range, |block: &SealedBlock<Block>, _: &Vec<Vec<Receipt>>| block
2528                .body()
2529                .transactions
2530                .clone()),
2531            (receipts_by_tx_range, |block: &SealedBlock<Block>, receipts: &Vec<Vec<Receipt>>| {
2532                receipts[block.number as usize].clone()
2533            })
2534        ]);
2535
2536        Ok(())
2537    }
2538
2539    macro_rules! test_by_block_range {
2540        ([$(($method:ident, $data_extractor:expr)),* $(,)?]) => {{
2541            // Get the number methods being tested.
2542            // Since each method tested will move a block from memory to storage, this ensures we have enough.
2543            let extra_blocks = [$(stringify!($method)),*].len();
2544
2545            let mut rng = generators::rng();
2546            let (provider, mut database_blocks, mut in_memory_blocks, _) = provider_with_random_blocks(
2547                &mut rng,
2548                TEST_BLOCKS_COUNT,
2549                TEST_BLOCKS_COUNT + extra_blocks,
2550                BlockRangeParams {
2551                    tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2552                    ..Default::default()
2553                },
2554            )?;
2555
2556            $(
2557                // Since data moves for each tried method, need to recalculate everything
2558                let db_block_count = database_blocks.len() as u64;
2559                let in_mem_block_count = in_memory_blocks.len() as u64;
2560
2561                let db_range = 0..=db_block_count - 1;
2562                let in_mem_range = db_block_count..=(in_mem_block_count + db_range.end());
2563
2564                // Retrieve the expected database data
2565                let database_data =
2566                    database_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2567                assert_eq!(provider.$method(db_range.clone())?, database_data);
2568
2569                // Retrieve the expected in-memory data
2570                let in_memory_data =
2571                    in_memory_blocks.iter().map(|b| $data_extractor(b)).collect::<Vec<_>>();
2572                assert_eq!(provider.$method(in_mem_range.clone())?, in_memory_data);
2573
2574                // Test partial in-memory range
2575                assert_eq!(
2576                    &provider.$method(in_mem_range.start() + 1..=in_mem_range.end() - 1)?,
2577                    &in_memory_data[1..in_memory_data.len() - 1]
2578                );
2579
2580                // Test range that spans database and in-memory
2581                {
2582
2583                    // 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.
2584                    persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2585
2586                    assert_eq!(
2587                        provider.$method(in_mem_range.start() - 2..=in_mem_range.end() - 1)?,
2588                        database_data[database_data.len() - 2..]
2589                            .iter()
2590                            .chain(&in_memory_data[..in_memory_data.len() - 1])
2591                            .cloned()
2592                            .collect::<Vec<_>>()
2593                    );
2594
2595                    // Adjust our blocks accordingly
2596                    database_blocks.push(in_memory_blocks.remove(0));
2597                }
2598
2599                // Test invalid range
2600                let start_block_num = u64::MAX;
2601                let end_block_num = u64::MAX;
2602                let result = provider.$method(start_block_num..=end_block_num-1)?;
2603                assert!(result.is_empty(), "No data should be found for an invalid block range");
2604
2605                // Test valid range with empty results
2606                let result = provider.$method(in_mem_range.end() + 10..=in_mem_range.end() + 20)?;
2607                assert!(result.is_empty(), "No data should be found for an empty block range");
2608            )*
2609        }};
2610    }
2611
2612    #[test]
2613    fn test_methods_by_block_range() -> eyre::Result<()> {
2614        // todo(joshie) add canonical_hashes_range below after changing its interface into range
2615        // instead start end
2616        test_by_block_range!([
2617            (headers_range, |block: &SealedBlock<Block>| block.header().clone()),
2618            (sealed_headers_range, |block: &SealedBlock<Block>| block.clone_sealed_header()),
2619            (block_range, |block: &SealedBlock<Block>| block.clone().into_block()),
2620            (block_with_senders_range, |block: &SealedBlock<Block>| block
2621                .clone()
2622                .try_recover()
2623                .unwrap()),
2624            (recovered_block_range, |block: &SealedBlock<Block>| block
2625                .clone()
2626                .try_recover()
2627                .unwrap()),
2628            (transactions_by_block_range, |block: &SealedBlock<Block>| block
2629                .body()
2630                .transactions
2631                .clone()),
2632        ]);
2633
2634        Ok(())
2635    }
2636
2637    /// Helper macro to call a provider method based on argument count and check its result
2638    macro_rules! call_method {
2639        ($provider:expr, $method:ident, ($($args:expr),*), $expected_item:expr) => {{
2640            let result = $provider.$method($($args),*)?;
2641            assert_eq!(
2642                result,
2643                $expected_item,
2644                "{}: item does not match the expected item for arguments {:?}",
2645                stringify!($method),
2646                ($($args),*)
2647            );
2648        }};
2649
2650        // Handle valid or invalid arguments for one argument
2651        (ONE, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2652            let (arg, expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2653            call_method!($provider, $method, (arg), expected_item);
2654        }};
2655
2656        // Handle valid or invalid arguments for two arguments
2657        (TWO, $provider:expr, $method:ident, $item_extractor:expr, $txnum:expr, $txhash:expr, $block:expr, $receipts:expr) => {{
2658            let ((arg1, arg2), expected_item) = $item_extractor($block, $txnum($block), $txhash($block), $receipts);
2659            call_method!($provider, $method, (arg1, arg2), expected_item);
2660        }};
2661    }
2662
2663    /// Macro to test non-range methods.
2664    ///
2665    /// ( `NUMBER_ARGUMENTS`, METHOD, FN -> ((`METHOD_ARGUMENT(s)`,...), `EXPECTED_RESULT`),
2666    /// `INVALID_ARGUMENTS`)
2667    macro_rules! test_non_range {
2668    ([$(($arg_count:ident, $method:ident, $item_extractor:expr, $invalid_args:expr)),* $(,)?]) => {{
2669
2670        // Get the number methods being tested.
2671        // Since each method tested will move a block from memory to storage, this ensures we have enough.
2672        let extra_blocks = [$(stringify!($arg_count)),*].len();
2673
2674        let mut rng = generators::rng();
2675        let (provider, mut database_blocks, in_memory_blocks, receipts) = provider_with_random_blocks(
2676            &mut rng,
2677            TEST_BLOCKS_COUNT,
2678            TEST_BLOCKS_COUNT + extra_blocks,
2679            BlockRangeParams {
2680                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2681                ..Default::default()
2682            },
2683        )?;
2684
2685        let mut in_memory_blocks: std::collections::VecDeque<_> = in_memory_blocks.into();
2686
2687        $(
2688            let tx_hash = |block: &SealedBlock<Block>| *block.body().transactions[0].tx_hash();
2689            let tx_num = |block: &SealedBlock<Block>| {
2690                database_blocks
2691                    .iter()
2692                    .chain(in_memory_blocks.iter())
2693                    .take_while(|b| b.number < block.number)
2694                    .map(|b| b.transaction_count())
2695                    .sum::<usize>() as u64
2696            };
2697
2698            // Ensure that the first generated in-memory block exists
2699            {
2700                // 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.
2701                persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
2702
2703                call_method!($arg_count, provider, $method, $item_extractor, tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2704
2705                // Move the block as well in our own structures
2706                database_blocks.push(in_memory_blocks.pop_front().unwrap());
2707            }
2708
2709            // database_blocks is changed above
2710            let tx_num = |block: &SealedBlock<Block>| {
2711                database_blocks
2712                    .iter()
2713                    .chain(in_memory_blocks.iter())
2714                    .take_while(|b| b.number < block.number)
2715                    .map(|b| b.transaction_count())
2716                    .sum::<usize>() as u64
2717            };
2718
2719            // Invalid/Non-existent argument should return `None`
2720            {
2721                call_method!($arg_count, provider, $method, |_,_,_,_|  ($invalid_args, None), tx_num, tx_hash, &in_memory_blocks[0], &receipts);
2722            }
2723
2724            // Check that the item is only in memory and not in database
2725            {
2726                let last_mem_block = &in_memory_blocks[in_memory_blocks.len() - 1];
2727
2728                let (args, expected_item) = $item_extractor(last_mem_block, tx_num(last_mem_block), tx_hash(last_mem_block), &receipts);
2729                call_method!($arg_count, provider, $method, |_,_,_,_| (args.clone(), expected_item), tx_num, tx_hash, last_mem_block, &receipts);
2730
2731                // Ensure the item is not in storage
2732                call_method!($arg_count, provider.database, $method, |_,_,_,_|  (args, None), tx_num, tx_hash, last_mem_block, &receipts);
2733            }
2734        )*
2735    }};
2736}
2737
2738    #[test]
2739    fn test_non_range_methods() -> eyre::Result<()> {
2740        let test_tx_index = 0;
2741
2742        test_non_range!([
2743            (
2744                ONE,
2745                header,
2746                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2747                    block.hash(),
2748                    Some(block.header().clone())
2749                ),
2750                B256::random()
2751            ),
2752            (
2753                ONE,
2754                header_by_number,
2755                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2756                    block.number,
2757                    Some(block.header().clone())
2758                ),
2759                u64::MAX
2760            ),
2761            (
2762                ONE,
2763                sealed_header,
2764                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2765                    block.number,
2766                    Some(block.clone_sealed_header())
2767                ),
2768                u64::MAX
2769            ),
2770            (
2771                ONE,
2772                block_hash,
2773                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2774                    block.number,
2775                    Some(block.hash())
2776                ),
2777                u64::MAX
2778            ),
2779            (
2780                ONE,
2781                block_number,
2782                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2783                    block.hash(),
2784                    Some(block.number)
2785                ),
2786                B256::random()
2787            ),
2788            (
2789                ONE,
2790                block,
2791                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2792                    BlockHashOrNumber::Hash(block.hash()),
2793                    Some(block.clone().into_block())
2794                ),
2795                BlockHashOrNumber::Hash(B256::random())
2796            ),
2797            (
2798                ONE,
2799                block,
2800                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2801                    BlockHashOrNumber::Number(block.number),
2802                    Some(block.clone().into_block())
2803                ),
2804                BlockHashOrNumber::Number(u64::MAX)
2805            ),
2806            (
2807                ONE,
2808                block_body_indices,
2809                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2810                    block.number,
2811                    Some(StoredBlockBodyIndices {
2812                        first_tx_num: tx_num,
2813                        tx_count: block.transaction_count() as u64
2814                    })
2815                ),
2816                u64::MAX
2817            ),
2818            (
2819                TWO,
2820                recovered_block,
2821                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2822                    (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2823                    block.clone().try_recover().ok()
2824                ),
2825                (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2826            ),
2827            (
2828                TWO,
2829                recovered_block,
2830                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2831                    (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2832                    block.clone().try_recover().ok()
2833                ),
2834                (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2835            ),
2836            (
2837                TWO,
2838                sealed_block_with_senders,
2839                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2840                    (BlockHashOrNumber::Number(block.number), TransactionVariant::WithHash),
2841                    block.clone().try_recover().ok()
2842                ),
2843                (BlockHashOrNumber::Number(u64::MAX), TransactionVariant::WithHash)
2844            ),
2845            (
2846                TWO,
2847                sealed_block_with_senders,
2848                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2849                    (BlockHashOrNumber::Hash(block.hash()), TransactionVariant::WithHash),
2850                    block.clone().try_recover().ok()
2851                ),
2852                (BlockHashOrNumber::Hash(B256::random()), TransactionVariant::WithHash)
2853            ),
2854            (
2855                ONE,
2856                transaction_id,
2857                |_: &SealedBlock<Block>, tx_num: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2858                    tx_hash,
2859                    Some(tx_num)
2860                ),
2861                B256::random()
2862            ),
2863            (
2864                ONE,
2865                transaction_by_id,
2866                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2867                    tx_num,
2868                    Some(block.body().transactions[test_tx_index].clone())
2869                ),
2870                u64::MAX
2871            ),
2872            (
2873                ONE,
2874                transaction_by_id_unhashed,
2875                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2876                    tx_num,
2877                    Some(block.body().transactions[test_tx_index].clone())
2878                ),
2879                u64::MAX
2880            ),
2881            (
2882                ONE,
2883                transaction_by_hash,
2884                |block: &SealedBlock<Block>, _: TxNumber, tx_hash: B256, _: &Vec<Vec<Receipt>>| (
2885                    tx_hash,
2886                    Some(block.body().transactions[test_tx_index].clone())
2887                ),
2888                B256::random()
2889            ),
2890            (
2891                ONE,
2892                block_by_transaction_id,
2893                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2894                    tx_num,
2895                    Some(block.number)
2896                ),
2897                u64::MAX
2898            ),
2899            (
2900                ONE,
2901                transactions_by_block,
2902                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2903                    BlockHashOrNumber::Number(block.number),
2904                    Some(block.body().transactions.clone())
2905                ),
2906                BlockHashOrNumber::Number(u64::MAX)
2907            ),
2908            (
2909                ONE,
2910                transactions_by_block,
2911                |block: &SealedBlock<Block>, _: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2912                    BlockHashOrNumber::Hash(block.hash()),
2913                    Some(block.body().transactions.clone())
2914                ),
2915                BlockHashOrNumber::Number(u64::MAX)
2916            ),
2917            (
2918                ONE,
2919                transaction_sender,
2920                |block: &SealedBlock<Block>, tx_num: TxNumber, _: B256, _: &Vec<Vec<Receipt>>| (
2921                    tx_num,
2922                    block.body().transactions[test_tx_index].recover_signer().ok()
2923                ),
2924                u64::MAX
2925            ),
2926            (
2927                ONE,
2928                receipt,
2929                |block: &SealedBlock<Block>,
2930                 tx_num: TxNumber,
2931                 _: B256,
2932                 receipts: &Vec<Vec<Receipt>>| (
2933                    tx_num,
2934                    Some(receipts[block.number as usize][test_tx_index].clone())
2935                ),
2936                u64::MAX
2937            ),
2938            (
2939                ONE,
2940                receipt_by_hash,
2941                |block: &SealedBlock<Block>,
2942                 _: TxNumber,
2943                 tx_hash: B256,
2944                 receipts: &Vec<Vec<Receipt>>| (
2945                    tx_hash,
2946                    Some(receipts[block.number as usize][test_tx_index].clone())
2947                ),
2948                B256::random()
2949            ),
2950            (
2951                ONE,
2952                receipts_by_block,
2953                |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2954                    BlockHashOrNumber::Number(block.number),
2955                    Some(receipts[block.number as usize].clone())
2956                ),
2957                BlockHashOrNumber::Number(u64::MAX)
2958            ),
2959            (
2960                ONE,
2961                receipts_by_block,
2962                |block: &SealedBlock<Block>, _: TxNumber, _: B256, receipts: &Vec<Vec<Receipt>>| (
2963                    BlockHashOrNumber::Hash(block.hash()),
2964                    Some(receipts[block.number as usize].clone())
2965                ),
2966                BlockHashOrNumber::Hash(B256::random())
2967            ),
2968            // TODO: withdrawals, requests, ommers
2969        ]);
2970
2971        Ok(())
2972    }
2973
2974    #[test]
2975    fn test_race() -> eyre::Result<()> {
2976        let mut rng = generators::rng();
2977        let (provider, _, in_memory_blocks, _) = provider_with_random_blocks(
2978            &mut rng,
2979            TEST_BLOCKS_COUNT - 1,
2980            TEST_BLOCKS_COUNT + 1,
2981            BlockRangeParams {
2982                tx_count: TEST_TRANSACTIONS_COUNT..TEST_TRANSACTIONS_COUNT,
2983                ..Default::default()
2984            },
2985        )?;
2986
2987        // Old implementation was querying the database first. This is problematic, if there are
2988        // changes AFTER the database transaction is created.
2989        let old_transaction_hash_fn =
2990            |hash: B256,
2991             canonical_in_memory_state: CanonicalInMemoryState,
2992             factory: ProviderFactory<MockNodeTypesWithDB>| {
2993                assert!(factory.transaction_by_hash(hash)?.is_none(), "should not be in database");
2994                Ok::<_, ProviderError>(canonical_in_memory_state.transaction_by_hash(hash))
2995            };
2996
2997        // Correct implementation queries in-memory first
2998        let correct_transaction_hash_fn =
2999            |hash: B256,
3000             canonical_in_memory_state: CanonicalInMemoryState,
3001             _factory: ProviderFactory<MockNodeTypesWithDB>| {
3002                if let Some(tx) = canonical_in_memory_state.transaction_by_hash(hash) {
3003                    return Ok::<_, ProviderError>(Some(tx));
3004                }
3005                panic!("should not be in database");
3006                // _factory.transaction_by_hash(hash)
3007            };
3008
3009        // OLD BEHAVIOUR
3010        {
3011            // This will persist block 1 AFTER a database is created. Moving it from memory to
3012            // storage.
3013            persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[0].number);
3014            let to_be_persisted_tx = in_memory_blocks[0].body().transactions[0].clone();
3015
3016            // Even though the block exists, given the order of provider queries done in the method
3017            // above, we do not see it.
3018            assert!(matches!(
3019                old_transaction_hash_fn(
3020                    *to_be_persisted_tx.tx_hash(),
3021                    provider.canonical_in_memory_state(),
3022                    provider.database.clone()
3023                ),
3024                Ok(None)
3025            ));
3026        }
3027
3028        // CORRECT BEHAVIOUR
3029        {
3030            // This will persist block 1 AFTER a database is created. Moving it from memory to
3031            // storage.
3032            persist_block_after_db_tx_creation(provider.clone(), in_memory_blocks[1].number);
3033            let to_be_persisted_tx = in_memory_blocks[1].body().transactions[0].clone();
3034
3035            assert_eq!(
3036                correct_transaction_hash_fn(
3037                    *to_be_persisted_tx.tx_hash(),
3038                    provider.canonical_in_memory_state(),
3039                    provider.database
3040                )
3041                .unwrap(),
3042                Some(to_be_persisted_tx)
3043            );
3044        }
3045
3046        Ok(())
3047    }
3048
3049    fn random_account(nonce: u64) -> (Address, Account) {
3050        (Address::random(), Account { nonce, balance: U256::from(nonce), ..Default::default() })
3051    }
3052
3053    /// [`BlockchainProvider::new`] needs a genesis header to initialize its chain tracker.
3054    fn test_provider_factory_with_genesis() -> eyre::Result<ProviderFactory<MockNodeTypesWithDB>> {
3055        let factory = create_test_provider_factory();
3056        let provider_rw = factory.provider_rw()?;
3057        let mut rng = generators::rng();
3058        let genesis =
3059            random_block(&mut rng, 0, BlockParams { tx_count: Some(0), ..Default::default() });
3060        provider_rw
3061            .insert_block(&genesis.try_recover().expect("failed to seal block with senders"))?;
3062        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(0))?;
3063        provider_rw.commit()?;
3064        Ok(factory)
3065    }
3066
3067    #[test]
3068    fn state_range_provider_account_range_is_sorted_and_bounded() -> eyre::Result<()> {
3069        let factory = test_provider_factory_with_genesis()?;
3070        let provider_rw = factory.provider_rw()?;
3071
3072        let accounts: Vec<_> = (0..5u64).map(random_account).collect();
3073        provider_rw.insert_account_for_hashing(
3074            accounts.iter().map(|(address, account)| (*address, Some(account.clone()))),
3075        )?;
3076        provider_rw.commit()?;
3077
3078        let provider = BlockchainProvider::new(factory)?;
3079
3080        let mut expected: Vec<_> = accounts
3081            .iter()
3082            .map(|(address, account)| (keccak256(address), account.clone()))
3083            .collect();
3084        expected.sort_by_key(|(hash, _)| *hash);
3085        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3086
3087        let all = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3088        assert_eq!(all.end, RangeEnd::Exhausted);
3089        assert_eq!(all.items, expected);
3090
3091        // The limit exactly matches the second account's hash, so the range ends there rather
3092        // than by exhausting the trie.
3093        let bounded = state.account_range(B256::ZERO, expected[1].0, 10_000)?;
3094        assert_eq!(bounded.end, RangeEnd::HashLimit);
3095        assert_eq!(bounded.items, expected[..2]);
3096
3097        Ok(())
3098    }
3099
3100    #[test]
3101    fn state_range_provider_account_range_respects_response_bytes() -> eyre::Result<()> {
3102        let factory = test_provider_factory_with_genesis()?;
3103        let provider_rw = factory.provider_rw()?;
3104
3105        let accounts: Vec<_> = (0..5u64).map(random_account).collect();
3106        provider_rw.insert_account_for_hashing(
3107            accounts.iter().map(|(address, account)| (*address, Some(account.clone()))),
3108        )?;
3109        provider_rw.commit()?;
3110
3111        let provider = BlockchainProvider::new(factory)?;
3112        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3113
3114        // Budget only fits a single account.
3115        let partial = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 150)?;
3116        assert_eq!(partial.end, RangeEnd::ByteLimit);
3117        assert_eq!(partial.items.len(), 1);
3118
3119        Ok(())
3120    }
3121
3122    #[test]
3123    fn state_range_provider_storage_range_and_root() -> eyre::Result<()> {
3124        let factory = test_provider_factory_with_genesis()?;
3125        let provider_rw = factory.provider_rw()?;
3126
3127        let (address, account) = random_account(1);
3128        let hashed_address = keccak256(address);
3129        provider_rw.insert_account_for_hashing([(address, Some(account))])?;
3130        let slots = [
3131            StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) },
3132            StorageEntry { key: B256::with_last_byte(2), value: U256::from(20) },
3133        ];
3134        provider_rw.insert_storage_for_hashing([(address, slots)])?;
3135        provider_rw.commit()?;
3136
3137        let provider = BlockchainProvider::new(factory)?;
3138        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3139
3140        let expected_root = provider.latest()?.storage_root(address, HashedStorage::default())?;
3141        assert_eq!(state.storage_root_by_hash(hashed_address)?, expected_root);
3142
3143        let returned = state
3144            .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3145            .unwrap();
3146        assert_eq!(returned.end, RangeEnd::Exhausted);
3147        let mut expected: Vec<_> =
3148            slots.iter().map(|entry| (keccak256(entry.key), entry.value)).collect();
3149        expected.sort_by_key(|(hash, _)| *hash);
3150        assert_eq!(returned.items, expected);
3151
3152        // `start == limit == ZERO` means the first real slot's hash already reaches the limit.
3153        let empty_window =
3154            state.storage_range(hashed_address, B256::ZERO, B256::ZERO, 10_000)?.unwrap();
3155        assert_eq!(empty_window.end, RangeEnd::HashLimit);
3156        assert_eq!(empty_window.items, expected[..1]);
3157
3158        // An account absent from the trie is distinguished from one with no storage.
3159        assert!(state
3160            .storage_range(B256::repeat_byte(0xee), B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3161            .is_none());
3162
3163        Ok(())
3164    }
3165
3166    #[test]
3167    fn state_range_provider_proofs_start_at_the_real_root() -> eyre::Result<()> {
3168        let factory = test_provider_factory_with_genesis()?;
3169        let provider_rw = factory.provider_rw()?;
3170
3171        let (address, account) = random_account(1);
3172        let hashed_address = keccak256(address);
3173        let hashed_slot = keccak256(B256::with_last_byte(1));
3174        provider_rw.insert_account_for_hashing([(address, Some(account))])?;
3175        provider_rw.insert_storage_for_hashing([(
3176            address,
3177            [StorageEntry { key: B256::with_last_byte(1), value: U256::from(10) }],
3178        )])?;
3179        provider_rw.commit()?;
3180
3181        let provider = BlockchainProvider::new(factory)?;
3182
3183        // The first node of a sorted boundary proof is always the trie root, so this checks the
3184        // proof was generated against the real, current root rather than a stale or empty one.
3185        let state_root = provider.latest()?.state_root(HashedPostState::default())?;
3186        let state = provider.state_range_provider(EMPTY_ROOT_HASH)?.unwrap();
3187        let account_proof = state.account_range_proof(&[hashed_address])?;
3188        assert!(!account_proof.is_empty());
3189        assert_eq!(keccak256(&account_proof[0]), state_root);
3190
3191        let storage_root = state.storage_root_by_hash(hashed_address)?;
3192        let storage_proof = state.storage_range_proof(hashed_address, &[hashed_slot])?;
3193        assert!(!storage_proof.is_empty());
3194        assert_eq!(keccak256(&storage_proof[0]), storage_root);
3195
3196        Ok(())
3197    }
3198
3199    #[test]
3200    fn state_range_provider_serves_recent_root_and_rejects_expired_root() -> eyre::Result<()> {
3201        let mut rng = generators::rng();
3202        let factory = create_test_provider_factory();
3203        let provider_rw = factory.provider_rw()?;
3204        let expired_root = B256::repeat_byte(0x11);
3205        let recent_root = B256::repeat_byte(0x22);
3206        let mut parent = B256::ZERO;
3207
3208        for number in 0..=SNAPSHOT_STATE_RETENTION {
3209            let mut block = random_block(
3210                &mut rng,
3211                number,
3212                BlockParams { parent: Some(parent), tx_count: Some(0), ..Default::default() },
3213            )
3214            .unseal();
3215            block.header.state_root = match number {
3216                0 => expired_root,
3217                64 => recent_root,
3218                _ => EMPTY_ROOT_HASH,
3219            };
3220            let block = block.seal_slow();
3221            parent = block.hash();
3222            provider_rw
3223                .insert_block(&block.try_recover().expect("failed to seal block with senders"))?;
3224        }
3225        provider_rw.save_stage_checkpoint(
3226            StageId::Finish,
3227            StageCheckpoint::new(SNAPSHOT_STATE_RETENTION),
3228        )?;
3229        provider_rw.commit()?;
3230
3231        let provider = BlockchainProvider::new(factory)?;
3232        assert!(provider.state_range_provider(recent_root)?.is_some());
3233        assert!(provider.state_range_provider(expired_root)?.is_none());
3234
3235        Ok(())
3236    }
3237
3238    #[test]
3239    fn state_range_provider_serves_persisted_root_with_in_memory_overlay() -> eyre::Result<()> {
3240        let mut rng = generators::rng();
3241
3242        // State A: one account, persisted at block 1. Block 1 is not the database head, so only
3243        // the persisted-history fallback can resolve its root.
3244        let (address, account_a) = random_account(1);
3245        let hashed_address = keccak256(address);
3246        let factory = test_provider_factory_with_genesis()?;
3247        let provider_rw = factory.provider_rw()?;
3248        provider_rw.insert_account_for_hashing([(address, Some(account_a.clone()))])?;
3249        provider_rw.commit()?;
3250        let persisted_root = factory.latest()?.state_root(HashedPostState::default())?;
3251
3252        let genesis_hash = factory.sealed_header(0)?.unwrap().hash();
3253        let mut persisted_block = random_block(
3254            &mut rng,
3255            1,
3256            BlockParams { parent: Some(genesis_hash), tx_count: Some(0), ..Default::default() },
3257        )
3258        .unseal();
3259        persisted_block.header.state_root = persisted_root;
3260        let persisted_block =
3261            persisted_block.seal_slow().try_recover().expect("failed to seal block with senders");
3262        let persisted_hash = persisted_block.hash();
3263
3264        let provider_rw = factory.provider_rw()?;
3265        provider_rw.insert_block(&persisted_block)?;
3266        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(1))?;
3267        provider_rw.commit()?;
3268
3269        // State B: block 2 changes the account and becomes the database head, with a root
3270        // different from block 1's.
3271        let account_b = Account { nonce: 2, balance: U256::from(2), ..account_a.clone() };
3272        let mut state_b = HashedPostState::default();
3273        state_b.accounts.insert(hashed_address, Some(account_b.clone()));
3274        let head_root = factory.latest()?.state_root(state_b.clone())?;
3275        assert_ne!(head_root, persisted_root);
3276
3277        let mut head_block = random_block(
3278            &mut rng,
3279            2,
3280            BlockParams { parent: Some(persisted_hash), tx_count: Some(0), ..Default::default() },
3281        )
3282        .unseal();
3283        head_block.header.state_root = head_root;
3284        let head_block =
3285            head_block.seal_slow().try_recover().expect("failed to seal block with senders");
3286        let head_hash = head_block.hash();
3287
3288        let provider_rw = factory.provider_rw()?;
3289        provider_rw.append_blocks_with_state(
3290            vec![head_block],
3291            &ExecutionOutcome {
3292                bundle: BundleState::new(
3293                    [(
3294                        address,
3295                        Some(account_a.clone().into()),
3296                        Some(account_b.into()),
3297                        Default::default(),
3298                    )],
3299                    [[(address, Some(Some(account_a.clone().into())), [])]],
3300                    [],
3301                ),
3302                first_block: 2,
3303                ..Default::default()
3304            },
3305            state_b.into_sorted(),
3306        )?;
3307        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(2))?;
3308        provider_rw.commit()?;
3309
3310        let provider = BlockchainProvider::new(factory)?;
3311
3312        // An in-memory block on top of the head adds another account under a root of its own.
3313        let (memory_address, memory_account) = random_account(3);
3314        let mut memory_state = HashedPostState::default();
3315        memory_state.accounts.insert(keccak256(memory_address), Some(memory_account));
3316
3317        let memory_root = B256::repeat_byte(0x77);
3318        assert_ne!(memory_root, persisted_root);
3319        let mut memory_block = random_block(
3320            &mut rng,
3321            3,
3322            BlockParams { parent: Some(head_hash), tx_count: Some(0), ..Default::default() },
3323        )
3324        .unseal();
3325        memory_block.header.state_root = memory_root;
3326        let memory_block =
3327            memory_block.seal_slow().try_recover().expect("failed to seal block with senders");
3328        let trie_data = SortedTrieData::new(
3329            Arc::new(memory_state.into_sorted()),
3330            Arc::new(TrieUpdates::default().into_sorted()),
3331        );
3332        let execution_output = BlockExecutionOutput {
3333            result: BlockExecutionResult {
3334                receipts: Default::default(),
3335                requests: Default::default(),
3336                gas_used: 0,
3337                blob_gas_used: 0,
3338            },
3339            state: Default::default(),
3340        };
3341        let executed =
3342            ExecutedBlock::new(Arc::new(memory_block), Arc::new(execution_output), trie_data);
3343        provider.database.overlay_manager().insert_block(executed.clone());
3344        provider
3345            .canonical_in_memory_state
3346            .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3347
3348        // No in-memory block carries the persisted root, so the persisted-history fallback must
3349        // resolve it, ignoring both the later database block and the in-memory block above it.
3350        assert!(!provider
3351            .canonical_in_memory_state
3352            .canonical_chain()
3353            .any(|state| state.state_root() == persisted_root));
3354        let state =
3355            provider.state_range_provider(persisted_root)?.expect("persisted root must resolve");
3356        let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3357        assert_eq!(range.items, vec![(hashed_address, account_a)]);
3358
3359        // The first node of a boundary proof is the trie root, so this is the root the view
3360        // reports.
3361        let proof = state.account_range_proof(&[hashed_address])?;
3362        assert!(!proof.is_empty());
3363        assert_eq!(keccak256(&proof[0]), persisted_root);
3364
3365        Ok(())
3366    }
3367
3368    #[test]
3369    fn latest_reads_in_memory_state_like_the_hash_lookup() -> eyre::Result<()> {
3370        use crate::{AccountReader, StateProvider, StateProviderBox};
3371        use reth_storage_api::DatabaseProviderROFactory;
3372        use reth_storage_overlay::OverlayStateProviderFactory;
3373
3374        let mut rng = generators::rng();
3375        let factory = test_provider_factory_with_genesis()?;
3376        let provider = BlockchainProvider::new(factory)?;
3377        let genesis = provider.canonical_in_memory_state.get_canonical_head();
3378
3379        let (address, account) = random_account(1);
3380        let hashed_address = keccak256(address);
3381        let slot_key = B256::with_last_byte(1);
3382        let slot = U256::from_be_bytes(slot_key.0);
3383        let value = U256::from(42);
3384
3385        let mut hashed_state = HashedPostState::default();
3386        hashed_state.accounts.insert(hashed_address, Some(account.clone()));
3387        hashed_state
3388            .storages
3389            .insert(hashed_address, HashedStorage::from_iter([(keccak256(slot_key), value)]));
3390
3391        let mut storage = HashMap::default();
3392        storage.insert(slot, (U256::ZERO, value));
3393
3394        let block = random_block(
3395            &mut rng,
3396            genesis.number + 1,
3397            BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3398        )
3399        .try_recover()
3400        .expect("failed to seal block with senders");
3401        let block_hash = block.hash();
3402
3403        let execution_output = BlockExecutionOutput {
3404            result: BlockExecutionResult {
3405                receipts: Default::default(),
3406                requests: Default::default(),
3407                gas_used: 0,
3408                blob_gas_used: 0,
3409            },
3410            state: BundleState::new(
3411                [(address, None, Some(account.clone().into()), storage)],
3412                [[(address, Some(None), [])]],
3413                [],
3414            ),
3415        };
3416        let executed = ExecutedBlock::new(
3417            Arc::new(block),
3418            Arc::new(execution_output),
3419            SortedTrieData::new(
3420                Arc::new(hashed_state.into_sorted()),
3421                Arc::new(TrieUpdates::default().into_sorted()),
3422            ),
3423        );
3424        provider.database.overlay_manager().insert_block(executed.clone());
3425        provider
3426            .canonical_in_memory_state
3427            .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3428
3429        // `latest` reuses the canonical `Arc<BlockState>` chain, while the hash-based lookup
3430        // rebuilds an equivalent chain from the overlay manager's block graph. Both must observe
3431        // the same in-memory account and storage values.
3432        let rebuilt_from_hash = OverlayStateProviderFactory::new(
3433            provider.database.clone(),
3434            provider.database.overlay_manager().overlay_builder(block_hash),
3435        )
3436        .database_provider_ro()?;
3437
3438        for state in [
3439            Box::new(rebuilt_from_hash) as StateProviderBox,
3440            provider.latest()?,
3441            provider.state_by_block_hash(block_hash)?,
3442        ] {
3443            assert_eq!(state.basic_account(&address)?, Some(account.clone()));
3444            assert_eq!(state.storage(address, slot_key)?, Some(value));
3445        }
3446
3447        Ok(())
3448    }
3449
3450    #[test]
3451    fn state_range_provider_reverts_database_advancement_past_anchor() -> eyre::Result<()> {
3452        let mut rng = generators::rng();
3453        let factory = test_provider_factory_with_genesis()?;
3454        let provider = BlockchainProvider::new(factory)?;
3455        let genesis = provider.canonical_in_memory_state.get_canonical_head();
3456
3457        // In-memory target block anchored on genesis, with a known account.
3458        let (target_address, target_account) = random_account(1);
3459        let target_hashed = keccak256(target_address);
3460        let mut target_state = HashedPostState::default();
3461        target_state.accounts.insert(target_hashed, Some(target_account.clone()));
3462
3463        let unique_root = B256::repeat_byte(0x77);
3464        let mut block = random_block(
3465            &mut rng,
3466            genesis.number + 1,
3467            BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3468        )
3469        .unseal();
3470        block.header.state_root = unique_root;
3471        let block = block.seal_slow().try_recover().expect("failed to seal block with senders");
3472        let trie_data = SortedTrieData::new(
3473            Arc::new(target_state.into_sorted()),
3474            Arc::new(TrieUpdates::default().into_sorted()),
3475        );
3476        let execution_output = BlockExecutionOutput {
3477            result: BlockExecutionResult {
3478                receipts: Default::default(),
3479                requests: Default::default(),
3480                gas_used: 0,
3481                blob_gas_used: 0,
3482            },
3483            state: Default::default(),
3484        };
3485        let executed = ExecutedBlock::new(Arc::new(block), Arc::new(execution_output), trie_data);
3486        provider.database.overlay_manager().insert_block(executed.clone());
3487        provider
3488            .canonical_in_memory_state
3489            .update_chain(NewCanonicalChain::Commit { new: vec![executed] });
3490
3491        // Persistence races ahead: a *different* block, with a *different* account, lands in
3492        // the database on top of the same genesis anchor while the in-memory chain above still
3493        // references genesis as its anchor.
3494        let (noise_address, noise_account) = random_account(2);
3495        let noise_block = random_block(
3496            &mut rng,
3497            genesis.number + 1,
3498            BlockParams { parent: Some(genesis.hash()), tx_count: Some(0), ..Default::default() },
3499        )
3500        .try_recover()
3501        .expect("failed to seal block with senders");
3502        let mut noise_state = HashedPostState::default();
3503        noise_state.accounts.insert(keccak256(noise_address), Some(noise_account.clone()));
3504        let provider_rw = provider.database.provider_rw()?;
3505        provider_rw.append_blocks_with_state(
3506            vec![noise_block],
3507            &ExecutionOutcome {
3508                bundle: BundleState::new(
3509                    [(noise_address, None, Some(noise_account.into()), Default::default())],
3510                    [[(noise_address, Some(None), [])]],
3511                    [],
3512                ),
3513                first_block: genesis.number + 1,
3514                ..Default::default()
3515            },
3516            noise_state.into_sorted(),
3517        )?;
3518        provider_rw
3519            .save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(genesis.number + 1))?;
3520        provider_rw.commit()?;
3521
3522        // Resolving the in-memory root must revert the database's advancement back to genesis,
3523        // so the noise account must not leak into the result.
3524        let state =
3525            provider.state_range_provider(unique_root)?.expect("in-memory root must resolve");
3526        let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3527        assert_eq!(range.items, vec![(target_hashed, target_account)]);
3528
3529        Ok(())
3530    }
3531
3532    #[test]
3533    fn historical_state_range_provider_reverts_state_change_past_retained_anchor(
3534    ) -> eyre::Result<()> {
3535        let mut rng = generators::rng();
3536
3537        // State A: the account and its one storage slot as of the retained anchor.
3538        let (address, account_a) = random_account(1);
3539        let hashed_address = keccak256(address);
3540        let slot_key = B256::with_last_byte(1);
3541        let slot = U256::from_be_bytes(slot_key.0);
3542        let hashed_slot = keccak256(slot_key);
3543        let value_a = U256::ONE;
3544
3545        let factory = test_provider_factory_with_genesis()?;
3546        let provider_rw = factory.provider_rw()?;
3547        provider_rw.insert_account_for_hashing([(address, Some(account_a.clone()))])?;
3548        provider_rw.insert_storage_for_hashing([(
3549            address,
3550            [StorageEntry { key: slot_key, value: value_a }],
3551        )])?;
3552        provider_rw.commit()?;
3553        let anchor_root = factory.latest()?.state_root(HashedPostState::default())?;
3554
3555        let genesis_hash = factory.sealed_header(0)?.unwrap().hash();
3556        let mut anchor_block = random_block(
3557            &mut rng,
3558            1,
3559            BlockParams { parent: Some(genesis_hash), tx_count: Some(0), ..Default::default() },
3560        )
3561        .unseal();
3562        anchor_block.header.state_root = anchor_root;
3563        let anchor_block =
3564            anchor_block.seal_slow().try_recover().expect("failed to seal block with senders");
3565        let anchor_hash = anchor_block.hash();
3566
3567        let provider_rw = factory.provider_rw()?;
3568        provider_rw.insert_block(&anchor_block)?;
3569        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(1))?;
3570        provider_rw.commit()?;
3571
3572        // State B: a later block changes both the account and its storage slot.
3573        let account_b = Account { nonce: 2, balance: U256::from(2), ..account_a.clone() };
3574        let value_b = U256::from(2);
3575
3576        let mut storage = HashMap::default();
3577        storage.insert(slot, (value_a, value_b));
3578
3579        let mut state_b = HashedPostState::default();
3580        state_b.accounts.insert(hashed_address, Some(account_b.clone()));
3581        state_b.storages.insert(hashed_address, HashedStorage::from_iter([(hashed_slot, value_b)]));
3582
3583        let state_b_root = factory.latest()?.state_root(state_b.clone())?;
3584        let mut later_block = random_block(
3585            &mut rng,
3586            2,
3587            BlockParams { parent: Some(anchor_hash), tx_count: Some(0), ..Default::default() },
3588        )
3589        .unseal();
3590        later_block.header.state_root = state_b_root;
3591        let later_block =
3592            later_block.seal_slow().try_recover().expect("failed to seal block with senders");
3593
3594        let provider_rw = factory.provider_rw()?;
3595        provider_rw.append_blocks_with_state(
3596            vec![later_block],
3597            &ExecutionOutcome {
3598                bundle: BundleState::new(
3599                    [(address, Some(account_a.clone().into()), Some(account_b.into()), storage)],
3600                    [[(address, Some(Some(account_a.clone().into())), [(slot, value_a)])]],
3601                    [],
3602                ),
3603                first_block: 2,
3604                ..Default::default()
3605            },
3606            state_b.into_sorted(),
3607        )?;
3608        provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(2))?;
3609        provider_rw.commit()?;
3610
3611        // Resolving the anchor root must revert the later account and storage changes; state B
3612        // must not leak into the response.
3613        let provider = BlockchainProvider::new(factory)?;
3614        let state =
3615            provider.state_range_provider(anchor_root)?.expect("retained root must resolve");
3616        let range = state.account_range(B256::ZERO, B256::repeat_byte(0xff), 10_000)?;
3617        assert_eq!(range.items, vec![(hashed_address, account_a)]);
3618
3619        let storage_range = state
3620            .storage_range(hashed_address, B256::ZERO, B256::repeat_byte(0xff), 10_000)?
3621            .expect("account must have storage");
3622        assert_eq!(storage_range.items, vec![(hashed_slot, value_a)]);
3623
3624        Ok(())
3625    }
3626
3627    #[test]
3628    fn get_state_preserves_empty_block_receipts() -> eyre::Result<()> {
3629        let mut rng = generators::rng();
3630        let factory = create_test_provider_factory();
3631        let writer = factory.provider_rw()?;
3632        let mut parent = B256::ZERO;
3633        let mut expected = Vec::new();
3634        // Persist empty blocks before receipt zero, between transactions and at the tip.
3635        for (number, tx_count) in [0, 0, 1, 0, 1, 0].into_iter().enumerate() {
3636            let block = random_block(
3637                &mut rng,
3638                number as u64,
3639                BlockParams {
3640                    parent: Some(parent),
3641                    tx_count: Some(tx_count),
3642                    ..Default::default()
3643                },
3644            )
3645            .try_recover()
3646            .expect("failed to recover test block");
3647            parent = block.hash();
3648            expected.push(
3649                block
3650                    .body()
3651                    .transactions
3652                    .iter()
3653                    .map(|tx| random_receipt(&mut rng, tx, Some(0), Some(0)))
3654                    .collect::<Vec<_>>(),
3655            );
3656            writer.insert_block(&block)?;
3657        }
3658        writer.write_state(
3659            &ExecutionOutcome { first_block: 0, receipts: expected.clone(), ..Default::default() },
3660            OriginalValuesKnown::No,
3661            StateWriteConfig::default(),
3662        )?;
3663        writer.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(5))?;
3664        writer.commit()?;
3665
3666        let provider = BlockchainProvider::new(factory)?;
3667        assert!(provider.canonical_in_memory_state.head_state().is_none());
3668        assert!(provider.receipt(0)?.is_some());
3669        for (number, receipts) in expected.into_iter().enumerate() {
3670            let outcome = provider.get_state(number as u64)?.expect("persisted block state");
3671            assert_eq!(outcome.receipts, vec![receipts], "block {number}");
3672        }
3673        Ok(())
3674    }
3675}