Skip to main content

reth_storage_overlay/
provider.rs

1use crate::{
2    database_state_frontiers, multiproof_calculator::OverlayMultiProofCalculator, ExecutionOverlay,
3    OverlayBuilder, StateTrieOverlay,
4};
5use alloy_primitives::{map::B256Map, Address, BlockHash, BlockNumber, B256, U256};
6use metrics::{Counter, Histogram};
7use reth_db_api::{cursor::DbDupCursorRO, tables, transaction::DbTx, DatabaseError};
8use reth_errors::{ProviderError, ProviderResult};
9use reth_ethereum_primitives::EthPrimitives;
10use reth_metrics::Metrics;
11use reth_primitives_traits::{
12    dashmap::{self, DashMap},
13    Account, NodePrimitives,
14};
15use reth_prune_types::PruneSegment;
16use reth_storage_api::{
17    AccountReader, BlockHashReader, BlockNumReader, BytecodeReader, ChangeSetReader, DBProvider,
18    DatabaseProviderFactory, DatabaseProviderROFactory, DbTxProvider, HashedPostStateProvider,
19    HistoryInfo, HistoryReader, PruneCheckpointReader, StageCheckpointReader, StateProofProvider,
20    StateProvider, StateRootProvider, StorageChangeSetReader, StorageRootProvider,
21    StorageSettingsCache,
22};
23use reth_trie::{
24    hashed_cursor::{
25        zero_destroyed_account_storage, HashedCursorFactory, HashedPostStateCursorFactory,
26    },
27    proof::{Proof, StorageProof as TrieStorageProof},
28    proof_v2::ProofCursorMetrics,
29    trie_cursor::{
30        InMemoryTrieCursor, InMemoryTrieCursorFactory, TrieCursor, TrieCursorFactory,
31        TrieStorageCursor,
32    },
33    updates::TrieUpdates,
34    witness::TrieWitness,
35    AccountProof, DecodedMultiProofV2, ExecutionWitnessMode, HashedPostState,
36    HashedPostStateSorted, HashedStorage, KeccakKeyHasher, MultiProof, MultiProofTargets,
37    MultiProofTargetsV2, StateRoot, StorageMultiProof, StorageProof, StorageRoot, TrieInput,
38    TrieInputSorted,
39};
40use reth_trie_db::{
41    DatabaseAccountTrieCursor, DatabaseHashedCursorFactory, DatabaseProof, DatabaseStateRoot,
42    DatabaseStorageProof, DatabaseStorageRoot, DatabaseStorageTrieCursor,
43    DatabaseTrieCursorFactory, LegacyKeyAdapter, PackedAccountsTrie, PackedKeyAdapter,
44    PackedStoragesTrie,
45};
46use std::{
47    cell::{OnceCell, RefCell},
48    fmt,
49    marker::PhantomPinned,
50    ops::Deref,
51    pin::Pin,
52    sync::Arc,
53    time::Instant,
54};
55use tracing::instrument;
56
57/// Factory for creating overlay state providers with optional reverts and overlays.
58///
59/// This factory allows building an `OverlayStateProvider` whose DB state has been reverted to a
60/// particular block, and/or with additional overlay information added on top.
61#[derive(Debug, Clone)]
62pub struct OverlayStateProviderFactory<F, N: NodePrimitives = EthPrimitives> {
63    /// The underlying database provider factory
64    factory: F,
65    /// Overlay builder containing the configuration and overlay calculation logic.
66    overlay_builder: OverlayBuilder<N>,
67    /// A cache mapping `(state_trie_tip, finish_tip, trie_changesets)` to [`StateTrieOverlay`].
68    ///
69    /// Under partial persistence the overlay depends on both durable frontiers, so both hashes are
70    /// part of the cache key.
71    state_trie_overlay_cache: StateTrieOverlayCache,
72    /// Metrics for provider factory operations.
73    metrics: OverlayStateProviderFactoryMetrics,
74    /// Cursor metric handles shared by the multiproof calculators of every provider.
75    proof_cursor_metrics: ProofCursorMetrics,
76    /// Revealed storage roots from the reused sparse trie, shared across proof workers.
77    known_storage_roots: Arc<B256Map<B256>>,
78}
79
80impl<F, N: NodePrimitives> OverlayStateProviderFactory<F, N> {
81    /// Create a new overlay state provider factory.
82    pub fn new(factory: F, overlay_builder: OverlayBuilder<N>) -> Self {
83        Self {
84            factory,
85            overlay_builder,
86            state_trie_overlay_cache: Default::default(),
87            metrics: Default::default(),
88            proof_cursor_metrics: Default::default(),
89            known_storage_roots: Default::default(),
90        }
91    }
92
93    /// Skips managed overlay construction when this factory is used by a task that reused a sparse
94    /// trie covering both durable frontiers through the parent.
95    ///
96    /// Trie and hashed cursors then read durable database state only. V2 account proofs use the
97    /// supplied storage roots, which is valid solely for revealing nodes into that reused sparse
98    /// trie. Methods that layer the overlay into their input, such as state
99    /// and storage roots, account and storage proofs, V1 multiproofs, witnesses and
100    /// [`HashedPostStateProvider::hashed_post_state`], return
101    /// [`ProviderError::UnsupportedProvider`].
102    ///
103    /// `known_storage_roots` must contain the revealed storage roots at this factory's parent,
104    /// keyed by hashed account address. Account proofs reuse them to avoid root calculation.
105    pub fn with_skip_overlay_for_reused_sparse_trie(
106        mut self,
107        anchor_hash: B256,
108        known_storage_roots: B256Map<B256>,
109    ) -> Self {
110        self.overlay_builder =
111            self.overlay_builder.with_skip_overlay_for_reused_sparse_trie(anchor_hash);
112        self.state_trie_overlay_cache = Default::default();
113        self.known_storage_roots = Arc::new(known_storage_roots);
114        self
115    }
116}
117
118impl<F, N> DatabaseProviderROFactory for OverlayStateProviderFactory<F, N>
119where
120    N: NodePrimitives,
121    F: DatabaseProviderFactory,
122    F::Provider: StageCheckpointReader
123        + PruneCheckpointReader
124        + BlockNumReader
125        + ChangeSetReader
126        + StorageChangeSetReader
127        + StorageSettingsCache,
128{
129    type Provider = OverlayStateProvider<OwnedProvider<F::Provider>, N>;
130
131    /// Create a read-only [`OverlayStateProvider`].
132    #[instrument(level = "debug", target = "providers::state::overlay", skip_all)]
133    fn database_provider_ro(
134        &self,
135    ) -> ProviderResult<OverlayStateProvider<OwnedProvider<F::Provider>, N>> {
136        let overall_start = Instant::now();
137
138        // Get a read-only provider
139        let provider = {
140            let start = Instant::now();
141            let res = self.factory.database_provider_ro()?;
142            self.metrics.create_provider_duration.record(start.elapsed());
143            res
144        };
145
146        let is_v2 = provider.cached_storage_settings().is_v2();
147        self.metrics.database_provider_ro_duration.record(overall_start.elapsed());
148        Ok(OverlayStateProvider::from_parts(
149            OwnedProvider(provider),
150            Some(self.overlay_builder.clone()),
151            Arc::clone(&self.state_trie_overlay_cache),
152            self.metrics.clone(),
153            self.proof_cursor_metrics.clone(),
154            self.known_storage_roots.clone(),
155            is_v2,
156        ))
157    }
158}
159
160/// State provider with lazily resolved state trie and execution overlays.
161pub struct OverlayStateProvider<Provider, N: NodePrimitives = EthPrimitives>
162where
163    Provider: Deref,
164    Provider::Target: DBProvider,
165{
166    /// Multiproof calculator reused across requests with the same `requires_masks` flag.
167    ///
168    /// It borrows `provider`'s transaction and the state trie overlays, so `Drop` releases it
169    /// first.
170    multiproof_calculator:
171        RefCell<Option<CachedMultiProofCalculator<<Provider::Target as DbTxProvider>::Tx>>>,
172    /// The `!Unpin` pointee preserves cached transaction borrows when the owning box moves.
173    provider: Pin<Box<(Provider, PhantomPinned)>>,
174    overlay_builder: Option<OverlayBuilder<N>>,
175    state_trie_overlay_cache: StateTrieOverlayCache,
176    metrics: OverlayStateProviderFactoryMetrics,
177    proof_cursor_metrics: ProofCursorMetrics,
178    /// Revealed storage roots from the reused sparse trie, shared across proof workers.
179    known_storage_roots: Arc<B256Map<B256>>,
180    state_trie_overlay: OnceCell<StateTrieOverlay>,
181    state_trie_overlay_with_trie_changesets: OnceCell<StateTrieOverlay>,
182    execution_overlay: OnceCell<CachedExecutionOverlay>,
183    is_v2: bool,
184}
185
186impl<Provider: DBProvider, N: NodePrimitives> OverlayStateProvider<OwnedProvider<Provider>, N> {
187    /// Creates an overlay state provider over an already-open database provider.
188    pub fn new(provider: Provider, overlay_builder: OverlayBuilder<N>) -> Self
189    where
190        Provider: StorageSettingsCache,
191    {
192        let is_v2 = provider.cached_storage_settings().is_v2();
193        Self::from_parts(
194            OwnedProvider(provider),
195            Some(overlay_builder),
196            Default::default(),
197            Default::default(),
198            Default::default(),
199            Default::default(),
200            is_v2,
201        )
202    }
203
204    #[cfg(test)]
205    fn new_with_execution(
206        provider: Provider,
207        execution_overlay: Arc<ExecutionOverlay>,
208        is_v2: bool,
209    ) -> Self {
210        let mut provider = Self::from_parts(
211            OwnedProvider(provider),
212            None,
213            Default::default(),
214            Default::default(),
215            Default::default(),
216            Default::default(),
217            is_v2,
218        );
219        provider.execution_overlay = OnceCell::from(CachedExecutionOverlay {
220            overlay: execution_overlay,
221            historical_fallback: None,
222        });
223        provider
224    }
225}
226
227impl<'a, Provider: DBProvider, N: NodePrimitives> OverlayStateProvider<&'a Provider, N> {
228    /// Creates an overlay state provider over a borrowed database provider.
229    pub fn new_ref(provider: &'a Provider, overlay_builder: OverlayBuilder<N>) -> Self
230    where
231        Provider: StorageSettingsCache,
232    {
233        let is_v2 = provider.cached_storage_settings().is_v2();
234        Self::from_parts(
235            provider,
236            Some(overlay_builder),
237            Default::default(),
238            Default::default(),
239            Default::default(),
240            Default::default(),
241            is_v2,
242        )
243    }
244
245    pub(crate) fn new_with_state_trie(
246        provider: &'a Provider,
247        state_trie_overlay: StateTrieOverlay,
248        is_v2: bool,
249    ) -> Self {
250        let mut provider = Self::from_parts(
251            provider,
252            None,
253            Default::default(),
254            Default::default(),
255            Default::default(),
256            Default::default(),
257            is_v2,
258        );
259        provider.state_trie_overlay = OnceCell::from(state_trie_overlay.clone());
260        provider.state_trie_overlay_with_trie_changesets = OnceCell::from(state_trie_overlay);
261        provider
262    }
263}
264
265impl<Provider, N: NodePrimitives> OverlayStateProvider<Provider, N>
266where
267    Provider: Deref,
268    Provider::Target: DBProvider,
269{
270    /// Creates a provider whose overlays resolve lazily and that has no cached multiproof
271    /// calculator.
272    fn from_parts(
273        provider: Provider,
274        overlay_builder: Option<OverlayBuilder<N>>,
275        state_trie_overlay_cache: StateTrieOverlayCache,
276        metrics: OverlayStateProviderFactoryMetrics,
277        proof_cursor_metrics: ProofCursorMetrics,
278        known_storage_roots: Arc<B256Map<B256>>,
279        is_v2: bool,
280    ) -> Self {
281        Self {
282            multiproof_calculator: RefCell::new(None),
283            provider: Box::pin((provider, PhantomPinned)),
284            overlay_builder,
285            state_trie_overlay_cache,
286            metrics,
287            proof_cursor_metrics,
288            known_storage_roots,
289            state_trie_overlay: OnceCell::new(),
290            state_trie_overlay_with_trie_changesets: OnceCell::new(),
291            execution_overlay: OnceCell::new(),
292            is_v2,
293        }
294    }
295
296    fn provider(&self) -> &Provider::Target {
297        &self.provider.as_ref().get_ref().0
298    }
299
300    fn state_trie_overlay(&self, trie_changesets: bool) -> ProviderResult<&StateTrieOverlay>
301    where
302        Provider::Target: StageCheckpointReader
303            + PruneCheckpointReader
304            + ChangeSetReader
305            + StorageChangeSetReader
306            + DBProvider
307            + BlockNumReader
308            + StorageSettingsCache,
309    {
310        let state_trie_overlay = self.state_trie_overlay_mut(trie_changesets);
311        if let Some(overlay) = state_trie_overlay.get() {
312            return Ok(overlay)
313        }
314
315        let (state_trie_tip_block, finish_tip_block) = database_state_frontiers(self.provider())?;
316        let overlay = match self.state_trie_overlay_cache.entry((
317            state_trie_tip_block.hash,
318            finish_tip_block.hash,
319            trie_changesets,
320        )) {
321            dashmap::Entry::Occupied(entry) => entry.get().clone(),
322            dashmap::Entry::Vacant(entry) => {
323                self.metrics.state_trie_overlay_cache_misses.increment(1);
324                let overlay = self
325                    .overlay_builder
326                    .as_ref()
327                    .expect("state trie overlay must be initialized or lazily resolvable")
328                    .build_state_trie_overlay_at_frontiers(
329                        self.provider(),
330                        state_trie_tip_block,
331                        finish_tip_block,
332                        trie_changesets,
333                    )?;
334                if !overlay.skipped_for_reused_sparse_trie() {
335                    entry.insert(overlay.clone());
336                }
337                overlay
338            }
339        };
340        let _ = state_trie_overlay.set(overlay);
341        Ok(state_trie_overlay.get().expect("state trie overlay was just initialized"))
342    }
343
344    const fn state_trie_overlay_mut(&self, trie_changesets: bool) -> &OnceCell<StateTrieOverlay> {
345        if trie_changesets {
346            &self.state_trie_overlay_with_trie_changesets
347        } else {
348            &self.state_trie_overlay
349        }
350    }
351
352    fn build_overlay(
353        &self,
354        input: TrieInputSorted,
355        trie_changesets: bool,
356    ) -> ProviderResult<TrieInputSorted>
357    where
358        Provider::Target: StageCheckpointReader
359            + PruneCheckpointReader
360            + ChangeSetReader
361            + StorageChangeSetReader
362            + DBProvider
363            + BlockNumReader
364            + StorageSettingsCache,
365    {
366        let overlay = self.state_trie_overlay(trie_changesets)?;
367        if overlay.skipped_for_reused_sparse_trie() {
368            return Err(ProviderError::UnsupportedProvider)
369        }
370        let TrieInputSorted { nodes: input_nodes, state: input_state, mut prefix_sets } = input;
371        let overlay_input = overlay.input();
372        let mut nodes = Arc::clone(&overlay_input.nodes);
373        let mut state = Arc::clone(&overlay_input.state);
374
375        if !input_nodes.is_empty() {
376            Arc::make_mut(&mut nodes).extend_ref_and_sort(&input_nodes);
377        }
378        if !input_state.is_empty() {
379            Arc::make_mut(&mut state).extend_ref_and_sort(&input_state);
380        }
381
382        prefix_sets.extend_ref(&overlay_input.prefix_sets);
383        Ok(TrieInputSorted::new(nodes, state, prefix_sets))
384    }
385
386    fn execution_overlay(
387        &self,
388    ) -> ProviderResult<(&Arc<ExecutionOverlay>, Option<&HistoricalFallback>)>
389    where
390        Provider::Target: StageCheckpointReader
391            + PruneCheckpointReader
392            + ChangeSetReader
393            + StorageChangeSetReader
394            + DBProvider
395            + BlockNumReader,
396    {
397        if let Some(overlay) = self.execution_overlay.get() {
398            return Ok((&overlay.overlay, overlay.historical_fallback.as_ref()))
399        }
400
401        let (state_trie_tip_block, finish_tip_block) = database_state_frontiers(self.provider())?;
402        let (overlay, fallback_block_number) = self
403            .overlay_builder
404            .as_ref()
405            .expect("execution overlay must be initialized or lazily resolvable")
406            .execution_overlay_at_frontiers(
407                self.provider(),
408                state_trie_tip_block,
409                finish_tip_block,
410            )?;
411        let historical_fallback = fallback_block_number
412            .map(|block_number| {
413                let account_history_block_number = self
414                    .provider()
415                    .get_prune_checkpoint(PruneSegment::AccountHistory)?
416                    .and_then(|checkpoint| checkpoint.block_number)
417                    .map(|block_number| block_number + 1);
418                if account_history_block_number.is_some_and(|lowest| block_number < lowest) {
419                    return Err(ProviderError::StateAtBlockPruned(block_number))
420                }
421
422                let storage_history_block_number = self
423                    .provider()
424                    .get_prune_checkpoint(PruneSegment::StorageHistory)?
425                    .and_then(|checkpoint| checkpoint.block_number)
426                    .map(|block_number| block_number + 1);
427                if storage_history_block_number.is_some_and(|lowest| block_number < lowest) {
428                    return Err(ProviderError::StateAtBlockPruned(block_number))
429                }
430
431                Ok(HistoricalFallback {
432                    block_number,
433                    account_history_block_number,
434                    storage_history_block_number,
435                })
436            })
437            .transpose()?;
438        let overlay = CachedExecutionOverlay { overlay, historical_fallback };
439        let _ = self.execution_overlay.set(overlay);
440        let overlay = self.execution_overlay.get().expect("execution overlay was just initialized");
441        Ok((&overlay.overlay, overlay.historical_fallback.as_ref()))
442    }
443}
444
445impl<Provider, N: NodePrimitives> Drop for OverlayStateProvider<Provider, N>
446where
447    Provider: Deref,
448    Provider::Target: DBProvider,
449{
450    fn drop(&mut self) {
451        // The calculator borrows the transaction and overlays, so release it before the fields.
452        self.multiproof_calculator.get_mut().take();
453    }
454}
455
456impl<Provider, N: NodePrimitives> fmt::Debug for OverlayStateProvider<Provider, N>
457where
458    Provider: Deref,
459    Provider::Target: DBProvider + fmt::Debug,
460{
461    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462        f.debug_struct("OverlayStateProvider")
463            .field("provider", self.provider())
464            .field("state_trie_overlay", &self.state_trie_overlay.get())
465            .field("execution_overlay", &self.execution_overlay.get())
466            .field("is_v2", &self.is_v2)
467            .finish()
468    }
469}
470
471impl<Provider, N: NodePrimitives> AccountReader for OverlayStateProvider<Provider, N>
472where
473    Provider: Deref,
474    Provider::Target: DBProvider
475        + HistoryReader
476        + StorageSettingsCache
477        + StageCheckpointReader
478        + PruneCheckpointReader
479        + ChangeSetReader
480        + StorageChangeSetReader
481        + BlockNumReader,
482{
483    fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
484        let (overlay, historical_fallback) = self.execution_overlay()?;
485        if let Some(account) = overlay.accounts().get(address) {
486            return Ok(account.as_ref().map(Account::from))
487        }
488        if let Some(historical_fallback) = historical_fallback {
489            return match self.provider().account_history_info(
490                *address,
491                historical_fallback.block_number,
492                historical_fallback.account_history_block_number,
493            )? {
494                HistoryInfo::NotYetWritten => Ok(None),
495                HistoryInfo::InChangeset(changeset_block_number) => self
496                    .provider()
497                    .get_account_before_block(changeset_block_number, *address)?
498                    .ok_or(ProviderError::AccountChangesetNotFound {
499                        block_number: changeset_block_number,
500                        address: *address,
501                    })
502                    .map(|account_before| account_before.info),
503                HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
504                    self.basic_account_from_db(address)
505                }
506            }
507        }
508        self.basic_account_from_db(address)
509    }
510}
511
512impl<Provider, N: NodePrimitives> OverlayStateProvider<Provider, N>
513where
514    Provider: Deref,
515    Provider::Target: DBProvider + StorageSettingsCache,
516{
517    fn basic_account_from_db(&self, address: &Address) -> ProviderResult<Option<Account>> {
518        if self.provider().cached_storage_settings().use_hashed_state() {
519            let hashed_address = alloy_primitives::keccak256(address);
520            self.provider()
521                .tx()
522                .get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)
523                .map_err(Into::into)
524        } else {
525            self.provider()
526                .tx()
527                .get_by_encoded_key::<tables::PlainAccountState>(address)
528                .map_err(Into::into)
529        }
530    }
531}
532
533impl<Provider, N: NodePrimitives> BlockHashReader for OverlayStateProvider<Provider, N>
534where
535    Provider: Deref,
536    Provider::Target: DBProvider
537        + StageCheckpointReader
538        + PruneCheckpointReader
539        + ChangeSetReader
540        + StorageChangeSetReader
541        + BlockNumReader,
542{
543    fn block_hash(&self, number: BlockNumber) -> ProviderResult<Option<B256>> {
544        let (overlay, _) = self.execution_overlay()?;
545        if let Some(block) = overlay.block_hashes().iter().find(|block| block.number == number) {
546            return Ok(Some(block.hash))
547        }
548        self.provider().block_hash(number)
549    }
550
551    fn canonical_hashes_range(
552        &self,
553        start: BlockNumber,
554        end: BlockNumber,
555    ) -> ProviderResult<Vec<B256>> {
556        let (overlay, _) = self.execution_overlay()?;
557        let mut block_hashes =
558            overlay.block_hashes().iter().filter(|block| (start..end).contains(&block.number));
559        let Some(first_block) = block_hashes.next() else {
560            return self.provider().canonical_hashes_range(start, end)
561        };
562
563        let mut hashes = self.provider().canonical_hashes_range(start, first_block.number)?;
564        hashes.push(first_block.hash);
565        hashes.extend(block_hashes.map(|block| block.hash));
566        Ok(hashes)
567    }
568}
569
570impl<Provider, N: NodePrimitives> BytecodeReader for OverlayStateProvider<Provider, N>
571where
572    Provider: Deref,
573    Provider::Target: DBProvider
574        + StageCheckpointReader
575        + PruneCheckpointReader
576        + ChangeSetReader
577        + StorageChangeSetReader
578        + BlockNumReader,
579{
580    fn bytecode_by_hash(
581        &self,
582        code_hash: &B256,
583    ) -> ProviderResult<Option<reth_primitives_traits::Bytecode>> {
584        let (overlay, _) = self.execution_overlay()?;
585        if let Some(bytecode) = overlay.code_hashes().get(code_hash) {
586            return Ok(Some(reth_primitives_traits::Bytecode(bytecode.clone())));
587        }
588        self.provider()
589            .tx()
590            .prefetch(true)
591            .get_by_encoded_key::<tables::Bytecodes>(code_hash)
592            .map_err(Into::into)
593    }
594}
595
596impl<Provider, N: NodePrimitives> StateRootProvider for OverlayStateProvider<Provider, N>
597where
598    Provider: Deref,
599    Provider::Target: DBProvider
600        + StageCheckpointReader
601        + PruneCheckpointReader
602        + ChangeSetReader
603        + StorageChangeSetReader
604        + BlockNumReader
605        + StorageSettingsCache,
606{
607    fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
608        reth_trie_db::with_adapter!(self.provider(), |A| {
609            let input =
610                self.build_overlay(TrieInputSorted::from_state(hashed_state.into_sorted()), false)?;
611            Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(self.provider().tx(), input)?)
612        })
613    }
614
615    fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
616        reth_trie_db::with_adapter!(self.provider(), |A| {
617            let input = self.build_overlay(TrieInputSorted::from_unsorted(input), false)?;
618            Ok(<DbStateRoot<'_, _, A> as DatabaseStateRoot<_>>::overlay_root_from_nodes(
619                self.provider().tx(),
620                input,
621            )?)
622        })
623    }
624
625    fn state_root_with_updates(
626        &self,
627        hashed_state: HashedPostState,
628    ) -> ProviderResult<(B256, TrieUpdates)> {
629        reth_trie_db::with_adapter!(self.provider(), |A| {
630            let input =
631                self.build_overlay(TrieInputSorted::from_state(hashed_state.into_sorted()), true)?;
632            Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(
633                self.provider().tx(),
634                input,
635            )?)
636        })
637    }
638
639    fn state_root_from_nodes_with_updates(
640        &self,
641        input: TrieInput,
642    ) -> ProviderResult<(B256, TrieUpdates)> {
643        reth_trie_db::with_adapter!(self.provider(), |A| {
644            let input = self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
645            Ok(
646                <DbStateRoot<'_, _, A> as DatabaseStateRoot<_>>::overlay_root_from_nodes_with_updates(
647                    self.provider().tx(),
648                    input,
649                )?,
650            )
651        })
652    }
653}
654
655impl<Provider, N: NodePrimitives> StorageRootProvider for OverlayStateProvider<Provider, N>
656where
657    Provider: Deref,
658    Provider::Target: DBProvider
659        + StageCheckpointReader
660        + PruneCheckpointReader
661        + ChangeSetReader
662        + StorageChangeSetReader
663        + BlockNumReader
664        + StorageSettingsCache,
665{
666    fn storage_root(
667        &self,
668        address: Address,
669        hashed_storage: HashedStorage,
670    ) -> ProviderResult<B256> {
671        reth_trie_db::with_adapter!(self.provider(), |A| {
672            let hashed_address = alloy_primitives::keccak256(address);
673            let input = self.build_overlay(
674                TrieInputSorted::from_state(
675                    HashedPostState::from_hashed_storage(hashed_address, hashed_storage)
676                        .into_sorted(),
677                ),
678                false,
679            )?;
680            <DbStorageRoot<'_, _, A>>::overlay_root(self.provider().tx(), address, input)
681                .map_err(|err| ProviderError::Database(err.into()))
682        })
683    }
684
685    fn storage_proof(
686        &self,
687        address: Address,
688        slot: B256,
689        hashed_storage: HashedStorage,
690    ) -> ProviderResult<StorageProof> {
691        self.storage_multiproof(address, &[slot], hashed_storage)?
692            .storage_proof(slot)
693            .map_err(ProviderError::from)
694    }
695
696    fn storage_multiproof(
697        &self,
698        address: Address,
699        slots: &[B256],
700        hashed_storage: HashedStorage,
701    ) -> ProviderResult<StorageMultiProof> {
702        reth_trie_db::with_adapter!(self.provider(), |A| {
703            let hashed_address = alloy_primitives::keccak256(address);
704            let input = self.build_overlay(
705                TrieInputSorted::from_state(
706                    HashedPostState::from_hashed_storage(hashed_address, hashed_storage)
707                        .into_sorted(),
708                ),
709                false,
710            )?;
711            <DbStorageProof<'_, _, A>>::overlay_storage_multiproof(
712                self.provider().tx(),
713                address,
714                slots,
715                input,
716            )
717            .map_err(ProviderError::from)
718        })
719    }
720}
721
722impl<Provider, N: NodePrimitives> StateProofProvider for OverlayStateProvider<Provider, N>
723where
724    Provider: Deref,
725    Provider::Target: DBProvider
726        + StageCheckpointReader
727        + PruneCheckpointReader
728        + ChangeSetReader
729        + StorageChangeSetReader
730        + BlockNumReader
731        + StorageSettingsCache,
732{
733    fn proof(
734        &self,
735        input: TrieInput,
736        address: Address,
737        slots: &[B256],
738    ) -> ProviderResult<AccountProof> {
739        reth_trie_db::with_adapter!(self.provider(), |A| {
740            let TrieInputSorted { nodes, state, prefix_sets } =
741                self.build_overlay(TrieInputSorted::from_unsorted(input), false)?;
742            let input = TrieInput::new(
743                Arc::unwrap_or_clone(nodes).into(),
744                Arc::unwrap_or_clone(state).into(),
745                prefix_sets,
746            );
747            let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.provider().tx());
748            proof.overlay_account_proof(input, address, slots).map_err(ProviderError::from)
749        })
750    }
751
752    fn multiproof(
753        &self,
754        input: TrieInput,
755        targets: MultiProofTargets,
756    ) -> ProviderResult<MultiProof> {
757        reth_trie_db::with_adapter!(self.provider(), |A| {
758            let TrieInputSorted { nodes, state, prefix_sets } =
759                self.build_overlay(TrieInputSorted::from_unsorted(input), false)?;
760            let input = TrieInput::new(
761                Arc::unwrap_or_clone(nodes).into(),
762                Arc::unwrap_or_clone(state).into(),
763                prefix_sets,
764            );
765            let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.provider().tx());
766            proof.overlay_multiproof(input, targets).map_err(ProviderError::from)
767        })
768    }
769
770    fn multiproof_v2(
771        &self,
772        targets: MultiProofTargetsV2,
773        requires_masks: bool,
774    ) -> ProviderResult<DecodedMultiProofV2> {
775        // Avoid resolving the overlay when there is nothing to prove.
776        if targets.is_empty() {
777            return Ok(DecodedMultiProofV2::default())
778        }
779        let mut calculator_slot = self.multiproof_calculator.borrow_mut();
780        let cached = match &mut *calculator_slot {
781            Some(cached) if cached.requires_masks == requires_masks => cached,
782            slot => {
783                let input = self.state_trie_overlay(requires_masks)?.input();
784                // SAFETY: The transaction lives behind `provider`, which is pinned or borrowed for
785                // the provider's lifetime, and the overlay allocations live in `OnceCell`s that are
786                // never reset. `Drop` releases the calculator before either, and the calculator
787                // never leaves this provider, which is not `Sync`. An owned
788                // transaction therefore only moves between threads together with
789                // the calculator. A borrowed provider is `Send` only if it is
790                // `Sync`, in which case its transaction may be shared.
791                let calculator = unsafe {
792                    OverlayMultiProofCalculator::new(
793                        self.provider().tx(),
794                        input,
795                        self.is_v2,
796                        self.proof_cursor_metrics.clone(),
797                        self.known_storage_roots.clone(),
798                    )
799                };
800                slot.insert(CachedMultiProofCalculator { requires_masks, calculator })
801            }
802        };
803        cached.calculator.multiproof(targets)
804    }
805
806    fn witness(
807        &self,
808        input: TrieInput,
809        target: HashedPostState,
810        mode: ExecutionWitnessMode,
811    ) -> ProviderResult<Vec<alloy_primitives::Bytes>> {
812        reth_trie_db::with_adapter!(self.provider(), |A| {
813            let TrieInputSorted { nodes, state, prefix_sets } =
814                self.build_overlay(TrieInputSorted::from_unsorted(input), false)?;
815            let witness = TrieWitness::new(
816                InMemoryTrieCursorFactory::new(
817                    DatabaseTrieCursorFactory::<_, A>::new(self.provider().tx()),
818                    nodes.as_ref(),
819                ),
820                HashedPostStateCursorFactory::new(
821                    DatabaseHashedCursorFactory::new(self.provider().tx()),
822                    state.as_ref(),
823                ),
824            )
825            .with_prefix_sets_mut(prefix_sets)
826            .with_execution_witness_mode(mode);
827            let witness =
828                if mode.is_canonical() { witness } else { witness.always_include_root_node() };
829            let mut values: Vec<_> = witness.compute(target)?.into_values().collect();
830            if mode.is_canonical() {
831                values.sort_unstable();
832            }
833            Ok(values)
834        })
835    }
836}
837
838impl<Provider, N: NodePrimitives> HashedPostStateProvider for OverlayStateProvider<Provider, N>
839where
840    Provider: Deref,
841    Provider::Target: DBProvider
842        + StageCheckpointReader
843        + PruneCheckpointReader
844        + ChangeSetReader
845        + StorageChangeSetReader
846        + BlockNumReader
847        + StorageSettingsCache,
848{
849    fn hashed_post_state(
850        &self,
851        bundle_state: &revm::database::BundleState,
852    ) -> ProviderResult<HashedPostState> {
853        let mut hashed_state =
854            HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state());
855        if !bundle_state
856            .state()
857            .values()
858            .any(|account| account.was_destroyed() && account.original_info.is_some())
859        {
860            return Ok(hashed_state)
861        }
862
863        let overlay_state = self.build_overlay(TrieInputSorted::default(), false)?.state;
864        zero_destroyed_account_storage(
865            &HashedPostStateCursorFactory::new(
866                DatabaseHashedCursorFactory::new(self.provider().tx()),
867                overlay_state.as_ref(),
868            ),
869            bundle_state.state(),
870            &mut hashed_state,
871        )?;
872        Ok(hashed_state)
873    }
874}
875
876impl<Provider, N: NodePrimitives> StateProvider for OverlayStateProvider<Provider, N>
877where
878    Provider: Deref,
879    Provider::Target: DBProvider
880        + HistoryReader
881        + StorageSettingsCache
882        + StageCheckpointReader
883        + PruneCheckpointReader
884        + ChangeSetReader
885        + StorageChangeSetReader
886        + BlockNumReader,
887{
888    fn storage(
889        &self,
890        address: Address,
891        storage_key: alloy_primitives::StorageKey,
892    ) -> ProviderResult<Option<alloy_primitives::StorageValue>> {
893        let (overlay, historical_fallback) = self.execution_overlay()?;
894        if let Some(value) = overlay.storage_value(address, U256::from_be_bytes(storage_key.0)) {
895            return Ok(Some(value));
896        }
897        if let Some(historical_fallback) = historical_fallback {
898            return match self.provider().storage_history_info(
899                address,
900                storage_key,
901                historical_fallback.block_number,
902                historical_fallback.storage_history_block_number,
903            )? {
904                HistoryInfo::NotYetWritten => Ok(None),
905                HistoryInfo::InChangeset(changeset_block_number) => self
906                    .provider()
907                    .get_storage_before_block(changeset_block_number, address, storage_key)?
908                    .ok_or_else(|| ProviderError::StorageChangesetNotFound {
909                        block_number: changeset_block_number,
910                        address,
911                        storage_key: Box::new(storage_key),
912                    })
913                    .map(|entry| Some(entry.value)),
914                HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
915                    self.storage_from_db(address, storage_key, true)
916                }
917            }
918        }
919        self.storage_from_db(address, storage_key, false)
920    }
921}
922
923impl<Provider, N: NodePrimitives> OverlayStateProvider<Provider, N>
924where
925    Provider: Deref,
926    Provider::Target: DBProvider + StorageSettingsCache,
927{
928    fn storage_from_db(
929        &self,
930        address: Address,
931        storage_key: alloy_primitives::StorageKey,
932        zero_if_missing: bool,
933    ) -> ProviderResult<Option<alloy_primitives::StorageValue>> {
934        if self.provider().cached_storage_settings().use_hashed_state() {
935            let hashed_address = alloy_primitives::keccak256(address);
936            let hashed_slot = alloy_primitives::keccak256(storage_key);
937            let mut cursor = self.provider().tx().cursor_dup_read::<tables::HashedStorages>()?;
938            let value = cursor
939                .seek_by_key_subkey(hashed_address, hashed_slot)?
940                .filter(|entry| entry.key == hashed_slot)
941                .map(|entry| entry.value);
942            Ok(value.or_else(|| zero_if_missing.then_some(U256::ZERO)))
943        } else {
944            let mut cursor = self.provider().tx().cursor_dup_read::<tables::PlainStorageState>()?;
945            if let Some(entry) = cursor.seek_by_key_subkey(address, storage_key)? &&
946                entry.key == storage_key
947            {
948                return Ok(Some(entry.value))
949            }
950            Ok(zero_if_missing.then_some(U256::ZERO))
951        }
952    }
953}
954
955impl<Provider, N: NodePrimitives> TrieCursorFactory for OverlayStateProvider<Provider, N>
956where
957    Provider: Deref,
958    Provider::Target: DBProvider
959        + StageCheckpointReader
960        + PruneCheckpointReader
961        + ChangeSetReader
962        + StorageChangeSetReader
963        + BlockNumReader
964        + StorageSettingsCache,
965{
966    type AccountTrieCursor<'a>
967        = InMemoryTrieCursor<'a, Box<dyn TrieCursor + Send + 'a>>
968    where
969        Self: 'a;
970
971    type StorageTrieCursor<'a>
972        = InMemoryTrieCursor<'a, Box<dyn TrieStorageCursor + Send + 'a>>
973    where
974        Self: 'a;
975
976    fn account_trie_cursor(&self) -> Result<Self::AccountTrieCursor<'_>, DatabaseError> {
977        let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
978        let cursor: Box<dyn TrieCursor + Send> = if self.is_v2 {
979            Box::new(DatabaseAccountTrieCursor::<_, PackedKeyAdapter>::new(
980                self.provider().tx().cursor_read::<PackedAccountsTrie>()?,
981            ))
982        } else {
983            Box::new(DatabaseAccountTrieCursor::<_, LegacyKeyAdapter>::new(
984                self.provider().tx().cursor_read::<tables::AccountsTrie>()?,
985            ))
986        };
987        Ok(InMemoryTrieCursor::new_account(cursor, &overlay.input().nodes))
988    }
989
990    fn storage_trie_cursor(
991        &self,
992        hashed_address: B256,
993    ) -> Result<Self::StorageTrieCursor<'_>, DatabaseError> {
994        let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
995        let cursor: Box<dyn TrieStorageCursor + Send> = if self.is_v2 {
996            Box::new(DatabaseStorageTrieCursor::<_, PackedKeyAdapter>::new(
997                self.provider().tx().cursor_dup_read::<PackedStoragesTrie>()?,
998                hashed_address,
999            ))
1000        } else {
1001            Box::new(DatabaseStorageTrieCursor::<_, LegacyKeyAdapter>::new(
1002                self.provider().tx().cursor_dup_read::<tables::StoragesTrie>()?,
1003                hashed_address,
1004            ))
1005        };
1006        Ok(InMemoryTrieCursor::new_storage(cursor, &overlay.input().nodes, hashed_address))
1007    }
1008}
1009
1010impl<Provider, N: NodePrimitives> HashedCursorFactory for OverlayStateProvider<Provider, N>
1011where
1012    Provider: Deref,
1013    Provider::Target: DBProvider
1014        + StageCheckpointReader
1015        + PruneCheckpointReader
1016        + ChangeSetReader
1017        + StorageChangeSetReader
1018        + BlockNumReader
1019        + StorageSettingsCache,
1020{
1021    type AccountCursor<'a>
1022        = <HashedPostStateCursorFactory<
1023        DatabaseHashedCursorFactory<&'a <Provider::Target as DbTxProvider>::Tx>,
1024        &'a Arc<HashedPostStateSorted>,
1025    > as HashedCursorFactory>::AccountCursor<'a>
1026    where
1027        Self: 'a;
1028
1029    type StorageCursor<'a>
1030        = <HashedPostStateCursorFactory<
1031        DatabaseHashedCursorFactory<&'a <Provider::Target as DbTxProvider>::Tx>,
1032        &'a Arc<HashedPostStateSorted>,
1033    > as HashedCursorFactory>::StorageCursor<'a>
1034    where
1035        Self: 'a;
1036
1037    fn hashed_account_cursor(&self) -> Result<Self::AccountCursor<'_>, DatabaseError> {
1038        let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
1039        HashedPostStateCursorFactory::new(
1040            DatabaseHashedCursorFactory::new(self.provider().tx()),
1041            &overlay.input().state,
1042        )
1043        .hashed_account_cursor()
1044    }
1045
1046    fn hashed_storage_cursor(
1047        &self,
1048        hashed_address: B256,
1049    ) -> Result<Self::StorageCursor<'_>, DatabaseError> {
1050        let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
1051        HashedPostStateCursorFactory::new(
1052            DatabaseHashedCursorFactory::new(self.provider().tx()),
1053            &overlay.input().state,
1054        )
1055        .hashed_storage_cursor(hashed_address)
1056    }
1057}
1058
1059/// Metrics for overlay state provider factory operations.
1060#[derive(Clone, Metrics)]
1061#[metrics(scope = "storage.providers.overlay")]
1062pub(crate) struct OverlayStateProviderFactoryMetrics {
1063    /// Duration of creating the database provider transaction.
1064    create_provider_duration: Histogram,
1065    /// Overall duration of the [`OverlayStateProviderFactory::database_provider_ro`] call.
1066    database_provider_ro_duration: Histogram,
1067    /// Number of cache misses when fetching state trie overlays.
1068    state_trie_overlay_cache_misses: Counter,
1069}
1070
1071type StateTrieOverlayCache = Arc<DashMap<(BlockHash, BlockHash, bool), StateTrieOverlay>>;
1072
1073#[derive(Clone, Debug)]
1074struct CachedExecutionOverlay {
1075    overlay: Arc<ExecutionOverlay>,
1076    historical_fallback: Option<HistoricalFallback>,
1077}
1078
1079#[derive(Clone, Copy, Debug)]
1080struct HistoricalFallback {
1081    block_number: BlockNumber,
1082    account_history_block_number: Option<BlockNumber>,
1083    storage_history_block_number: Option<BlockNumber>,
1084}
1085
1086type DbStateRoot<'a, TX, A> =
1087    StateRoot<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
1088type DbStorageRoot<'a, TX, A> =
1089    StorageRoot<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
1090type DbStorageProof<'a, TX, A> =
1091    TrieStorageProof<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
1092type DbProof<'a, TX, A> =
1093    Proof<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
1094
1095#[doc(hidden)]
1096#[derive(Debug)]
1097pub struct OwnedProvider<Provider>(Provider);
1098
1099impl<Provider> Deref for OwnedProvider<Provider> {
1100    type Target = Provider;
1101
1102    fn deref(&self) -> &Self::Target {
1103        &self.0
1104    }
1105}
1106
1107/// Multiproof calculator cached by [`OverlayStateProvider`].
1108struct CachedMultiProofCalculator<TX: DbTx + 'static> {
1109    /// Whether the calculator returns masks that match the stored trie.
1110    requires_masks: bool,
1111    calculator: OverlayMultiProofCalculator<TX>,
1112}
1113
1114fn into_database_error(error: ProviderError) -> DatabaseError {
1115    match error {
1116        ProviderError::Database(error) => error,
1117        error => DatabaseError::Other(error.to_string()),
1118    }
1119}
1120
1121#[cfg(test)]
1122mod tests {
1123    use super::*;
1124    use crate::{ExecutionOverlay, OverlayManager};
1125    use alloy_eips::BlockNumHash;
1126    use alloy_primitives::{Address, U256};
1127    use reth_chain_state::{test_utils::TestBlockBuilder, ExecutedBlock};
1128    use reth_db_api::{
1129        models::{
1130            storage_sharded_key::StorageShardedKey, AccountBeforeTx, BlockNumberAddress, ShardedKey,
1131        },
1132        tables,
1133        transaction::DbTxMut,
1134        BlockNumberList,
1135    };
1136    use reth_primitives_traits::Account;
1137    use reth_provider::{
1138        test_utils::{create_test_provider_factory, MockNodeTypesWithDB},
1139        BlockWriter, ProviderFactory,
1140    };
1141    use reth_stages_types::{FinishCheckpoint, StageCheckpoint, StageId};
1142    use reth_storage_api::StageCheckpointWriter;
1143    use reth_trie::{
1144        updates::TrieUpdatesSorted, BranchNodeCompact, HashedPostState, HashedStorage, Nibbles,
1145        SortedTrieData,
1146    };
1147    use revm::{bytecode::Bytecode as RevmBytecode, state::AccountInfo};
1148
1149    fn with_unique_trie_data(
1150        block: &ExecutedBlock<EthPrimitives>,
1151        id: u8,
1152    ) -> ExecutedBlock<EthPrimitives> {
1153        let hashed_address = B256::with_last_byte(id);
1154        let hashed_slot = B256::with_last_byte(id.saturating_add(32));
1155        let hashed_state = HashedPostState::default()
1156            .with_accounts([(hashed_address, Some(Account::default()))])
1157            .with_storages([(
1158                hashed_address,
1159                HashedStorage::from_iter([(hashed_slot, U256::from(id))]),
1160            )])
1161            .into_sorted();
1162        let trie_updates = TrieUpdatesSorted::new(
1163            vec![(
1164                Nibbles::from_nibbles([id]),
1165                Some(BranchNodeCompact::new(0, 0, 0, vec![], None)),
1166            )],
1167            Default::default(),
1168        );
1169
1170        ExecutedBlock::new(
1171            Arc::clone(&block.recovered_block),
1172            Arc::clone(&block.execution_output),
1173            SortedTrieData::new(Arc::new(hashed_state), Arc::new(trie_updates)),
1174        )
1175    }
1176
1177    fn test_blocks() -> Vec<ExecutedBlock<EthPrimitives>> {
1178        TestBlockBuilder::eth()
1179            .get_executed_blocks(0..5)
1180            .enumerate()
1181            .map(|(index, block)| with_unique_trie_data(&block, index as u8 + 1))
1182            .collect()
1183    }
1184
1185    fn setup_frontiers(
1186        state_trie_tip_index: usize,
1187        finish_tip_index: usize,
1188    ) -> (ProviderFactory<MockNodeTypesWithDB>, Vec<ExecutedBlock<EthPrimitives>>) {
1189        let factory = create_test_provider_factory();
1190        let blocks = test_blocks();
1191        let provider_rw = factory.provider_rw().unwrap();
1192        for block in &blocks[..=finish_tip_index] {
1193            provider_rw.insert_block(block.recovered_block()).unwrap();
1194        }
1195        provider_rw
1196            .save_stage_checkpoint(
1197                StageId::Finish,
1198                StageCheckpoint::new(blocks[finish_tip_index].block_number())
1199                    .with_finish_stage_checkpoint(FinishCheckpoint {
1200                        partial_state_trie: Some(blocks[state_trie_tip_index].block_number()),
1201                    }),
1202            )
1203            .unwrap();
1204        provider_rw.commit().unwrap();
1205
1206        (factory, blocks)
1207    }
1208
1209    fn account_keys(overlay: &StateTrieOverlay) -> Vec<B256> {
1210        overlay.input().state.accounts.iter().map(|(key, _)| *key).collect()
1211    }
1212
1213    fn account_node_paths(overlay: &StateTrieOverlay) -> Vec<Nibbles> {
1214        overlay.input().nodes.account_nodes_ref().iter().map(|(path, _)| *path).collect()
1215    }
1216
1217    #[test]
1218    fn overlay_cache_is_keyed_by_both_durable_frontiers() {
1219        let (factory, blocks) = setup_frontiers(1, 3);
1220        let manager = OverlayManager::default();
1221        for block in &blocks[2..=3] {
1222            manager.insert_block(block.clone());
1223        }
1224        let state_provider_factory = OverlayStateProviderFactory::new(
1225            factory.clone(),
1226            manager.overlay_builder(blocks[3].recovered_block().hash()),
1227        );
1228
1229        let provider = state_provider_factory.database_provider_ro().unwrap();
1230        let first = provider.state_trie_overlay(false).unwrap().clone();
1231        assert_eq!(account_keys(&first), vec![B256::with_last_byte(3), B256::with_last_byte(4)]);
1232        drop(provider);
1233
1234        let provider_rw = factory.provider_rw().unwrap();
1235        provider_rw
1236            .save_stage_checkpoint(
1237                StageId::Finish,
1238                StageCheckpoint::new(blocks[3].block_number()).with_finish_stage_checkpoint(
1239                    FinishCheckpoint { partial_state_trie: Some(blocks[2].block_number()) },
1240                ),
1241            )
1242            .unwrap();
1243        provider_rw.commit().unwrap();
1244
1245        let provider = state_provider_factory.database_provider_ro().unwrap();
1246        let second = provider.state_trie_overlay(false).unwrap().clone();
1247        assert_eq!(account_keys(&second), vec![B256::with_last_byte(4)]);
1248        assert_eq!(account_node_paths(&second), vec![Nibbles::from_nibbles([4])]);
1249        assert_eq!(state_provider_factory.state_trie_overlay_cache.len(), 2);
1250    }
1251
1252    #[test]
1253    fn overlays_are_computed_lazily() {
1254        let (factory, blocks) = setup_frontiers(1, 3);
1255        let manager = OverlayManager::default();
1256        for block in &blocks[2..=3] {
1257            manager.insert_block(block.clone());
1258        }
1259        let state_provider_factory = OverlayStateProviderFactory::new(
1260            factory,
1261            manager.overlay_builder(blocks[3].recovered_block().hash()),
1262        );
1263
1264        let provider = state_provider_factory.database_provider_ro().unwrap();
1265
1266        assert!(provider.state_trie_overlay.get().is_none());
1267        assert!(provider.execution_overlay.get().is_none());
1268        assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1269
1270        provider.basic_account(&Address::ZERO).unwrap();
1271        assert!(provider.state_trie_overlay.get().is_none());
1272        assert!(provider.execution_overlay.get().is_some());
1273        assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1274
1275        provider.account_trie_cursor().unwrap();
1276        assert_eq!(state_provider_factory.state_trie_overlay_cache.len(), 1);
1277    }
1278
1279    #[test]
1280    fn state_trie_overlay_cache_is_keyed_by_trie_changesets() {
1281        let (factory, blocks) = setup_frontiers(1, 3);
1282        let manager = OverlayManager::default();
1283        for block in &blocks[2..=3] {
1284            manager.insert_block(block.clone());
1285        }
1286        let state_provider_factory = OverlayStateProviderFactory::new(
1287            factory,
1288            manager.overlay_builder(blocks[3].recovered_block().hash()),
1289        );
1290        let provider = state_provider_factory.database_provider_ro().unwrap();
1291
1292        provider.state_trie_overlay(false).unwrap();
1293        provider.state_trie_overlay(true).unwrap();
1294
1295        assert_eq!(state_provider_factory.state_trie_overlay_cache.len(), 2);
1296    }
1297
1298    #[test]
1299    fn supplied_state_trie_overlay_is_available_in_both_modes() {
1300        let (factory, _) = setup_frontiers(1, 1);
1301        let provider = factory.provider().unwrap();
1302        let provider = OverlayStateProvider::<&_, EthPrimitives>::new_with_state_trie(
1303            &provider,
1304            StateTrieOverlay::new(TrieInputSorted::default()),
1305            false,
1306        );
1307
1308        assert!(provider.state_trie_overlay(false).is_ok());
1309        assert!(provider.state_trie_overlay(true).is_ok());
1310    }
1311
1312    #[test]
1313    fn lazy_overlays_survive_manager_block_removal() {
1314        let (factory, blocks) = setup_frontiers(1, 1);
1315        let manager = OverlayManager::default();
1316        for block in &blocks[2..=3] {
1317            manager.insert_block(block.clone());
1318        }
1319        let state_provider_factory = OverlayStateProviderFactory::new(
1320            factory,
1321            manager.overlay_builder(blocks[3].recovered_block().hash()),
1322        );
1323        let provider = state_provider_factory.database_provider_ro().unwrap();
1324
1325        manager.remove_blocks(blocks[2..=3].iter().map(|block| block.recovered_block().hash()));
1326
1327        let (execution_overlay, _) = provider.execution_overlay().unwrap();
1328        assert_eq!(
1329            execution_overlay.block_hashes(),
1330            [blocks[2].recovered_block().num_hash(), blocks[3].recovered_block().num_hash()]
1331        );
1332        assert_eq!(
1333            account_keys(provider.state_trie_overlay(false).unwrap()),
1334            vec![B256::with_last_byte(3), B256::with_last_byte(4)]
1335        );
1336    }
1337
1338    #[test]
1339    fn skipped_state_trie_overlay_is_not_cached_or_used_for_state_roots() {
1340        let (factory, blocks) = setup_frontiers(3, 3);
1341        let manager = OverlayManager::default();
1342        manager.insert_block(blocks[4].clone());
1343        let state_provider_factory = OverlayStateProviderFactory::new(
1344            factory,
1345            manager
1346                .overlay_builder(blocks[4].recovered_block().hash())
1347                .with_skip_overlay_for_reused_sparse_trie(blocks[3].recovered_block().hash()),
1348        );
1349
1350        let provider = state_provider_factory.database_provider_ro().unwrap();
1351        assert!(provider.state_trie_overlay(false).unwrap().skipped_for_reused_sparse_trie());
1352        assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1353        assert!(matches!(
1354            provider.state_root(HashedPostState::default()),
1355            Err(ProviderError::UnsupportedProvider)
1356        ));
1357        assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1358    }
1359
1360    #[test]
1361    fn execution_overlay_readers_use_overlay_first() {
1362        let (factory, _) = setup_frontiers(1, 3);
1363        let address = Address::with_last_byte(1);
1364        let account_info = AccountInfo { nonce: 1, balance: U256::from(2), ..Default::default() };
1365        let block_hash = B256::with_last_byte(3);
1366        let storage_key = B256::with_last_byte(4);
1367        let storage_value = U256::from(5);
1368        let code_hash = B256::with_last_byte(6);
1369        let bytecode = RevmBytecode::new_raw([0x60, 0x01].into());
1370        let mut execution_overlay = ExecutionOverlay::default();
1371        execution_overlay.accounts_mut().insert(address, Some(account_info.clone()));
1372        execution_overlay.block_hashes_mut().push(BlockNumHash::new(1, block_hash));
1373        execution_overlay
1374            .storage_mut()
1375            .entry(address)
1376            .or_default()
1377            .insert(U256::from_be_bytes(storage_key.0), storage_value);
1378        execution_overlay.code_hashes_mut().insert(code_hash, bytecode.clone());
1379        let provider = OverlayStateProvider::<_, EthPrimitives>::new_with_execution(
1380            factory.provider().unwrap(),
1381            Arc::new(execution_overlay),
1382            false,
1383        );
1384
1385        assert_eq!(provider.basic_account(&address).unwrap(), Some(Account::from(account_info)));
1386        assert!(provider.basic_account(&Address::with_last_byte(2)).unwrap().is_none());
1387        assert_eq!(provider.block_hash(1).unwrap(), Some(block_hash));
1388        assert_eq!(provider.canonical_hashes_range(1, 2).unwrap(), vec![block_hash]);
1389        assert_eq!(provider.storage(address, storage_key).unwrap(), Some(storage_value));
1390        assert_eq!(
1391            provider.bytecode_by_hash(&code_hash).unwrap(),
1392            Some(reth_primitives_traits::Bytecode(bytecode))
1393        );
1394    }
1395
1396    #[test]
1397    #[allow(clippy::clone_on_copy)]
1398    fn historical_execution_reads_use_history_indexes() {
1399        let (factory, blocks) = setup_frontiers(1, 3);
1400        let address = Address::with_last_byte(1);
1401        let storage_key = B256::with_last_byte(2);
1402        let account = Account { balance: U256::from(10), ..Default::default() };
1403        let storage = U256::from(10);
1404        let provider_rw = factory.provider_rw().unwrap();
1405
1406        provider_rw
1407            .tx_ref()
1408            .put::<tables::AccountsHistory>(
1409                ShardedKey { key: address, highest_block_number: u64::MAX },
1410                BlockNumberList::new([2]).unwrap(),
1411            )
1412            .unwrap();
1413        provider_rw
1414            .tx_ref()
1415            .put::<tables::AccountChangeSets>(
1416                2,
1417                AccountBeforeTx { address, info: Some(account.clone()) },
1418            )
1419            .unwrap();
1420        provider_rw
1421            .tx_ref()
1422            .put::<tables::PlainAccountState>(
1423                address,
1424                Account { balance: U256::from(20), ..Default::default() },
1425            )
1426            .unwrap();
1427        provider_rw
1428            .tx_ref()
1429            .put::<tables::StoragesHistory>(
1430                StorageShardedKey {
1431                    address,
1432                    sharded_key: ShardedKey { key: storage_key, highest_block_number: u64::MAX },
1433                },
1434                BlockNumberList::new([2]).unwrap(),
1435            )
1436            .unwrap();
1437        provider_rw
1438            .tx_ref()
1439            .put::<tables::StorageChangeSets>(
1440                BlockNumberAddress((2, address)),
1441                reth_primitives_traits::StorageEntry { key: storage_key, value: storage },
1442            )
1443            .unwrap();
1444        provider_rw
1445            .tx_ref()
1446            .put::<tables::PlainStorageState>(
1447                address,
1448                reth_primitives_traits::StorageEntry { key: storage_key, value: U256::from(20) },
1449            )
1450            .unwrap();
1451        provider_rw.commit().unwrap();
1452
1453        let state_provider_factory = OverlayStateProviderFactory::<_, EthPrimitives>::new(
1454            factory,
1455            OverlayManager::default().overlay_builder(blocks[1].recovered_block().hash()),
1456        );
1457        let provider = state_provider_factory.database_provider_ro().unwrap();
1458
1459        assert_eq!(provider.basic_account(&address).unwrap(), Some(account));
1460        assert_eq!(provider.storage(address, storage_key).unwrap(), Some(storage));
1461    }
1462}