1use crate::{
2 AccountReader, BlockHashReader, ChangeSetReader, EitherReader, HashedPostStateProvider,
3 ProviderError, RocksDBProviderFactory, StateProvider, StateRootProvider,
4};
5use alloy_eips::merge::EPOCH_SLOTS;
6use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, StorageValue, B256};
7use reth_db_api::{
8 cursor::{DbCursorRO, DbDupCursorRO},
9 table::Table,
10 tables,
11 transaction::DbTx,
12 BlockNumberList,
13};
14use reth_primitives_traits::{Account, Bytecode, NodePrimitives};
15use reth_storage_api::{
16 BlockNumReader, BytecodeReader, DBProvider, NodePrimitivesProvider, PruneCheckpointReader,
17 StageCheckpointReader, StateProofProvider, StorageChangeSetReader, StorageRootProvider,
18 StorageSettingsCache,
19};
20use reth_storage_errors::provider::ProviderResult;
21use reth_storage_overlay::{Overlay, OverlayManager};
22use reth_trie::{
23 hashed_cursor::{zero_destroyed_account_storage, HashedPostStateCursorFactory},
24 proof::{Proof, StorageProof},
25 trie_cursor::InMemoryTrieCursorFactory,
26 updates::TrieUpdates,
27 witness::TrieWitness,
28 AccountProof, ExecutionWitnessMode, HashedPostState, HashedStorage, KeccakKeyHasher,
29 MultiProof, MultiProofTargets, StateRoot, StorageMultiProof, StorageRoot, TrieInput,
30 TrieInputSorted,
31};
32use reth_trie_db::{DatabaseProof, DatabaseStateRoot, DatabaseStorageProof, DatabaseStorageRoot};
33
34use std::{fmt::Debug, sync::Arc};
35
36type DbStateRoot<'a, TX, A> = StateRoot<
37 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
38 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
39>;
40type DbStorageRoot<'a, TX, A> = StorageRoot<
41 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
42 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
43>;
44type DbStorageProof<'a, TX, A> = StorageProof<
45 'static,
46 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
47 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
48>;
49type DbProof<'a, TX, A> = Proof<
50 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
51 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
52>;
53
54#[derive(Debug, Eq, PartialEq)]
58pub enum HistoryInfo {
59 NotYetWritten,
62 InChangeset(u64),
65 InPlainState,
68 MaybeInPlainState,
71}
72
73impl HistoryInfo {
74 pub const fn from_lookup(
85 found_block: Option<u64>,
86 is_before_first_write: bool,
87 lowest_available: Option<BlockNumber>,
88 ) -> Self {
89 if is_before_first_write {
90 if let (Some(_), Some(block_number)) = (lowest_available, found_block) {
91 return Self::InChangeset(block_number)
94 }
95 return Self::NotYetWritten
97 }
98
99 if let Some(block_number) = found_block {
100 Self::InChangeset(block_number)
102 } else {
103 Self::InPlainState
106 }
107 }
108}
109
110#[derive(Debug)]
122pub struct HistoricalStateProviderRef<
123 'b,
124 Provider,
125 N: NodePrimitives = <Provider as NodePrimitivesProvider>::Primitives,
126> where
127 Provider: NodePrimitivesProvider<Primitives = N>,
128{
129 provider: &'b Provider,
131 overlay_manager: OverlayManager<N>,
133 block_number: BlockNumber,
135 lowest_available_blocks: LowestAvailableBlocks,
137}
138
139impl<'b, Provider, N> HistoricalStateProviderRef<'b, Provider, N>
140where
141 Provider: DBProvider
142 + ChangeSetReader
143 + StorageChangeSetReader
144 + BlockNumReader
145 + NodePrimitivesProvider<Primitives = N>,
146 N: NodePrimitives,
147{
148 pub fn new(
150 provider: &'b Provider,
151 block_number: BlockNumber,
152 overlay_manager: OverlayManager<N>,
153 ) -> Self {
154 Self {
155 provider,
156 overlay_manager,
157 block_number,
158 lowest_available_blocks: Default::default(),
159 }
160 }
161
162 pub const fn new_with_lowest_available_blocks(
165 provider: &'b Provider,
166 block_number: BlockNumber,
167 lowest_available_blocks: LowestAvailableBlocks,
168 overlay_manager: OverlayManager<N>,
169 ) -> Self {
170 Self { provider, overlay_manager, block_number, lowest_available_blocks }
171 }
172
173 pub fn account_history_lookup(&self, address: Address) -> ProviderResult<HistoryInfo>
175 where
176 Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
177 {
178 if !self.lowest_available_blocks.is_account_history_available(self.block_number) {
179 return Err(ProviderError::StateAtBlockPruned(self.block_number))
180 }
181
182 let visible_tip = self.provider.best_block_number()?;
183
184 self.provider.with_rocksdb_snapshot(|rocksdb_ref| {
185 let mut reader = EitherReader::new_accounts_history(self.provider, rocksdb_ref)?;
186 reader.account_history_info(
187 address,
188 self.block_number,
189 self.lowest_available_blocks.account_history_block_number,
190 visible_tip,
191 )
192 })
193 }
194
195 pub fn storage_history_lookup(
199 &self,
200 address: Address,
201 lookup_key: B256,
202 ) -> ProviderResult<HistoryInfo>
203 where
204 Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
205 {
206 if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
207 return Err(ProviderError::StateAtBlockPruned(self.block_number))
208 }
209
210 let visible_tip = self.provider.best_block_number()?;
211
212 self.provider.with_rocksdb_snapshot(|rocksdb_ref| {
213 let mut reader = EitherReader::new_storages_history(self.provider, rocksdb_ref)?;
214 reader.storage_history_info(
215 address,
216 lookup_key,
217 self.block_number,
218 self.lowest_available_blocks.storage_history_block_number,
219 visible_tip,
220 )
221 })
222 }
223
224 fn storage_by_lookup_key(
229 &self,
230 address: Address,
231 lookup_key: B256,
232 ) -> ProviderResult<Option<StorageValue>>
233 where
234 Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
235 {
236 match self.storage_history_lookup(address, lookup_key)? {
237 HistoryInfo::NotYetWritten => Ok(None),
238 HistoryInfo::InChangeset(changeset_block_number) => self
239 .provider
240 .get_storage_before_block(changeset_block_number, address, lookup_key)?
241 .ok_or_else(|| ProviderError::StorageChangesetNotFound {
242 block_number: changeset_block_number,
243 address,
244 storage_key: Box::new(lookup_key),
245 })
246 .map(|entry| entry.value)
247 .map(Some),
248 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
249 if self.provider.cached_storage_settings().use_hashed_state() {
250 let hashed_address = alloy_primitives::keccak256(address);
251 let hashed_slot = alloy_primitives::keccak256(lookup_key);
252 Ok(self
253 .tx()
254 .cursor_dup_read::<tables::HashedStorages>()?
255 .seek_by_key_subkey(hashed_address, hashed_slot)?
256 .filter(|entry| entry.key == hashed_slot)
257 .map(|entry| entry.value)
258 .or(Some(StorageValue::ZERO)))
259 } else {
260 Ok(self
261 .tx()
262 .cursor_dup_read::<tables::PlainStorageState>()?
263 .seek_by_key_subkey(address, lookup_key)?
264 .filter(|entry| entry.key == lookup_key)
265 .map(|entry| entry.value)
266 .or(Some(StorageValue::ZERO)))
267 }
268 }
269 }
270 }
271
272 fn check_distance_against_limit(&self, limit: u64) -> ProviderResult<bool> {
274 let tip = self.provider.last_block_number()?;
275
276 Ok(tip.saturating_sub(self.block_number) > limit)
277 }
278
279 fn build_overlay(&self, input: TrieInputSorted) -> ProviderResult<TrieInputSorted>
280 where
281 Provider:
282 BlockHashReader + PruneCheckpointReader + StageCheckpointReader + StorageSettingsCache,
283 {
284 if self.check_distance_against_limit(EPOCH_SLOTS)? {
285 tracing::warn!(
286 target: "providers::historical_sp",
287 target = self.block_number,
288 "Attempt to calculate state root for an old block might result in OOM"
289 );
290 }
291
292 let target_block = self.block_number.saturating_sub(1);
295 let anchor_hash = self
296 .provider
297 .block_hash(target_block)?
298 .ok_or_else(|| ProviderError::HeaderNotFound(target_block.into()))?;
299
300 let TrieInputSorted { nodes, state, prefix_sets } = input;
301 let overlay_builder = self
302 .overlay_manager
303 .overlay_builder(anchor_hash)
304 .with_immediate_state_trie_overlay(state, nodes);
305 let Overlay { trie_updates, hashed_post_state } =
306 overlay_builder.build_overlay(self.provider)?;
307
308 Ok(TrieInputSorted::new(trie_updates, hashed_post_state, prefix_sets))
309 }
310
311 pub const fn with_lowest_available_account_history_block_number(
313 mut self,
314 block_number: BlockNumber,
315 ) -> Self {
316 self.lowest_available_blocks.account_history_block_number = Some(block_number);
317 self
318 }
319
320 pub const fn with_lowest_available_storage_history_block_number(
322 mut self,
323 block_number: BlockNumber,
324 ) -> Self {
325 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
326 self
327 }
328}
329
330impl<Provider, N> HistoricalStateProviderRef<'_, Provider, N>
331where
332 Provider: DBProvider + BlockNumReader + NodePrimitivesProvider<Primitives = N>,
333 N: NodePrimitives,
334{
335 fn tx(&self) -> &Provider::Tx {
336 self.provider.tx_ref()
337 }
338}
339
340impl<Provider, N> AccountReader for HistoricalStateProviderRef<'_, Provider, N>
341where
342 Provider: DBProvider
343 + BlockNumReader
344 + ChangeSetReader
345 + StorageChangeSetReader
346 + StorageSettingsCache
347 + RocksDBProviderFactory
348 + NodePrimitivesProvider<Primitives = N>,
349 N: NodePrimitives,
350{
351 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
353 match self.account_history_lookup(*address)? {
354 HistoryInfo::NotYetWritten => Ok(None),
355 HistoryInfo::InChangeset(changeset_block_number) => {
356 self.provider
358 .get_account_before_block(changeset_block_number, *address)?
359 .ok_or(ProviderError::AccountChangesetNotFound {
360 block_number: changeset_block_number,
361 address: *address,
362 })
363 .map(|account_before| account_before.info)
364 }
365 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
366 if self.provider.cached_storage_settings().use_hashed_state() {
367 let hashed_address = alloy_primitives::keccak256(address);
368 Ok(self.tx().get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)?)
369 } else {
370 Ok(self.tx().get_by_encoded_key::<tables::PlainAccountState>(address)?)
371 }
372 }
373 }
374 }
375}
376
377impl<Provider, N> BlockHashReader for HistoricalStateProviderRef<'_, Provider, N>
378where
379 Provider:
380 DBProvider + BlockNumReader + BlockHashReader + NodePrimitivesProvider<Primitives = N>,
381 N: NodePrimitives,
382{
383 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
385 self.provider.block_hash(number)
386 }
387
388 fn canonical_hashes_range(
389 &self,
390 start: BlockNumber,
391 end: BlockNumber,
392 ) -> ProviderResult<Vec<B256>> {
393 self.provider.canonical_hashes_range(start, end)
394 }
395}
396
397impl<Provider, N> StateRootProvider for HistoricalStateProviderRef<'_, Provider, N>
398where
399 Provider: DBProvider
400 + ChangeSetReader
401 + StorageChangeSetReader
402 + BlockNumReader
403 + BlockHashReader
404 + PruneCheckpointReader
405 + StageCheckpointReader
406 + StorageSettingsCache
407 + NodePrimitivesProvider<Primitives = N>,
408 N: NodePrimitives,
409{
410 fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
411 reth_trie_db::with_adapter!(self.provider, |A| {
412 let input = self.build_overlay(TrieInputSorted::from_unsorted(
413 TrieInput::from_state(hashed_state),
414 ))?;
415 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(self.tx(), input)?)
416 })
417 }
418
419 fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
420 reth_trie_db::with_adapter!(self.provider, |A| {
421 let input = self.build_overlay(TrieInputSorted::from_unsorted(input))?;
422 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(self.tx(), input)?)
423 })
424 }
425
426 fn state_root_with_updates(
427 &self,
428 hashed_state: HashedPostState,
429 ) -> ProviderResult<(B256, TrieUpdates)> {
430 reth_trie_db::with_adapter!(self.provider, |A| {
431 let input = self.build_overlay(TrieInputSorted::from_unsorted(
432 TrieInput::from_state(hashed_state),
433 ))?;
434 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(self.tx(), input)?)
435 })
436 }
437
438 fn state_root_from_nodes_with_updates(
439 &self,
440 input: TrieInput,
441 ) -> ProviderResult<(B256, TrieUpdates)> {
442 reth_trie_db::with_adapter!(self.provider, |A| {
443 let input = self.build_overlay(TrieInputSorted::from_unsorted(input))?;
444 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(self.tx(), input)?)
445 })
446 }
447}
448
449impl<Provider, N> StorageRootProvider for HistoricalStateProviderRef<'_, Provider, N>
450where
451 Provider: DBProvider
452 + ChangeSetReader
453 + StorageChangeSetReader
454 + BlockNumReader
455 + BlockHashReader
456 + PruneCheckpointReader
457 + StageCheckpointReader
458 + StorageSettingsCache
459 + NodePrimitivesProvider<Primitives = N>,
460 N: NodePrimitives,
461{
462 fn storage_root(
463 &self,
464 address: Address,
465 hashed_storage: HashedStorage,
466 ) -> ProviderResult<B256> {
467 reth_trie_db::with_adapter!(self.provider, |A| {
468 let input = self.build_overlay(TrieInputSorted::from_unsorted(
469 TrieInput::from_state(HashedPostState::from_hashed_storage(
470 alloy_primitives::keccak256(address),
471 hashed_storage,
472 )),
473 ))?;
474 let hashed_storage = input
475 .state
476 .account_storages()
477 .get(&alloy_primitives::keccak256(address))
478 .cloned()
479 .unwrap_or_default()
480 .into();
481 <DbStorageRoot<'_, _, A>>::overlay_root(self.tx(), address, hashed_storage)
482 .map_err(|err| ProviderError::Database(err.into()))
483 })
484 }
485
486 fn storage_proof(
487 &self,
488 address: Address,
489 slot: B256,
490 hashed_storage: HashedStorage,
491 ) -> ProviderResult<reth_trie::StorageProof> {
492 reth_trie_db::with_adapter!(self.provider, |A| {
493 let input = self.build_overlay(TrieInputSorted::from_unsorted(
494 TrieInput::from_state(HashedPostState::from_hashed_storage(
495 alloy_primitives::keccak256(address),
496 hashed_storage,
497 )),
498 ))?;
499 let hashed_storage = input
500 .state
501 .account_storages()
502 .get(&alloy_primitives::keccak256(address))
503 .cloned()
504 .unwrap_or_default()
505 .into();
506 <DbStorageProof<'_, _, A>>::overlay_storage_proof(
507 self.tx(),
508 address,
509 slot,
510 hashed_storage,
511 )
512 .map_err(ProviderError::from)
513 })
514 }
515
516 fn storage_multiproof(
517 &self,
518 address: Address,
519 slots: &[B256],
520 hashed_storage: HashedStorage,
521 ) -> ProviderResult<StorageMultiProof> {
522 reth_trie_db::with_adapter!(self.provider, |A| {
523 let input = self.build_overlay(TrieInputSorted::from_unsorted(
524 TrieInput::from_state(HashedPostState::from_hashed_storage(
525 alloy_primitives::keccak256(address),
526 hashed_storage,
527 )),
528 ))?;
529 let hashed_storage = input
530 .state
531 .account_storages()
532 .get(&alloy_primitives::keccak256(address))
533 .cloned()
534 .unwrap_or_default()
535 .into();
536 <DbStorageProof<'_, _, A>>::overlay_storage_multiproof(
537 self.tx(),
538 address,
539 slots,
540 hashed_storage,
541 )
542 .map_err(ProviderError::from)
543 })
544 }
545}
546
547impl<Provider, N> StateProofProvider for HistoricalStateProviderRef<'_, Provider, N>
548where
549 Provider: DBProvider
550 + ChangeSetReader
551 + StorageChangeSetReader
552 + BlockNumReader
553 + BlockHashReader
554 + PruneCheckpointReader
555 + StageCheckpointReader
556 + StorageSettingsCache
557 + NodePrimitivesProvider<Primitives = N>,
558 N: NodePrimitives,
559{
560 fn proof(
562 &self,
563 input: TrieInput,
564 address: Address,
565 slots: &[B256],
566 ) -> ProviderResult<AccountProof> {
567 reth_trie_db::with_adapter!(self.provider, |A| {
568 let TrieInputSorted { nodes, state, prefix_sets } =
569 self.build_overlay(TrieInputSorted::from_unsorted(input))?;
570 let input = TrieInput::new(
571 Arc::unwrap_or_clone(nodes).into(),
572 Arc::unwrap_or_clone(state).into(),
573 prefix_sets,
574 );
575 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.tx());
576 proof.overlay_account_proof(input, address, slots).map_err(ProviderError::from)
577 })
578 }
579
580 fn multiproof(
581 &self,
582 input: TrieInput,
583 targets: MultiProofTargets,
584 ) -> ProviderResult<MultiProof> {
585 reth_trie_db::with_adapter!(self.provider, |A| {
586 let TrieInputSorted { nodes, state, prefix_sets } =
587 self.build_overlay(TrieInputSorted::from_unsorted(input))?;
588 let input = TrieInput::new(
589 Arc::unwrap_or_clone(nodes).into(),
590 Arc::unwrap_or_clone(state).into(),
591 prefix_sets,
592 );
593 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.tx());
594 proof.overlay_multiproof(input, targets).map_err(ProviderError::from)
595 })
596 }
597
598 fn witness(
599 &self,
600 input: TrieInput,
601 target: HashedPostState,
602 mode: ExecutionWitnessMode,
603 ) -> ProviderResult<Vec<Bytes>> {
604 reth_trie_db::with_adapter!(self.provider, |A| {
605 let TrieInputSorted { nodes, state, prefix_sets } =
606 self.build_overlay(TrieInputSorted::from_unsorted(input))?;
607 let witness = TrieWitness::new(
608 InMemoryTrieCursorFactory::new(
609 reth_trie_db::DatabaseTrieCursorFactory::<_, A>::new(self.tx()),
610 nodes.as_ref(),
611 ),
612 HashedPostStateCursorFactory::new(
613 reth_trie_db::DatabaseHashedCursorFactory::new(self.tx()),
614 state.as_ref(),
615 ),
616 )
617 .with_prefix_sets_mut(prefix_sets)
618 .with_execution_witness_mode(mode);
619 let witness =
620 if mode.is_canonical() { witness } else { witness.always_include_root_node() };
621 witness.compute(target).map_err(ProviderError::from).map(|hm| {
622 let mut values: Vec<_> = hm.into_values().collect();
623 if mode.is_canonical() {
624 values.sort_unstable();
625 }
626 values
627 })
628 })
629 }
630}
631
632impl<Provider, N> HashedPostStateProvider for HistoricalStateProviderRef<'_, Provider, N>
633where
634 Provider: DBProvider
635 + ChangeSetReader
636 + StorageChangeSetReader
637 + BlockNumReader
638 + BlockHashReader
639 + PruneCheckpointReader
640 + StageCheckpointReader
641 + StorageSettingsCache
642 + NodePrimitivesProvider<Primitives = N>,
643 N: NodePrimitives,
644{
645 fn hashed_post_state(
646 &self,
647 bundle_state: &revm::database::BundleState,
648 ) -> ProviderResult<HashedPostState> {
649 let mut hashed_state =
650 HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state());
651 if !bundle_state
652 .state()
653 .values()
654 .any(|account| account.was_destroyed() && account.original_info.is_some())
655 {
656 return Ok(hashed_state)
657 }
658
659 let historical = self.build_overlay(TrieInputSorted::default())?.state;
660 zero_destroyed_account_storage(
661 &HashedPostStateCursorFactory::new(
662 reth_trie_db::DatabaseHashedCursorFactory::new(self.tx()),
663 historical.as_ref(),
664 ),
665 bundle_state.state(),
666 &mut hashed_state,
667 )?;
668 Ok(hashed_state)
669 }
670}
671
672impl<Provider, N> StateProvider for HistoricalStateProviderRef<'_, Provider, N>
673where
674 Provider: DBProvider
675 + BlockNumReader
676 + BlockHashReader
677 + ChangeSetReader
678 + StorageChangeSetReader
679 + PruneCheckpointReader
680 + StageCheckpointReader
681 + StorageSettingsCache
682 + RocksDBProviderFactory
683 + NodePrimitivesProvider<Primitives = N>,
684 N: NodePrimitives,
685{
686 fn storage(
688 &self,
689 address: Address,
690 storage_key: StorageKey,
691 ) -> ProviderResult<Option<StorageValue>> {
692 self.storage_by_lookup_key(address, storage_key)
693 }
694}
695
696impl<Provider, N> BytecodeReader for HistoricalStateProviderRef<'_, Provider, N>
697where
698 Provider: DBProvider + BlockNumReader + NodePrimitivesProvider<Primitives = N>,
699 N: NodePrimitives,
700{
701 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
703 self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
704 }
705}
706
707#[derive(Debug)]
710pub struct HistoricalStateProvider<Provider: NodePrimitivesProvider> {
711 provider: Provider,
713 overlay_manager: OverlayManager<Provider::Primitives>,
715 block_number: BlockNumber,
717 lowest_available_blocks: LowestAvailableBlocks,
719}
720
721impl<
722 Provider: DBProvider
723 + ChangeSetReader
724 + StorageChangeSetReader
725 + BlockNumReader
726 + NodePrimitivesProvider,
727 > HistoricalStateProvider<Provider>
728{
729 pub fn new(
731 provider: Provider,
732 block_number: BlockNumber,
733 overlay_manager: OverlayManager<Provider::Primitives>,
734 ) -> Self {
735 Self {
736 provider,
737 overlay_manager,
738 block_number,
739 lowest_available_blocks: Default::default(),
740 }
741 }
742
743 pub const fn with_lowest_available_account_history_block_number(
745 mut self,
746 block_number: BlockNumber,
747 ) -> Self {
748 self.lowest_available_blocks.account_history_block_number = Some(block_number);
749 self
750 }
751
752 pub const fn with_lowest_available_storage_history_block_number(
754 mut self,
755 block_number: BlockNumber,
756 ) -> Self {
757 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
758 self
759 }
760}
761
762impl<
763 Provider: DBProvider
764 + ChangeSetReader
765 + StorageChangeSetReader
766 + BlockNumReader
767 + NodePrimitivesProvider,
768 > HistoricalStateProvider<Provider>
769{
770 #[inline(always)]
772 fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
773 HistoricalStateProviderRef::new_with_lowest_available_blocks(
774 &self.provider,
775 self.block_number,
776 self.lowest_available_blocks,
777 self.overlay_manager.clone(),
778 )
779 }
780}
781
782reth_storage_api::macros::delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + ChangeSetReader + StorageChangeSetReader + PruneCheckpointReader + StageCheckpointReader + StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider]);
784
785#[derive(Clone, Copy, Debug, Default)]
788pub struct LowestAvailableBlocks {
789 pub account_history_block_number: Option<BlockNumber>,
793 pub storage_history_block_number: Option<BlockNumber>,
797}
798
799impl LowestAvailableBlocks {
800 pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
803 self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
804 }
805
806 pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
809 self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
810 }
811}
812
813#[inline]
825pub fn compute_history_rank(
826 chunk: &reth_db_api::BlockNumberList,
827 block_number: BlockNumber,
828) -> (u64, Option<u64>) {
829 let mut rank = chunk.rank(block_number);
830 if rank.checked_sub(1).and_then(|r| chunk.select(r)) == Some(block_number) {
834 rank -= 1;
835 }
836 (rank, chunk.select(rank))
837}
838
839#[inline]
844pub fn needs_prev_shard_check(
845 rank: u64,
846 found_block: Option<u64>,
847 block_number: BlockNumber,
848) -> bool {
849 rank == 0 && found_block != Some(block_number)
850}
851
852pub fn history_info<T, K, C>(
857 cursor: &mut C,
858 key: K,
859 block_number: BlockNumber,
860 key_filter: impl Fn(&K) -> bool,
861 lowest_available_block_number: Option<BlockNumber>,
862) -> ProviderResult<HistoryInfo>
863where
864 T: Table<Key = K, Value = BlockNumberList>,
865 C: DbCursorRO<T>,
866{
867 if let Some(chunk) = cursor.seek(key)?.filter(|(k, _)| key_filter(k)).map(|x| x.1) {
871 let (rank, found_block) = compute_history_rank(&chunk, block_number);
872
873 let is_before_first_write = needs_prev_shard_check(rank, found_block, block_number) &&
880 !cursor.prev()?.is_some_and(|(k, _)| key_filter(&k));
881
882 Ok(HistoryInfo::from_lookup(
883 found_block,
884 is_before_first_write,
885 lowest_available_block_number,
886 ))
887 } else if lowest_available_block_number.is_some() {
888 Ok(HistoryInfo::MaybeInPlainState)
891 } else {
892 Ok(HistoryInfo::NotYetWritten)
894 }
895}
896
897#[cfg(test)]
898mod tests {
899 use super::needs_prev_shard_check;
900 use crate::{
901 providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
902 test_utils::create_test_provider_factory,
903 AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, RocksDBProviderFactory,
904 StateProvider,
905 };
906 use alloy_primitives::{address, b256, Address, B256, U256};
907 use reth_db_api::{
908 models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
909 tables,
910 transaction::{DbTx, DbTxMut},
911 BlockNumberList,
912 };
913 use reth_primitives_traits::{Account, StorageEntry};
914 use reth_storage_api::{
915 BlockHashReader, BlockNumReader, ChangeSetReader, DBProvider, DatabaseProviderFactory,
916 NodePrimitivesProvider, PruneCheckpointReader, StageCheckpointReader,
917 StorageChangeSetReader, StorageSettingsCache,
918 };
919 use reth_storage_errors::provider::ProviderError;
920 use reth_storage_overlay::OverlayManager;
921
922 const ADDRESS: Address = address!("0x0000000000000000000000000000000000000001");
923 const HIGHER_ADDRESS: Address = address!("0x0000000000000000000000000000000000000005");
924 const STORAGE: B256 =
925 b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
926
927 const fn assert_state_provider<T: StateProvider>() {}
928 #[expect(dead_code)]
929 const fn assert_historical_state_provider<
930 T: DBProvider
931 + BlockNumReader
932 + BlockHashReader
933 + ChangeSetReader
934 + StorageChangeSetReader
935 + PruneCheckpointReader
936 + StageCheckpointReader
937 + StorageSettingsCache
938 + RocksDBProviderFactory
939 + NodePrimitivesProvider,
940 >() {
941 assert_state_provider::<HistoricalStateProvider<T>>();
942 }
943
944 #[test]
945 fn history_provider_get_account() {
946 let factory = create_test_provider_factory();
947 let tx = factory.provider_rw().unwrap().into_tx();
948
949 tx.put::<tables::AccountsHistory>(
950 ShardedKey { key: ADDRESS, highest_block_number: 7 },
951 BlockNumberList::new([1, 3, 7]).unwrap(),
952 )
953 .unwrap();
954 tx.put::<tables::AccountsHistory>(
955 ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
956 BlockNumberList::new([10, 15]).unwrap(),
957 )
958 .unwrap();
959 tx.put::<tables::AccountsHistory>(
960 ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
961 BlockNumberList::new([4]).unwrap(),
962 )
963 .unwrap();
964
965 let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
966 let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
967 let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
968 let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
969 let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
970
971 let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
972
973 tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
975 .unwrap();
976 tx.put::<tables::AccountChangeSets>(
977 3,
978 AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
979 )
980 .unwrap();
981 tx.put::<tables::AccountChangeSets>(
982 4,
983 AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
984 )
985 .unwrap();
986 tx.put::<tables::AccountChangeSets>(
987 7,
988 AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
989 )
990 .unwrap();
991 tx.put::<tables::AccountChangeSets>(
992 10,
993 AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
994 )
995 .unwrap();
996 tx.put::<tables::AccountChangeSets>(
997 15,
998 AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
999 )
1000 .unwrap();
1001
1002 tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
1004 tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
1005 tx.commit().unwrap();
1006
1007 let db = factory.provider().unwrap();
1008
1009 assert!(matches!(
1011 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1012 .basic_account(&ADDRESS),
1013 Ok(None)
1014 ));
1015 assert!(matches!(
1016 HistoricalStateProviderRef::new(&db, 2, OverlayManager::default()).basic_account(&ADDRESS),
1017 Ok(Some(acc)) if acc == acc_at3
1018 ));
1019 assert!(matches!(
1020 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default()).basic_account(&ADDRESS),
1021 Ok(Some(acc)) if acc == acc_at3
1022 ));
1023 assert!(matches!(
1024 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).basic_account(&ADDRESS),
1025 Ok(Some(acc)) if acc == acc_at7
1026 ));
1027 assert!(matches!(
1028 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).basic_account(&ADDRESS),
1029 Ok(Some(acc)) if acc == acc_at7
1030 ));
1031 assert!(matches!(
1032 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).basic_account(&ADDRESS),
1033 Ok(Some(acc)) if acc == acc_at10
1034 ));
1035 assert!(matches!(
1036 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).basic_account(&ADDRESS),
1037 Ok(Some(acc)) if acc == acc_at10
1038 ));
1039 assert!(matches!(
1040 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).basic_account(&ADDRESS),
1041 Ok(Some(acc)) if acc == acc_at15
1042 ));
1043 assert!(matches!(
1044 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).basic_account(&ADDRESS),
1045 Ok(Some(acc)) if acc == acc_plain
1046 ));
1047
1048 assert!(matches!(
1049 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1050 .basic_account(&HIGHER_ADDRESS),
1051 Ok(None)
1052 ));
1053 assert!(matches!(
1054 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).basic_account(&HIGHER_ADDRESS),
1055 Ok(Some(acc)) if acc == higher_acc_plain
1056 ));
1057 }
1058
1059 #[test]
1060 fn history_provider_get_storage() {
1061 let factory = create_test_provider_factory();
1062 let tx = factory.provider_rw().unwrap().into_tx();
1063
1064 tx.put::<tables::StoragesHistory>(
1065 StorageShardedKey {
1066 address: ADDRESS,
1067 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1068 },
1069 BlockNumberList::new([3, 7]).unwrap(),
1070 )
1071 .unwrap();
1072 tx.put::<tables::StoragesHistory>(
1073 StorageShardedKey {
1074 address: ADDRESS,
1075 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1076 },
1077 BlockNumberList::new([10, 15]).unwrap(),
1078 )
1079 .unwrap();
1080 tx.put::<tables::StoragesHistory>(
1081 StorageShardedKey {
1082 address: HIGHER_ADDRESS,
1083 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1084 },
1085 BlockNumberList::new([4]).unwrap(),
1086 )
1087 .unwrap();
1088
1089 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1090 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1091 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1092 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1093 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1094 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1095 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1096
1097 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1099 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1100 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1101 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1102 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1103
1104 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1106 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1107 tx.commit().unwrap();
1108
1109 let db = factory.provider().unwrap();
1110
1111 assert!(matches!(
1113 HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1114 .storage(ADDRESS, STORAGE),
1115 Ok(None)
1116 ));
1117 assert!(matches!(
1118 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1119 .storage(ADDRESS, STORAGE),
1120 Ok(Some(U256::ZERO))
1121 ));
1122 assert!(matches!(
1123 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1124 Ok(Some(expected_value)) if expected_value == entry_at7.value
1125 ));
1126 assert!(matches!(
1127 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1128 Ok(Some(expected_value)) if expected_value == entry_at7.value
1129 ));
1130 assert!(matches!(
1131 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1132 Ok(Some(expected_value)) if expected_value == entry_at10.value
1133 ));
1134 assert!(matches!(
1135 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1136 Ok(Some(expected_value)) if expected_value == entry_at10.value
1137 ));
1138 assert!(matches!(
1139 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1140 Ok(Some(expected_value)) if expected_value == entry_at15.value
1141 ));
1142 assert!(matches!(
1143 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1144 Ok(Some(expected_value)) if expected_value == entry_plain.value
1145 ));
1146 assert!(matches!(
1147 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1148 .storage(HIGHER_ADDRESS, STORAGE),
1149 Ok(None)
1150 ));
1151 assert!(matches!(
1152 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1153 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1154 ));
1155 }
1156
1157 #[test]
1158 fn history_provider_unavailable() {
1159 let factory = create_test_provider_factory();
1160 let db = factory.database_provider_rw().unwrap();
1161
1162 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1165 &db,
1166 2,
1167 LowestAvailableBlocks {
1168 account_history_block_number: Some(3),
1169 storage_history_block_number: Some(3),
1170 },
1171 OverlayManager::default(),
1172 );
1173 assert!(matches!(
1174 provider.account_history_lookup(ADDRESS),
1175 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1176 ));
1177 assert!(matches!(
1178 provider.storage_history_lookup(ADDRESS, STORAGE),
1179 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1180 ));
1181
1182 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1185 &db,
1186 2,
1187 LowestAvailableBlocks {
1188 account_history_block_number: Some(2),
1189 storage_history_block_number: Some(2),
1190 },
1191 OverlayManager::default(),
1192 );
1193 assert!(matches!(
1194 provider.account_history_lookup(ADDRESS),
1195 Ok(HistoryInfo::MaybeInPlainState)
1196 ));
1197 assert!(matches!(
1198 provider.storage_history_lookup(ADDRESS, STORAGE),
1199 Ok(HistoryInfo::MaybeInPlainState)
1200 ));
1201
1202 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1205 &db,
1206 2,
1207 LowestAvailableBlocks {
1208 account_history_block_number: Some(1),
1209 storage_history_block_number: Some(1),
1210 },
1211 OverlayManager::default(),
1212 );
1213 assert!(matches!(
1214 provider.account_history_lookup(ADDRESS),
1215 Ok(HistoryInfo::MaybeInPlainState)
1216 ));
1217 assert!(matches!(
1218 provider.storage_history_lookup(ADDRESS, STORAGE),
1219 Ok(HistoryInfo::MaybeInPlainState)
1220 ));
1221 }
1222
1223 #[test]
1224 fn test_history_info_from_lookup() {
1225 assert_eq!(HistoryInfo::from_lookup(Some(10), true, None), HistoryInfo::NotYetWritten);
1227 assert_eq!(HistoryInfo::from_lookup(None, true, None), HistoryInfo::NotYetWritten);
1228
1229 assert_eq!(HistoryInfo::from_lookup(Some(10), true, Some(5)), HistoryInfo::InChangeset(10));
1231 assert_eq!(HistoryInfo::from_lookup(None, true, Some(5)), HistoryInfo::NotYetWritten);
1232
1233 assert_eq!(HistoryInfo::from_lookup(Some(10), false, None), HistoryInfo::InChangeset(10));
1235 assert_eq!(HistoryInfo::from_lookup(None, false, None), HistoryInfo::InPlainState);
1236 }
1237
1238 #[test]
1239 fn history_provider_get_storage_legacy() {
1240 let factory = create_test_provider_factory();
1241
1242 assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
1243
1244 let tx = factory.provider_rw().unwrap().into_tx();
1245
1246 tx.put::<tables::StoragesHistory>(
1247 StorageShardedKey {
1248 address: ADDRESS,
1249 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1250 },
1251 BlockNumberList::new([3, 7]).unwrap(),
1252 )
1253 .unwrap();
1254 tx.put::<tables::StoragesHistory>(
1255 StorageShardedKey {
1256 address: ADDRESS,
1257 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1258 },
1259 BlockNumberList::new([10, 15]).unwrap(),
1260 )
1261 .unwrap();
1262 tx.put::<tables::StoragesHistory>(
1263 StorageShardedKey {
1264 address: HIGHER_ADDRESS,
1265 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1266 },
1267 BlockNumberList::new([4]).unwrap(),
1268 )
1269 .unwrap();
1270
1271 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1272 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1273 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1274 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1275 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1276 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1277 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1278
1279 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1280 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1281 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1282 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1283 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1284
1285 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1286 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1287 tx.commit().unwrap();
1288
1289 let db = factory.provider().unwrap();
1290
1291 assert!(matches!(
1292 HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1293 .storage(ADDRESS, STORAGE),
1294 Ok(None)
1295 ));
1296 assert!(matches!(
1297 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1298 .storage(ADDRESS, STORAGE),
1299 Ok(Some(U256::ZERO))
1300 ));
1301 assert!(matches!(
1302 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1303 Ok(Some(expected_value)) if expected_value == entry_at7.value
1304 ));
1305 assert!(matches!(
1306 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1307 Ok(Some(expected_value)) if expected_value == entry_at7.value
1308 ));
1309 assert!(matches!(
1310 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1311 Ok(Some(expected_value)) if expected_value == entry_at10.value
1312 ));
1313 assert!(matches!(
1314 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1315 Ok(Some(expected_value)) if expected_value == entry_at10.value
1316 ));
1317 assert!(matches!(
1318 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1319 Ok(Some(expected_value)) if expected_value == entry_at15.value
1320 ));
1321 assert!(matches!(
1322 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1323 Ok(Some(expected_value)) if expected_value == entry_plain.value
1324 ));
1325 assert!(matches!(
1326 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1327 .storage(HIGHER_ADDRESS, STORAGE),
1328 Ok(None)
1329 ));
1330 assert!(matches!(
1331 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1332 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1333 ));
1334 }
1335
1336 #[test]
1337 fn history_provider_get_storage_hashed_state() {
1338 use crate::BlockWriter;
1339 use alloy_primitives::keccak256;
1340 use reth_db_api::models::StorageSettings;
1341 use reth_execution_types::ExecutionOutcome;
1342 use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
1343 use revm::database::BundleState;
1344 use std::collections::HashMap;
1345
1346 let factory = create_test_provider_factory();
1347 factory.set_storage_settings_cache(StorageSettings::v2());
1348
1349 let slot = U256::from_be_bytes(*STORAGE);
1350 let account: revm::state::AccountInfo =
1351 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None }.into();
1352 let higher_account: revm::state::AccountInfo =
1353 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None }.into();
1354
1355 let mut rng = generators::rng();
1356 let blocks = random_block_range(
1357 &mut rng,
1358 0..=15,
1359 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1360 );
1361
1362 let mut addr_storage = HashMap::default();
1363 addr_storage.insert(slot, (U256::ZERO, U256::from(100)));
1364 let mut higher_storage = HashMap::default();
1365 higher_storage.insert(slot, (U256::ZERO, U256::from(1000)));
1366
1367 type Revert = Vec<(Address, Option<Option<revm::state::AccountInfo>>, Vec<(U256, U256)>)>;
1368 let mut reverts: Vec<Revert> = vec![Vec::new(); 16];
1369
1370 reverts[3] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::ZERO)])];
1371 reverts[4] =
1372 vec![(HIGHER_ADDRESS, Some(Some(higher_account.clone())), vec![(slot, U256::ZERO)])];
1373 reverts[7] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(7))])];
1374 reverts[10] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(10))])];
1375 reverts[15] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(15))])];
1376
1377 let bundle = BundleState::new(
1378 [
1379 (ADDRESS, None, Some(account), addr_storage),
1380 (HIGHER_ADDRESS, None, Some(higher_account), higher_storage),
1381 ],
1382 reverts,
1383 [],
1384 );
1385
1386 let provider_rw = factory.provider_rw().unwrap();
1387 provider_rw
1388 .append_blocks_with_state(
1389 blocks
1390 .into_iter()
1391 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1392 .collect(),
1393 &ExecutionOutcome { bundle, first_block: 0, ..Default::default() },
1394 Default::default(),
1395 )
1396 .unwrap();
1397
1398 let hashed_address = keccak256(ADDRESS);
1399 let hashed_higher_address = keccak256(HIGHER_ADDRESS);
1400 let hashed_storage = keccak256(STORAGE);
1401
1402 provider_rw
1403 .tx_ref()
1404 .put::<tables::HashedStorages>(
1405 hashed_address,
1406 StorageEntry { key: hashed_storage, value: U256::from(100) },
1407 )
1408 .unwrap();
1409 provider_rw
1410 .tx_ref()
1411 .put::<tables::HashedStorages>(
1412 hashed_higher_address,
1413 StorageEntry { key: hashed_storage, value: U256::from(1000) },
1414 )
1415 .unwrap();
1416 provider_rw
1417 .tx_ref()
1418 .put::<tables::HashedAccounts>(
1419 hashed_address,
1420 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None },
1421 )
1422 .unwrap();
1423 provider_rw
1424 .tx_ref()
1425 .put::<tables::HashedAccounts>(
1426 hashed_higher_address,
1427 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None },
1428 )
1429 .unwrap();
1430 provider_rw.commit().unwrap();
1431
1432 let db = factory.provider().unwrap();
1433
1434 assert!(matches!(
1435 HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1436 .storage(ADDRESS, STORAGE),
1437 Ok(None)
1438 ));
1439 assert!(matches!(
1440 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1441 .storage(ADDRESS, STORAGE),
1442 Ok(Some(U256::ZERO))
1443 ));
1444 assert!(matches!(
1445 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1446 Ok(Some(v)) if v == U256::from(7)
1447 ));
1448 assert!(matches!(
1449 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1450 Ok(Some(v)) if v == U256::from(7)
1451 ));
1452 assert!(matches!(
1453 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1454 Ok(Some(v)) if v == U256::from(10)
1455 ));
1456 assert!(matches!(
1457 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1458 Ok(Some(v)) if v == U256::from(10)
1459 ));
1460 assert!(matches!(
1461 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1462 Ok(Some(v)) if v == U256::from(15)
1463 ));
1464 assert!(matches!(
1465 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1466 Ok(Some(v)) if v == U256::from(100)
1467 ));
1468 assert!(matches!(
1469 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1470 .storage(HIGHER_ADDRESS, STORAGE),
1471 Ok(None)
1472 ));
1473 assert!(matches!(
1474 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1475 Ok(Some(v)) if v == U256::from(1000)
1476 ));
1477 }
1478
1479 #[test]
1480 fn destroyed_storage_zeros_use_historical_state() {
1481 use crate::BlockWriter;
1482 use alloy_primitives::{keccak256, map::HashMap};
1483 use reth_execution_types::ExecutionOutcome;
1484 use reth_stages_types::{StageCheckpoint, StageId};
1485 use reth_storage_api::{HashedPostStateProvider, StageCheckpointWriter};
1486 use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
1487 use revm::{
1488 database::{AccountStatus, BundleAccount, BundleState},
1489 state::AccountInfo,
1490 };
1491
1492 let factory = create_test_provider_factory();
1493 let slot = U256::from(1);
1494 let old_value = U256::from(2);
1495 let account = AccountInfo::default();
1496 let blocks = random_block_range(
1497 &mut generators::rng(),
1498 0..=1,
1499 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1500 );
1501 let mut reverts = vec![Vec::new(); 2];
1502 reverts[1] = vec![(ADDRESS, None, vec![(slot, old_value)])];
1503 let bundle = BundleState::new(
1504 [(
1505 ADDRESS,
1506 Some(account.clone()),
1507 Some(account.clone()),
1508 HashMap::from_iter([(slot, (old_value, U256::ZERO))]),
1509 )],
1510 reverts,
1511 [],
1512 );
1513
1514 let provider_rw = factory.provider_rw().unwrap();
1515 provider_rw
1516 .append_blocks_with_state(
1517 blocks
1518 .into_iter()
1519 .map(|block| block.try_recover().expect("failed to seal block with senders"))
1520 .collect(),
1521 &ExecutionOutcome { bundle, first_block: 0, ..Default::default() },
1522 Default::default(),
1523 )
1524 .unwrap();
1525 provider_rw.save_stage_checkpoint(StageId::Finish, StageCheckpoint::new(1)).unwrap();
1526 provider_rw.commit().unwrap();
1527
1528 let db = factory.provider().unwrap();
1529 let hashed_address = keccak256(ADDRESS);
1530 assert!(db.tx_ref().get::<tables::HashedStorages>(hashed_address).unwrap().is_none());
1531
1532 let mut destroyed_bundle = BundleState::default();
1533 destroyed_bundle.state.insert(
1534 ADDRESS,
1535 BundleAccount::new(Some(account), None, Default::default(), AccountStatus::Destroyed),
1536 );
1537 let provider = HistoricalStateProviderRef::new(&db, 1, OverlayManager::default());
1538 let hashed_state = provider.hashed_post_state(&destroyed_bundle).unwrap();
1539
1540 assert_eq!(
1541 hashed_state.storages[&hashed_address].storage[&keccak256(B256::from(slot))],
1542 U256::ZERO
1543 );
1544 }
1545
1546 #[test]
1547 fn newly_created_destroyed_account_skips_historical_overlay() {
1548 use reth_storage_api::HashedPostStateProvider;
1549 use revm::database::{AccountStatus, BundleAccount, BundleState};
1550
1551 let factory = create_test_provider_factory();
1552 let db = factory.provider().unwrap();
1553 let mut bundle = BundleState::default();
1554 bundle.state.insert(
1555 ADDRESS,
1556 BundleAccount::new(None, None, Default::default(), AccountStatus::Destroyed),
1557 );
1558
1559 let provider = HistoricalStateProviderRef::new(&db, 1, OverlayManager::default());
1560 let hashed_state = provider.hashed_post_state(&bundle).unwrap();
1561
1562 assert!(hashed_state.storages.is_empty());
1563 }
1564
1565 #[test]
1566 fn test_needs_prev_shard_check() {
1567 assert!(needs_prev_shard_check(0, Some(10), 5));
1569 assert!(needs_prev_shard_check(0, None, 5));
1570 assert!(!needs_prev_shard_check(0, Some(5), 5)); assert!(!needs_prev_shard_check(1, Some(10), 5)); }
1573}