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