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 =
537 self.build_overlay(TrieInputSorted::from_state(hashed_state.into_sorted()), true)?;
538 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(self.provider().tx(), input)?)
539 })
540 }
541
542 fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
543 reth_trie_db::with_adapter!(self.provider(), |A| {
544 let input = self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
545 Ok(<DbStateRoot<'_, _, A> as DatabaseStateRoot<_>>::overlay_root_from_nodes(
546 self.provider().tx(),
547 input,
548 )?)
549 })
550 }
551
552 fn state_root_with_updates(
553 &self,
554 hashed_state: HashedPostState,
555 ) -> ProviderResult<(B256, TrieUpdates)> {
556 reth_trie_db::with_adapter!(self.provider(), |A| {
557 let input =
558 self.build_overlay(TrieInputSorted::from_state(hashed_state.into_sorted()), true)?;
559 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(
560 self.provider().tx(),
561 input,
562 )?)
563 })
564 }
565
566 fn state_root_from_nodes_with_updates(
567 &self,
568 input: TrieInput,
569 ) -> ProviderResult<(B256, TrieUpdates)> {
570 reth_trie_db::with_adapter!(self.provider(), |A| {
571 let input = self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
572 Ok(
573 <DbStateRoot<'_, _, A> as DatabaseStateRoot<_>>::overlay_root_from_nodes_with_updates(
574 self.provider().tx(),
575 input,
576 )?,
577 )
578 })
579 }
580}
581
582impl<Provider, N: NodePrimitives> StorageRootProvider for OverlayStateProvider<Provider, N>
583where
584 Provider: Deref,
585 Provider::Target: DBProvider
586 + StageCheckpointReader
587 + PruneCheckpointReader
588 + ChangeSetReader
589 + StorageChangeSetReader
590 + BlockNumReader
591 + StorageSettingsCache,
592{
593 fn storage_root(
594 &self,
595 address: Address,
596 hashed_storage: HashedStorage,
597 ) -> ProviderResult<B256> {
598 reth_trie_db::with_adapter!(self.provider(), |A| {
599 let hashed_address = alloy_primitives::keccak256(address);
600 let input = self.build_overlay(
601 TrieInputSorted::from_state(
602 HashedPostState::from_hashed_storage(hashed_address, hashed_storage)
603 .into_sorted(),
604 ),
605 true,
606 )?;
607 <DbStorageRoot<'_, _, A>>::overlay_root(self.provider().tx(), address, input)
608 .map_err(|err| ProviderError::Database(err.into()))
609 })
610 }
611
612 fn storage_proof(
613 &self,
614 address: Address,
615 slot: B256,
616 hashed_storage: HashedStorage,
617 ) -> ProviderResult<StorageProof> {
618 self.storage_multiproof(address, &[slot], hashed_storage)?
619 .storage_proof(slot)
620 .map_err(ProviderError::from)
621 }
622
623 fn storage_multiproof(
624 &self,
625 address: Address,
626 slots: &[B256],
627 hashed_storage: HashedStorage,
628 ) -> ProviderResult<StorageMultiProof> {
629 reth_trie_db::with_adapter!(self.provider(), |A| {
630 let hashed_address = alloy_primitives::keccak256(address);
631 let input = self.build_overlay(
632 TrieInputSorted::from_state(
633 HashedPostState::from_hashed_storage(hashed_address, hashed_storage)
634 .into_sorted(),
635 ),
636 true,
637 )?;
638 <DbStorageProof<'_, _, A>>::overlay_storage_multiproof(
639 self.provider().tx(),
640 address,
641 slots,
642 input,
643 )
644 .map_err(ProviderError::from)
645 })
646 }
647}
648
649impl<Provider, N: NodePrimitives> StateProofProvider for OverlayStateProvider<Provider, N>
650where
651 Provider: Deref,
652 Provider::Target: DBProvider
653 + StageCheckpointReader
654 + PruneCheckpointReader
655 + ChangeSetReader
656 + StorageChangeSetReader
657 + BlockNumReader
658 + StorageSettingsCache,
659{
660 fn proof(
661 &self,
662 input: TrieInput,
663 address: Address,
664 slots: &[B256],
665 ) -> ProviderResult<AccountProof> {
666 reth_trie_db::with_adapter!(self.provider(), |A| {
667 let TrieInputSorted { nodes, state, prefix_sets } =
668 self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
669 let input = TrieInput::new(
670 Arc::unwrap_or_clone(nodes).into(),
671 Arc::unwrap_or_clone(state).into(),
672 prefix_sets,
673 );
674 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.provider().tx());
675 proof.overlay_account_proof(input, address, slots).map_err(ProviderError::from)
676 })
677 }
678
679 fn multiproof(
680 &self,
681 input: TrieInput,
682 targets: MultiProofTargets,
683 ) -> ProviderResult<MultiProof> {
684 reth_trie_db::with_adapter!(self.provider(), |A| {
685 let TrieInputSorted { nodes, state, prefix_sets } =
686 self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
687 let input = TrieInput::new(
688 Arc::unwrap_or_clone(nodes).into(),
689 Arc::unwrap_or_clone(state).into(),
690 prefix_sets,
691 );
692 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.provider().tx());
693 proof.overlay_multiproof(input, targets).map_err(ProviderError::from)
694 })
695 }
696
697 fn multiproof_v2(
698 &self,
699 input: TrieInput,
700 targets: MultiProofTargetsV2,
701 ) -> ProviderResult<DecodedMultiProofV2> {
702 reth_trie_db::with_adapter!(self.provider(), |A| {
703 let TrieInputSorted { nodes, state, prefix_sets } =
704 self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
705 let input = TrieInput::new(
706 Arc::unwrap_or_clone(nodes).into(),
707 Arc::unwrap_or_clone(state).into(),
708 prefix_sets,
709 );
710 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.provider().tx());
711 proof.overlay_multiproof_v2(input, targets).map_err(ProviderError::from)
712 })
713 }
714
715 fn witness(
716 &self,
717 input: TrieInput,
718 target: HashedPostState,
719 mode: ExecutionWitnessMode,
720 ) -> ProviderResult<Vec<alloy_primitives::Bytes>> {
721 reth_trie_db::with_adapter!(self.provider(), |A| {
722 let TrieInputSorted { nodes, state, prefix_sets } =
723 self.build_overlay(TrieInputSorted::from_unsorted(input), true)?;
724 let witness = TrieWitness::new(
725 InMemoryTrieCursorFactory::new(
726 DatabaseTrieCursorFactory::<_, A>::new(self.provider().tx()),
727 nodes.as_ref(),
728 ),
729 HashedPostStateCursorFactory::new(
730 DatabaseHashedCursorFactory::new(self.provider().tx()),
731 state.as_ref(),
732 ),
733 )
734 .with_prefix_sets_mut(prefix_sets)
735 .with_execution_witness_mode(mode);
736 let witness =
737 if mode.is_canonical() { witness } else { witness.always_include_root_node() };
738 let mut values: Vec<_> = witness.compute(target)?.into_values().collect();
739 if mode.is_canonical() {
740 values.sort_unstable();
741 }
742 Ok(values)
743 })
744 }
745}
746
747impl<Provider, N: NodePrimitives> HashedPostStateProvider for OverlayStateProvider<Provider, N>
748where
749 Provider: Deref,
750 Provider::Target: DBProvider
751 + StageCheckpointReader
752 + PruneCheckpointReader
753 + ChangeSetReader
754 + StorageChangeSetReader
755 + BlockNumReader
756 + StorageSettingsCache,
757{
758 fn hashed_post_state(
759 &self,
760 bundle_state: &revm::database::BundleState,
761 ) -> ProviderResult<HashedPostState> {
762 let mut hashed_state =
763 HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state());
764 if !bundle_state
765 .state()
766 .values()
767 .any(|account| account.was_destroyed() && account.original_info.is_some())
768 {
769 return Ok(hashed_state)
770 }
771
772 let overlay_state = self.build_overlay(TrieInputSorted::default(), true)?.state;
773 zero_destroyed_account_storage(
774 &HashedPostStateCursorFactory::new(
775 DatabaseHashedCursorFactory::new(self.provider().tx()),
776 overlay_state.as_ref(),
777 ),
778 bundle_state.state(),
779 &mut hashed_state,
780 )?;
781 Ok(hashed_state)
782 }
783}
784
785impl<Provider, N: NodePrimitives> StateProvider for OverlayStateProvider<Provider, N>
786where
787 Provider: Deref,
788 Provider::Target: DBProvider
789 + HistoryReader
790 + BlockHashReader
791 + StorageSettingsCache
792 + StageCheckpointReader
793 + PruneCheckpointReader
794 + ChangeSetReader
795 + StorageChangeSetReader
796 + BlockNumReader,
797{
798 fn storage(
799 &self,
800 address: Address,
801 storage_key: alloy_primitives::StorageKey,
802 ) -> ProviderResult<Option<alloy_primitives::StorageValue>> {
803 let (overlay, historical_fallback) = self.execution_overlay()?;
804 if let Some(value) = overlay.storage_value(address, U256::from_be_bytes(storage_key.0)) {
805 return Ok(Some(value));
806 }
807 if let Some(historical_fallback) = historical_fallback {
808 return match self.provider().storage_history_info(
809 address,
810 storage_key,
811 historical_fallback.block_number,
812 historical_fallback.storage_history_block_number,
813 )? {
814 HistoryInfo::NotYetWritten => Ok(None),
815 HistoryInfo::InChangeset(changeset_block_number) => self
816 .provider()
817 .get_storage_before_block(changeset_block_number, address, storage_key)?
818 .ok_or_else(|| ProviderError::StorageChangesetNotFound {
819 block_number: changeset_block_number,
820 address,
821 storage_key: Box::new(storage_key),
822 })
823 .map(|entry| Some(entry.value)),
824 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
825 self.storage_from_db(address, storage_key, true)
826 }
827 }
828 }
829 self.storage_from_db(address, storage_key, false)
830 }
831}
832
833impl<Provider, N: NodePrimitives> OverlayStateProvider<Provider, N>
834where
835 Provider: Deref,
836 Provider::Target: DBProvider + StorageSettingsCache,
837{
838 fn storage_from_db(
839 &self,
840 address: Address,
841 storage_key: alloy_primitives::StorageKey,
842 zero_if_missing: bool,
843 ) -> ProviderResult<Option<alloy_primitives::StorageValue>> {
844 if self.provider().cached_storage_settings().use_hashed_state() {
845 let hashed_address = alloy_primitives::keccak256(address);
846 let hashed_slot = alloy_primitives::keccak256(storage_key);
847 let mut cursor = self.provider().tx().cursor_dup_read::<tables::HashedStorages>()?;
848 let value = cursor
849 .seek_by_key_subkey(hashed_address, hashed_slot)?
850 .filter(|entry| entry.key == hashed_slot)
851 .map(|entry| entry.value);
852 Ok(value.or_else(|| zero_if_missing.then_some(U256::ZERO)))
853 } else {
854 let mut cursor = self.provider().tx().cursor_dup_read::<tables::PlainStorageState>()?;
855 if let Some(entry) = cursor.seek_by_key_subkey(address, storage_key)? &&
856 entry.key == storage_key
857 {
858 return Ok(Some(entry.value))
859 }
860 Ok(zero_if_missing.then_some(U256::ZERO))
861 }
862 }
863}
864
865impl<Provider, N: NodePrimitives> TrieCursorFactory for OverlayStateProvider<Provider, N>
866where
867 Provider: Deref,
868 Provider::Target: DBProvider
869 + StageCheckpointReader
870 + PruneCheckpointReader
871 + ChangeSetReader
872 + StorageChangeSetReader
873 + BlockNumReader
874 + StorageSettingsCache,
875{
876 type AccountTrieCursor<'a>
877 = InMemoryTrieCursor<'a, Box<dyn TrieCursor + Send + 'a>>
878 where
879 Self: 'a;
880
881 type StorageTrieCursor<'a>
882 = InMemoryTrieCursor<'a, Box<dyn TrieStorageCursor + Send + 'a>>
883 where
884 Self: 'a;
885
886 fn account_trie_cursor(&self) -> Result<Self::AccountTrieCursor<'_>, DatabaseError> {
887 let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
888 let cursor: Box<dyn TrieCursor + Send> = if self.is_v2 {
889 Box::new(DatabaseAccountTrieCursor::<_, PackedKeyAdapter>::new(
890 self.provider().tx().cursor_read::<PackedAccountsTrie>()?,
891 ))
892 } else {
893 Box::new(DatabaseAccountTrieCursor::<_, LegacyKeyAdapter>::new(
894 self.provider().tx().cursor_read::<tables::AccountsTrie>()?,
895 ))
896 };
897 Ok(InMemoryTrieCursor::new_account(cursor, &overlay.input().nodes))
898 }
899
900 fn storage_trie_cursor(
901 &self,
902 hashed_address: B256,
903 ) -> Result<Self::StorageTrieCursor<'_>, DatabaseError> {
904 let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
905 let cursor: Box<dyn TrieStorageCursor + Send> = if self.is_v2 {
906 Box::new(DatabaseStorageTrieCursor::<_, PackedKeyAdapter>::new(
907 self.provider().tx().cursor_dup_read::<PackedStoragesTrie>()?,
908 hashed_address,
909 ))
910 } else {
911 Box::new(DatabaseStorageTrieCursor::<_, LegacyKeyAdapter>::new(
912 self.provider().tx().cursor_dup_read::<tables::StoragesTrie>()?,
913 hashed_address,
914 ))
915 };
916 Ok(InMemoryTrieCursor::new_storage(cursor, &overlay.input().nodes, hashed_address))
917 }
918}
919
920impl<Provider, N: NodePrimitives> HashedCursorFactory for OverlayStateProvider<Provider, N>
921where
922 Provider: Deref,
923 Provider::Target: DBProvider
924 + StageCheckpointReader
925 + PruneCheckpointReader
926 + ChangeSetReader
927 + StorageChangeSetReader
928 + BlockNumReader
929 + StorageSettingsCache,
930{
931 type AccountCursor<'a>
932 = <HashedPostStateCursorFactory<
933 DatabaseHashedCursorFactory<&'a <Provider::Target as DbTxProvider>::Tx>,
934 &'a Arc<HashedPostStateSorted>,
935 > as HashedCursorFactory>::AccountCursor<'a>
936 where
937 Self: 'a;
938
939 type StorageCursor<'a>
940 = <HashedPostStateCursorFactory<
941 DatabaseHashedCursorFactory<&'a <Provider::Target as DbTxProvider>::Tx>,
942 &'a Arc<HashedPostStateSorted>,
943 > as HashedCursorFactory>::StorageCursor<'a>
944 where
945 Self: 'a;
946
947 fn hashed_account_cursor(&self) -> Result<Self::AccountCursor<'_>, DatabaseError> {
948 let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
949 HashedPostStateCursorFactory::new(
950 DatabaseHashedCursorFactory::new(self.provider().tx()),
951 &overlay.input().state,
952 )
953 .hashed_account_cursor()
954 }
955
956 fn hashed_storage_cursor(
957 &self,
958 hashed_address: B256,
959 ) -> Result<Self::StorageCursor<'_>, DatabaseError> {
960 let overlay = self.state_trie_overlay(true).map_err(into_database_error)?;
961 HashedPostStateCursorFactory::new(
962 DatabaseHashedCursorFactory::new(self.provider().tx()),
963 &overlay.input().state,
964 )
965 .hashed_storage_cursor(hashed_address)
966 }
967}
968
969#[derive(Clone, Metrics)]
971#[metrics(scope = "storage.providers.overlay")]
972pub(crate) struct OverlayStateProviderFactoryMetrics {
973 create_provider_duration: Histogram,
975 database_provider_ro_duration: Histogram,
977 state_trie_overlay_cache_misses: Counter,
979}
980
981type StateTrieOverlayCache = Arc<DashMap<(BlockHash, BlockHash, bool), StateTrieOverlay>>;
982
983#[derive(Clone, Debug)]
984struct CachedExecutionOverlay {
985 overlay: Arc<ExecutionOverlay>,
986 historical_fallback: Option<HistoricalFallback>,
987}
988
989#[derive(Clone, Copy, Debug)]
990struct HistoricalFallback {
991 block_number: BlockNumber,
992 account_history_block_number: Option<BlockNumber>,
993 storage_history_block_number: Option<BlockNumber>,
994}
995
996type DbStateRoot<'a, TX, A> =
997 StateRoot<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
998type DbStorageRoot<'a, TX, A> =
999 StorageRoot<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
1000type DbStorageProof<'a, TX, A> = TrieStorageProof<
1001 'static,
1002 DatabaseTrieCursorFactory<&'a TX, A>,
1003 DatabaseHashedCursorFactory<&'a TX>,
1004>;
1005type DbProof<'a, TX, A> =
1006 Proof<DatabaseTrieCursorFactory<&'a TX, A>, DatabaseHashedCursorFactory<&'a TX>>;
1007
1008#[doc(hidden)]
1009#[derive(Debug)]
1010pub struct OwnedProvider<Provider>(Provider);
1011
1012impl<Provider> Deref for OwnedProvider<Provider> {
1013 type Target = Provider;
1014
1015 fn deref(&self) -> &Self::Target {
1016 &self.0
1017 }
1018}
1019
1020fn into_database_error(error: ProviderError) -> DatabaseError {
1021 match error {
1022 ProviderError::Database(error) => error,
1023 error => DatabaseError::Other(error.to_string()),
1024 }
1025}
1026
1027#[cfg(test)]
1028mod tests {
1029 use super::*;
1030 use crate::{ExecutionOverlay, OverlayManager};
1031 use alloy_eips::BlockNumHash;
1032 use alloy_primitives::{Address, U256};
1033 use reth_chain_state::{test_utils::TestBlockBuilder, ExecutedBlock};
1034 use reth_db_api::{
1035 models::{
1036 storage_sharded_key::StorageShardedKey, AccountBeforeTx, BlockNumberAddress, ShardedKey,
1037 },
1038 tables,
1039 transaction::DbTxMut,
1040 BlockNumberList,
1041 };
1042 use reth_primitives_traits::Account;
1043 use reth_provider::{
1044 test_utils::{create_test_provider_factory, MockNodeTypesWithDB},
1045 BlockWriter, ProviderFactory,
1046 };
1047 use reth_stages_types::{FinishCheckpoint, StageCheckpoint, StageId};
1048 use reth_storage_api::StageCheckpointWriter;
1049 use reth_trie::{
1050 updates::TrieUpdatesSorted, BranchNodeCompact, HashedPostState, HashedStorage, Nibbles,
1051 };
1052 use revm::{bytecode::Bytecode as RevmBytecode, state::AccountInfo};
1053
1054 fn with_unique_trie_data(
1055 block: &ExecutedBlock<EthPrimitives>,
1056 id: u8,
1057 ) -> ExecutedBlock<EthPrimitives> {
1058 let hashed_address = B256::with_last_byte(id);
1059 let hashed_slot = B256::with_last_byte(id.saturating_add(32));
1060 let hashed_state = HashedPostState::default()
1061 .with_accounts([(hashed_address, Some(Account::default()))])
1062 .with_storages([(
1063 hashed_address,
1064 HashedStorage::from_iter([(hashed_slot, U256::from(id))]),
1065 )])
1066 .into_sorted();
1067 let trie_updates = TrieUpdatesSorted::new(
1068 vec![(
1069 Nibbles::from_nibbles([id]),
1070 Some(BranchNodeCompact::new(0, 0, 0, vec![], None)),
1071 )],
1072 Default::default(),
1073 );
1074
1075 ExecutedBlock::new(
1076 Arc::clone(&block.recovered_block),
1077 Arc::clone(&block.execution_output),
1078 Arc::new(hashed_state),
1079 Arc::new(trie_updates),
1080 )
1081 }
1082
1083 fn test_blocks() -> Vec<ExecutedBlock<EthPrimitives>> {
1084 TestBlockBuilder::eth()
1085 .get_executed_blocks(0..5)
1086 .enumerate()
1087 .map(|(index, block)| with_unique_trie_data(&block, index as u8 + 1))
1088 .collect()
1089 }
1090
1091 fn setup_frontiers(
1092 state_trie_tip_index: usize,
1093 finish_tip_index: usize,
1094 ) -> (ProviderFactory<MockNodeTypesWithDB>, Vec<ExecutedBlock<EthPrimitives>>) {
1095 let factory = create_test_provider_factory();
1096 let blocks = test_blocks();
1097 let provider_rw = factory.provider_rw().unwrap();
1098 for block in &blocks[..=finish_tip_index] {
1099 provider_rw.insert_block(block.recovered_block()).unwrap();
1100 }
1101 provider_rw
1102 .save_stage_checkpoint(
1103 StageId::Finish,
1104 StageCheckpoint::new(blocks[finish_tip_index].block_number())
1105 .with_finish_stage_checkpoint(FinishCheckpoint {
1106 partial_state_trie: Some(blocks[state_trie_tip_index].block_number()),
1107 }),
1108 )
1109 .unwrap();
1110 provider_rw.commit().unwrap();
1111
1112 (factory, blocks)
1113 }
1114
1115 fn account_keys(overlay: &StateTrieOverlay) -> Vec<B256> {
1116 overlay.input().state.accounts.iter().map(|(key, _)| *key).collect()
1117 }
1118
1119 fn account_node_paths(overlay: &StateTrieOverlay) -> Vec<Nibbles> {
1120 overlay.input().nodes.account_nodes_ref().iter().map(|(path, _)| *path).collect()
1121 }
1122
1123 #[test]
1124 fn overlay_cache_is_keyed_by_both_durable_frontiers() {
1125 let (factory, blocks) = setup_frontiers(1, 3);
1126 let manager = OverlayManager::default();
1127 for block in &blocks[2..=3] {
1128 manager.insert_block(block.clone());
1129 }
1130 let state_provider_factory = OverlayStateProviderFactory::new(
1131 factory.clone(),
1132 manager.overlay_builder(blocks[3].recovered_block().hash()),
1133 );
1134
1135 let provider = state_provider_factory.database_provider_ro().unwrap();
1136 let first = provider.state_trie_overlay(false).unwrap().clone();
1137 assert_eq!(account_keys(&first), vec![B256::with_last_byte(3), B256::with_last_byte(4)]);
1138 drop(provider);
1139
1140 let provider_rw = factory.provider_rw().unwrap();
1141 provider_rw
1142 .save_stage_checkpoint(
1143 StageId::Finish,
1144 StageCheckpoint::new(blocks[3].block_number()).with_finish_stage_checkpoint(
1145 FinishCheckpoint { partial_state_trie: Some(blocks[2].block_number()) },
1146 ),
1147 )
1148 .unwrap();
1149 provider_rw.commit().unwrap();
1150
1151 let provider = state_provider_factory.database_provider_ro().unwrap();
1152 let second = provider.state_trie_overlay(false).unwrap().clone();
1153 assert_eq!(account_keys(&second), vec![B256::with_last_byte(4)]);
1154 assert_eq!(account_node_paths(&second), vec![Nibbles::from_nibbles([4])]);
1155 assert_eq!(state_provider_factory.state_trie_overlay_cache.len(), 2);
1156 }
1157
1158 #[test]
1159 fn overlays_are_computed_lazily() {
1160 let (factory, blocks) = setup_frontiers(1, 3);
1161 let manager = OverlayManager::default();
1162 for block in &blocks[2..=3] {
1163 manager.insert_block(block.clone());
1164 }
1165 let state_provider_factory = OverlayStateProviderFactory::new(
1166 factory,
1167 manager.overlay_builder(blocks[3].recovered_block().hash()),
1168 );
1169
1170 let provider = state_provider_factory.database_provider_ro().unwrap();
1171
1172 assert!(provider.state_trie_overlay.get().is_none());
1173 assert!(provider.execution_overlay.get().is_none());
1174 assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1175
1176 provider.basic_account(&Address::ZERO).unwrap();
1177 assert!(provider.state_trie_overlay.get().is_none());
1178 assert!(provider.execution_overlay.get().is_some());
1179 assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1180
1181 provider.account_trie_cursor().unwrap();
1182 assert_eq!(state_provider_factory.state_trie_overlay_cache.len(), 1);
1183 }
1184
1185 #[test]
1186 fn state_trie_overlay_cache_is_keyed_by_trie_changesets() {
1187 let (factory, blocks) = setup_frontiers(1, 3);
1188 let manager = OverlayManager::default();
1189 for block in &blocks[2..=3] {
1190 manager.insert_block(block.clone());
1191 }
1192 let state_provider_factory = OverlayStateProviderFactory::new(
1193 factory,
1194 manager.overlay_builder(blocks[3].recovered_block().hash()),
1195 );
1196 let provider = state_provider_factory.database_provider_ro().unwrap();
1197
1198 provider.state_trie_overlay(false).unwrap();
1199 provider.state_trie_overlay(true).unwrap();
1200
1201 assert_eq!(state_provider_factory.state_trie_overlay_cache.len(), 2);
1202 }
1203
1204 #[test]
1205 fn supplied_state_trie_overlay_is_available_in_both_modes() {
1206 let (factory, _) = setup_frontiers(1, 1);
1207 let provider = factory.provider().unwrap();
1208 let provider = OverlayStateProvider::<&_, EthPrimitives>::new_with_state_trie(
1209 &provider,
1210 StateTrieOverlay::new(TrieInputSorted::default()),
1211 false,
1212 );
1213
1214 assert!(provider.state_trie_overlay(false).is_ok());
1215 assert!(provider.state_trie_overlay(true).is_ok());
1216 }
1217
1218 #[test]
1219 fn lazy_overlays_survive_manager_block_removal() {
1220 let (factory, blocks) = setup_frontiers(1, 1);
1221 let manager = OverlayManager::default();
1222 for block in &blocks[2..=3] {
1223 manager.insert_block(block.clone());
1224 }
1225 let state_provider_factory = OverlayStateProviderFactory::new(
1226 factory,
1227 manager.overlay_builder(blocks[3].recovered_block().hash()),
1228 );
1229 let provider = state_provider_factory.database_provider_ro().unwrap();
1230
1231 manager.remove_blocks(blocks[2..=3].iter().map(|block| block.recovered_block().hash()));
1232
1233 let (execution_overlay, _) = provider.execution_overlay().unwrap();
1234 assert_eq!(
1235 execution_overlay.block_hashes(),
1236 [blocks[2].recovered_block().num_hash(), blocks[3].recovered_block().num_hash()]
1237 );
1238 assert_eq!(
1239 account_keys(provider.state_trie_overlay(false).unwrap()),
1240 vec![B256::with_last_byte(3), B256::with_last_byte(4)]
1241 );
1242 }
1243
1244 #[test]
1245 fn skipped_state_trie_overlay_is_not_cached_or_used_for_state_roots() {
1246 let (factory, blocks) = setup_frontiers(3, 3);
1247 let manager = OverlayManager::default();
1248 manager.insert_block(blocks[4].clone());
1249 let state_provider_factory = OverlayStateProviderFactory::new(
1250 factory,
1251 manager
1252 .overlay_builder(blocks[4].recovered_block().hash())
1253 .with_skip_overlay_for_reused_sparse_trie(blocks[3].recovered_block().hash()),
1254 );
1255
1256 let provider = state_provider_factory.database_provider_ro().unwrap();
1257 assert!(provider.state_trie_overlay(false).unwrap().skipped_for_reused_sparse_trie());
1258 assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1259 assert!(matches!(
1260 provider.state_root(HashedPostState::default()),
1261 Err(ProviderError::UnsupportedProvider)
1262 ));
1263 assert!(state_provider_factory.state_trie_overlay_cache.is_empty());
1264 }
1265
1266 #[test]
1267 fn execution_overlay_readers_use_overlay_first() {
1268 let (factory, _) = setup_frontiers(1, 3);
1269 let address = Address::with_last_byte(1);
1270 let account_info = AccountInfo { nonce: 1, balance: U256::from(2), ..Default::default() };
1271 let block_hash = B256::with_last_byte(3);
1272 let storage_key = B256::with_last_byte(4);
1273 let storage_value = U256::from(5);
1274 let code_hash = B256::with_last_byte(6);
1275 let bytecode = RevmBytecode::new_raw([0x60, 0x01].into());
1276 let mut execution_overlay = ExecutionOverlay::default();
1277 execution_overlay.accounts_mut().insert(address, Some(account_info.clone()));
1278 execution_overlay.block_hashes_mut().push(BlockNumHash::new(1, block_hash));
1279 execution_overlay
1280 .storage_mut()
1281 .entry(address)
1282 .or_default()
1283 .insert(U256::from_be_bytes(storage_key.0), storage_value);
1284 execution_overlay.code_hashes_mut().insert(code_hash, bytecode.clone());
1285 let provider = OverlayStateProvider::<_, EthPrimitives>::new_with_execution(
1286 factory.provider().unwrap(),
1287 Arc::new(execution_overlay),
1288 false,
1289 );
1290
1291 assert_eq!(provider.basic_account(&address).unwrap(), Some(Account::from(account_info)));
1292 assert!(provider.basic_account(&Address::with_last_byte(2)).unwrap().is_none());
1293 assert_eq!(provider.block_hash(1).unwrap(), Some(block_hash));
1294 assert_eq!(provider.canonical_hashes_range(1, 2).unwrap(), vec![block_hash]);
1295 assert_eq!(provider.storage(address, storage_key).unwrap(), Some(storage_value));
1296 assert_eq!(
1297 provider.bytecode_by_hash(&code_hash).unwrap(),
1298 Some(reth_primitives_traits::Bytecode(bytecode))
1299 );
1300 }
1301
1302 #[test]
1303 #[allow(clippy::clone_on_copy)]
1304 fn historical_execution_reads_use_history_indexes() {
1305 let (factory, blocks) = setup_frontiers(1, 3);
1306 let address = Address::with_last_byte(1);
1307 let storage_key = B256::with_last_byte(2);
1308 let account = Account { balance: U256::from(10), ..Default::default() };
1309 let storage = U256::from(10);
1310 let provider_rw = factory.provider_rw().unwrap();
1311
1312 provider_rw
1313 .tx_ref()
1314 .put::<tables::AccountsHistory>(
1315 ShardedKey { key: address, highest_block_number: u64::MAX },
1316 BlockNumberList::new([2]).unwrap(),
1317 )
1318 .unwrap();
1319 provider_rw
1320 .tx_ref()
1321 .put::<tables::AccountChangeSets>(
1322 2,
1323 AccountBeforeTx { address, info: Some(account.clone()) },
1324 )
1325 .unwrap();
1326 provider_rw
1327 .tx_ref()
1328 .put::<tables::PlainAccountState>(
1329 address,
1330 Account { balance: U256::from(20), ..Default::default() },
1331 )
1332 .unwrap();
1333 provider_rw
1334 .tx_ref()
1335 .put::<tables::StoragesHistory>(
1336 StorageShardedKey {
1337 address,
1338 sharded_key: ShardedKey { key: storage_key, highest_block_number: u64::MAX },
1339 },
1340 BlockNumberList::new([2]).unwrap(),
1341 )
1342 .unwrap();
1343 provider_rw
1344 .tx_ref()
1345 .put::<tables::StorageChangeSets>(
1346 BlockNumberAddress((2, address)),
1347 reth_primitives_traits::StorageEntry { key: storage_key, value: storage },
1348 )
1349 .unwrap();
1350 provider_rw
1351 .tx_ref()
1352 .put::<tables::PlainStorageState>(
1353 address,
1354 reth_primitives_traits::StorageEntry { key: storage_key, value: U256::from(20) },
1355 )
1356 .unwrap();
1357 provider_rw.commit().unwrap();
1358
1359 let state_provider_factory = OverlayStateProviderFactory::<_, EthPrimitives>::new(
1360 factory,
1361 OverlayManager::default().overlay_builder(blocks[1].recovered_block().hash()),
1362 );
1363 let provider = state_provider_factory.database_provider_ro().unwrap();
1364
1365 assert_eq!(provider.basic_account(&address).unwrap(), Some(account));
1366 assert_eq!(provider.storage(address, storage_key).unwrap(), Some(storage));
1367 }
1368}