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