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