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#[derive(Debug, Clone)]
62pub struct OverlayStateProviderFactory<F, N: NodePrimitives = EthPrimitives> {
63 factory: F,
65 overlay_builder: OverlayBuilder<N>,
67 state_trie_overlay_cache: StateTrieOverlayCache,
72 metrics: OverlayStateProviderFactoryMetrics,
74 proof_cursor_metrics: ProofCursorMetrics,
76 known_storage_roots: Arc<B256Map<B256>>,
78}
79
80impl<F, N: NodePrimitives> OverlayStateProviderFactory<F, N> {
81 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 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 #[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 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
161pub struct OverlayStateProvider<Provider, N: NodePrimitives = EthPrimitives>
163where
164 Provider: Deref,
165 Provider::Target: DBProvider,
166{
167 multiproof_calculator:
172 RefCell<Option<CachedMultiProofCalculator<<Provider::Target as DbTxProvider>::Tx>>>,
173 provider: Pin<Box<(Provider, PhantomPinned)>>,
175 overlay_builder: Option<OverlayBuilder<N>>,
176 state_trie_overlay_cache: Option<StateTrieOverlayCache>,
178 metrics: OverlayStateProviderFactoryMetrics,
179 proof_cursor_metrics: ProofCursorMetrics,
180 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 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 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 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 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 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 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#[derive(Clone, Metrics)]
1074#[metrics(scope = "storage.providers.overlay")]
1075pub(crate) struct OverlayStateProviderFactoryMetrics {
1076 create_provider_duration: Histogram,
1078 database_provider_ro_duration: Histogram,
1080 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
1120struct CachedMultiProofCalculator<TX: DbTx + 'static> {
1122 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}