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