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