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::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: NodePrimitivesProvider<Primitives = N>,
635 N: NodePrimitives,
636{
637 fn hashed_post_state(&self, bundle_state: &revm::database::BundleState) -> HashedPostState {
638 HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
639 }
640}
641
642impl<Provider, N> StateProvider for HistoricalStateProviderRef<'_, Provider, N>
643where
644 Provider: DBProvider
645 + BlockNumReader
646 + BlockHashReader
647 + ChangeSetReader
648 + StorageChangeSetReader
649 + PruneCheckpointReader
650 + StageCheckpointReader
651 + StorageSettingsCache
652 + RocksDBProviderFactory
653 + NodePrimitivesProvider<Primitives = N>,
654 N: NodePrimitives,
655{
656 fn storage(
658 &self,
659 address: Address,
660 storage_key: StorageKey,
661 ) -> ProviderResult<Option<StorageValue>> {
662 self.storage_by_lookup_key(address, storage_key)
663 }
664}
665
666impl<Provider, N> BytecodeReader for HistoricalStateProviderRef<'_, Provider, N>
667where
668 Provider: DBProvider + BlockNumReader + NodePrimitivesProvider<Primitives = N>,
669 N: NodePrimitives,
670{
671 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
673 self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
674 }
675}
676
677#[derive(Debug)]
680pub struct HistoricalStateProvider<Provider: NodePrimitivesProvider> {
681 provider: Provider,
683 overlay_manager: OverlayManager<Provider::Primitives>,
685 block_number: BlockNumber,
687 lowest_available_blocks: LowestAvailableBlocks,
689}
690
691impl<
692 Provider: DBProvider
693 + ChangeSetReader
694 + StorageChangeSetReader
695 + BlockNumReader
696 + NodePrimitivesProvider,
697 > HistoricalStateProvider<Provider>
698{
699 pub fn new(
701 provider: Provider,
702 block_number: BlockNumber,
703 overlay_manager: OverlayManager<Provider::Primitives>,
704 ) -> Self {
705 Self {
706 provider,
707 overlay_manager,
708 block_number,
709 lowest_available_blocks: Default::default(),
710 }
711 }
712
713 pub const fn with_lowest_available_account_history_block_number(
715 mut self,
716 block_number: BlockNumber,
717 ) -> Self {
718 self.lowest_available_blocks.account_history_block_number = Some(block_number);
719 self
720 }
721
722 pub const fn with_lowest_available_storage_history_block_number(
724 mut self,
725 block_number: BlockNumber,
726 ) -> Self {
727 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
728 self
729 }
730}
731
732impl<
733 Provider: DBProvider
734 + ChangeSetReader
735 + StorageChangeSetReader
736 + BlockNumReader
737 + NodePrimitivesProvider,
738 > HistoricalStateProvider<Provider>
739{
740 #[inline(always)]
742 fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
743 HistoricalStateProviderRef::new_with_lowest_available_blocks(
744 &self.provider,
745 self.block_number,
746 self.lowest_available_blocks,
747 self.overlay_manager.clone(),
748 )
749 }
750}
751
752reth_storage_api::macros::delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + ChangeSetReader + StorageChangeSetReader + PruneCheckpointReader + StageCheckpointReader + StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider]);
754
755#[derive(Clone, Copy, Debug, Default)]
758pub struct LowestAvailableBlocks {
759 pub account_history_block_number: Option<BlockNumber>,
763 pub storage_history_block_number: Option<BlockNumber>,
767}
768
769impl LowestAvailableBlocks {
770 pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
773 self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
774 }
775
776 pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
779 self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
780 }
781}
782
783#[inline]
795pub fn compute_history_rank(
796 chunk: &reth_db_api::BlockNumberList,
797 block_number: BlockNumber,
798) -> (u64, Option<u64>) {
799 let mut rank = chunk.rank(block_number);
800 if rank.checked_sub(1).and_then(|r| chunk.select(r)) == Some(block_number) {
804 rank -= 1;
805 }
806 (rank, chunk.select(rank))
807}
808
809#[inline]
814pub fn needs_prev_shard_check(
815 rank: u64,
816 found_block: Option<u64>,
817 block_number: BlockNumber,
818) -> bool {
819 rank == 0 && found_block != Some(block_number)
820}
821
822pub fn history_info<T, K, C>(
827 cursor: &mut C,
828 key: K,
829 block_number: BlockNumber,
830 key_filter: impl Fn(&K) -> bool,
831 lowest_available_block_number: Option<BlockNumber>,
832) -> ProviderResult<HistoryInfo>
833where
834 T: Table<Key = K, Value = BlockNumberList>,
835 C: DbCursorRO<T>,
836{
837 if let Some(chunk) = cursor.seek(key)?.filter(|(k, _)| key_filter(k)).map(|x| x.1) {
841 let (rank, found_block) = compute_history_rank(&chunk, block_number);
842
843 let is_before_first_write = needs_prev_shard_check(rank, found_block, block_number) &&
850 !cursor.prev()?.is_some_and(|(k, _)| key_filter(&k));
851
852 Ok(HistoryInfo::from_lookup(
853 found_block,
854 is_before_first_write,
855 lowest_available_block_number,
856 ))
857 } else if lowest_available_block_number.is_some() {
858 Ok(HistoryInfo::MaybeInPlainState)
861 } else {
862 Ok(HistoryInfo::NotYetWritten)
864 }
865}
866
867#[cfg(test)]
868mod tests {
869 use super::needs_prev_shard_check;
870 use crate::{
871 providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
872 test_utils::create_test_provider_factory,
873 AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, RocksDBProviderFactory,
874 StateProvider,
875 };
876 use alloy_primitives::{address, b256, Address, B256, U256};
877 use reth_db_api::{
878 models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
879 tables,
880 transaction::{DbTx, DbTxMut},
881 BlockNumberList,
882 };
883 use reth_primitives_traits::{Account, StorageEntry};
884 use reth_storage_api::{
885 BlockHashReader, BlockNumReader, ChangeSetReader, DBProvider, DatabaseProviderFactory,
886 NodePrimitivesProvider, PruneCheckpointReader, StageCheckpointReader,
887 StorageChangeSetReader, StorageSettingsCache,
888 };
889 use reth_storage_errors::provider::ProviderError;
890 use reth_storage_overlay::OverlayManager;
891
892 const ADDRESS: Address = address!("0x0000000000000000000000000000000000000001");
893 const HIGHER_ADDRESS: Address = address!("0x0000000000000000000000000000000000000005");
894 const STORAGE: B256 =
895 b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
896
897 const fn assert_state_provider<T: StateProvider>() {}
898 #[expect(dead_code)]
899 const fn assert_historical_state_provider<
900 T: DBProvider
901 + BlockNumReader
902 + BlockHashReader
903 + ChangeSetReader
904 + StorageChangeSetReader
905 + PruneCheckpointReader
906 + StageCheckpointReader
907 + StorageSettingsCache
908 + RocksDBProviderFactory
909 + NodePrimitivesProvider,
910 >() {
911 assert_state_provider::<HistoricalStateProvider<T>>();
912 }
913
914 #[test]
915 fn history_provider_get_account() {
916 let factory = create_test_provider_factory();
917 let tx = factory.provider_rw().unwrap().into_tx();
918
919 tx.put::<tables::AccountsHistory>(
920 ShardedKey { key: ADDRESS, highest_block_number: 7 },
921 BlockNumberList::new([1, 3, 7]).unwrap(),
922 )
923 .unwrap();
924 tx.put::<tables::AccountsHistory>(
925 ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
926 BlockNumberList::new([10, 15]).unwrap(),
927 )
928 .unwrap();
929 tx.put::<tables::AccountsHistory>(
930 ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
931 BlockNumberList::new([4]).unwrap(),
932 )
933 .unwrap();
934
935 let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
936 let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
937 let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
938 let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
939 let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
940
941 let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
942
943 tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
945 .unwrap();
946 tx.put::<tables::AccountChangeSets>(
947 3,
948 AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
949 )
950 .unwrap();
951 tx.put::<tables::AccountChangeSets>(
952 4,
953 AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
954 )
955 .unwrap();
956 tx.put::<tables::AccountChangeSets>(
957 7,
958 AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
959 )
960 .unwrap();
961 tx.put::<tables::AccountChangeSets>(
962 10,
963 AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
964 )
965 .unwrap();
966 tx.put::<tables::AccountChangeSets>(
967 15,
968 AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
969 )
970 .unwrap();
971
972 tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
974 tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
975 tx.commit().unwrap();
976
977 let db = factory.provider().unwrap();
978
979 assert!(matches!(
981 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
982 .basic_account(&ADDRESS),
983 Ok(None)
984 ));
985 assert!(matches!(
986 HistoricalStateProviderRef::new(&db, 2, OverlayManager::default()).basic_account(&ADDRESS),
987 Ok(Some(acc)) if acc == acc_at3
988 ));
989 assert!(matches!(
990 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default()).basic_account(&ADDRESS),
991 Ok(Some(acc)) if acc == acc_at3
992 ));
993 assert!(matches!(
994 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).basic_account(&ADDRESS),
995 Ok(Some(acc)) if acc == acc_at7
996 ));
997 assert!(matches!(
998 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).basic_account(&ADDRESS),
999 Ok(Some(acc)) if acc == acc_at7
1000 ));
1001 assert!(matches!(
1002 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).basic_account(&ADDRESS),
1003 Ok(Some(acc)) if acc == acc_at10
1004 ));
1005 assert!(matches!(
1006 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).basic_account(&ADDRESS),
1007 Ok(Some(acc)) if acc == acc_at10
1008 ));
1009 assert!(matches!(
1010 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).basic_account(&ADDRESS),
1011 Ok(Some(acc)) if acc == acc_at15
1012 ));
1013 assert!(matches!(
1014 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).basic_account(&ADDRESS),
1015 Ok(Some(acc)) if acc == acc_plain
1016 ));
1017
1018 assert!(matches!(
1019 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1020 .basic_account(&HIGHER_ADDRESS),
1021 Ok(None)
1022 ));
1023 assert!(matches!(
1024 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).basic_account(&HIGHER_ADDRESS),
1025 Ok(Some(acc)) if acc == higher_acc_plain
1026 ));
1027 }
1028
1029 #[test]
1030 fn history_provider_get_storage() {
1031 let factory = create_test_provider_factory();
1032 let tx = factory.provider_rw().unwrap().into_tx();
1033
1034 tx.put::<tables::StoragesHistory>(
1035 StorageShardedKey {
1036 address: ADDRESS,
1037 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1038 },
1039 BlockNumberList::new([3, 7]).unwrap(),
1040 )
1041 .unwrap();
1042 tx.put::<tables::StoragesHistory>(
1043 StorageShardedKey {
1044 address: ADDRESS,
1045 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1046 },
1047 BlockNumberList::new([10, 15]).unwrap(),
1048 )
1049 .unwrap();
1050 tx.put::<tables::StoragesHistory>(
1051 StorageShardedKey {
1052 address: HIGHER_ADDRESS,
1053 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1054 },
1055 BlockNumberList::new([4]).unwrap(),
1056 )
1057 .unwrap();
1058
1059 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1060 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1061 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1062 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1063 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1064 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1065 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1066
1067 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1069 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1070 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1071 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1072 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1073
1074 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1076 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1077 tx.commit().unwrap();
1078
1079 let db = factory.provider().unwrap();
1080
1081 assert!(matches!(
1083 HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1084 .storage(ADDRESS, STORAGE),
1085 Ok(None)
1086 ));
1087 assert!(matches!(
1088 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1089 .storage(ADDRESS, STORAGE),
1090 Ok(Some(U256::ZERO))
1091 ));
1092 assert!(matches!(
1093 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1094 Ok(Some(expected_value)) if expected_value == entry_at7.value
1095 ));
1096 assert!(matches!(
1097 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1098 Ok(Some(expected_value)) if expected_value == entry_at7.value
1099 ));
1100 assert!(matches!(
1101 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1102 Ok(Some(expected_value)) if expected_value == entry_at10.value
1103 ));
1104 assert!(matches!(
1105 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1106 Ok(Some(expected_value)) if expected_value == entry_at10.value
1107 ));
1108 assert!(matches!(
1109 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1110 Ok(Some(expected_value)) if expected_value == entry_at15.value
1111 ));
1112 assert!(matches!(
1113 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1114 Ok(Some(expected_value)) if expected_value == entry_plain.value
1115 ));
1116 assert!(matches!(
1117 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1118 .storage(HIGHER_ADDRESS, STORAGE),
1119 Ok(None)
1120 ));
1121 assert!(matches!(
1122 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1123 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1124 ));
1125 }
1126
1127 #[test]
1128 fn history_provider_unavailable() {
1129 let factory = create_test_provider_factory();
1130 let db = factory.database_provider_rw().unwrap();
1131
1132 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1135 &db,
1136 2,
1137 LowestAvailableBlocks {
1138 account_history_block_number: Some(3),
1139 storage_history_block_number: Some(3),
1140 },
1141 OverlayManager::default(),
1142 );
1143 assert!(matches!(
1144 provider.account_history_lookup(ADDRESS),
1145 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1146 ));
1147 assert!(matches!(
1148 provider.storage_history_lookup(ADDRESS, STORAGE),
1149 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1150 ));
1151
1152 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1155 &db,
1156 2,
1157 LowestAvailableBlocks {
1158 account_history_block_number: Some(2),
1159 storage_history_block_number: Some(2),
1160 },
1161 OverlayManager::default(),
1162 );
1163 assert!(matches!(
1164 provider.account_history_lookup(ADDRESS),
1165 Ok(HistoryInfo::MaybeInPlainState)
1166 ));
1167 assert!(matches!(
1168 provider.storage_history_lookup(ADDRESS, STORAGE),
1169 Ok(HistoryInfo::MaybeInPlainState)
1170 ));
1171
1172 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1175 &db,
1176 2,
1177 LowestAvailableBlocks {
1178 account_history_block_number: Some(1),
1179 storage_history_block_number: Some(1),
1180 },
1181 OverlayManager::default(),
1182 );
1183 assert!(matches!(
1184 provider.account_history_lookup(ADDRESS),
1185 Ok(HistoryInfo::MaybeInPlainState)
1186 ));
1187 assert!(matches!(
1188 provider.storage_history_lookup(ADDRESS, STORAGE),
1189 Ok(HistoryInfo::MaybeInPlainState)
1190 ));
1191 }
1192
1193 #[test]
1194 fn test_history_info_from_lookup() {
1195 assert_eq!(HistoryInfo::from_lookup(Some(10), true, None), HistoryInfo::NotYetWritten);
1197 assert_eq!(HistoryInfo::from_lookup(None, true, None), HistoryInfo::NotYetWritten);
1198
1199 assert_eq!(HistoryInfo::from_lookup(Some(10), true, Some(5)), HistoryInfo::InChangeset(10));
1201 assert_eq!(HistoryInfo::from_lookup(None, true, Some(5)), HistoryInfo::NotYetWritten);
1202
1203 assert_eq!(HistoryInfo::from_lookup(Some(10), false, None), HistoryInfo::InChangeset(10));
1205 assert_eq!(HistoryInfo::from_lookup(None, false, None), HistoryInfo::InPlainState);
1206 }
1207
1208 #[test]
1209 fn history_provider_get_storage_legacy() {
1210 let factory = create_test_provider_factory();
1211
1212 assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
1213
1214 let tx = factory.provider_rw().unwrap().into_tx();
1215
1216 tx.put::<tables::StoragesHistory>(
1217 StorageShardedKey {
1218 address: ADDRESS,
1219 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1220 },
1221 BlockNumberList::new([3, 7]).unwrap(),
1222 )
1223 .unwrap();
1224 tx.put::<tables::StoragesHistory>(
1225 StorageShardedKey {
1226 address: ADDRESS,
1227 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1228 },
1229 BlockNumberList::new([10, 15]).unwrap(),
1230 )
1231 .unwrap();
1232 tx.put::<tables::StoragesHistory>(
1233 StorageShardedKey {
1234 address: HIGHER_ADDRESS,
1235 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1236 },
1237 BlockNumberList::new([4]).unwrap(),
1238 )
1239 .unwrap();
1240
1241 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1242 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1243 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1244 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1245 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1246 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1247 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1248
1249 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1250 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1251 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1252 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1253 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1254
1255 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1256 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1257 tx.commit().unwrap();
1258
1259 let db = factory.provider().unwrap();
1260
1261 assert!(matches!(
1262 HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1263 .storage(ADDRESS, STORAGE),
1264 Ok(None)
1265 ));
1266 assert!(matches!(
1267 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1268 .storage(ADDRESS, STORAGE),
1269 Ok(Some(U256::ZERO))
1270 ));
1271 assert!(matches!(
1272 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1273 Ok(Some(expected_value)) if expected_value == entry_at7.value
1274 ));
1275 assert!(matches!(
1276 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1277 Ok(Some(expected_value)) if expected_value == entry_at7.value
1278 ));
1279 assert!(matches!(
1280 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1281 Ok(Some(expected_value)) if expected_value == entry_at10.value
1282 ));
1283 assert!(matches!(
1284 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1285 Ok(Some(expected_value)) if expected_value == entry_at10.value
1286 ));
1287 assert!(matches!(
1288 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1289 Ok(Some(expected_value)) if expected_value == entry_at15.value
1290 ));
1291 assert!(matches!(
1292 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1293 Ok(Some(expected_value)) if expected_value == entry_plain.value
1294 ));
1295 assert!(matches!(
1296 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1297 .storage(HIGHER_ADDRESS, STORAGE),
1298 Ok(None)
1299 ));
1300 assert!(matches!(
1301 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1302 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1303 ));
1304 }
1305
1306 #[test]
1307 fn history_provider_get_storage_hashed_state() {
1308 use crate::BlockWriter;
1309 use alloy_primitives::keccak256;
1310 use reth_db_api::models::StorageSettings;
1311 use reth_execution_types::ExecutionOutcome;
1312 use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
1313 use revm::database::BundleState;
1314 use std::collections::HashMap;
1315
1316 let factory = create_test_provider_factory();
1317 factory.set_storage_settings_cache(StorageSettings::v2());
1318
1319 let slot = U256::from_be_bytes(*STORAGE);
1320 let account: revm::state::AccountInfo =
1321 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None }.into();
1322 let higher_account: revm::state::AccountInfo =
1323 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None }.into();
1324
1325 let mut rng = generators::rng();
1326 let blocks = random_block_range(
1327 &mut rng,
1328 0..=15,
1329 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1330 );
1331
1332 let mut addr_storage = HashMap::default();
1333 addr_storage.insert(slot, (U256::ZERO, U256::from(100)));
1334 let mut higher_storage = HashMap::default();
1335 higher_storage.insert(slot, (U256::ZERO, U256::from(1000)));
1336
1337 type Revert = Vec<(Address, Option<Option<revm::state::AccountInfo>>, Vec<(U256, U256)>)>;
1338 let mut reverts: Vec<Revert> = vec![Vec::new(); 16];
1339
1340 reverts[3] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::ZERO)])];
1341 reverts[4] =
1342 vec![(HIGHER_ADDRESS, Some(Some(higher_account.clone())), vec![(slot, U256::ZERO)])];
1343 reverts[7] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(7))])];
1344 reverts[10] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(10))])];
1345 reverts[15] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(15))])];
1346
1347 let bundle = BundleState::new(
1348 [
1349 (ADDRESS, None, Some(account), addr_storage),
1350 (HIGHER_ADDRESS, None, Some(higher_account), higher_storage),
1351 ],
1352 reverts,
1353 [],
1354 );
1355
1356 let provider_rw = factory.provider_rw().unwrap();
1357 provider_rw
1358 .append_blocks_with_state(
1359 blocks
1360 .into_iter()
1361 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1362 .collect(),
1363 &ExecutionOutcome { bundle, first_block: 0, ..Default::default() },
1364 Default::default(),
1365 )
1366 .unwrap();
1367
1368 let hashed_address = keccak256(ADDRESS);
1369 let hashed_higher_address = keccak256(HIGHER_ADDRESS);
1370 let hashed_storage = keccak256(STORAGE);
1371
1372 provider_rw
1373 .tx_ref()
1374 .put::<tables::HashedStorages>(
1375 hashed_address,
1376 StorageEntry { key: hashed_storage, value: U256::from(100) },
1377 )
1378 .unwrap();
1379 provider_rw
1380 .tx_ref()
1381 .put::<tables::HashedStorages>(
1382 hashed_higher_address,
1383 StorageEntry { key: hashed_storage, value: U256::from(1000) },
1384 )
1385 .unwrap();
1386 provider_rw
1387 .tx_ref()
1388 .put::<tables::HashedAccounts>(
1389 hashed_address,
1390 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None },
1391 )
1392 .unwrap();
1393 provider_rw
1394 .tx_ref()
1395 .put::<tables::HashedAccounts>(
1396 hashed_higher_address,
1397 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None },
1398 )
1399 .unwrap();
1400 provider_rw.commit().unwrap();
1401
1402 let db = factory.provider().unwrap();
1403
1404 assert!(matches!(
1405 HistoricalStateProviderRef::new(&db, 0, OverlayManager::default())
1406 .storage(ADDRESS, STORAGE),
1407 Ok(None)
1408 ));
1409 assert!(matches!(
1410 HistoricalStateProviderRef::new(&db, 3, OverlayManager::default())
1411 .storage(ADDRESS, STORAGE),
1412 Ok(Some(U256::ZERO))
1413 ));
1414 assert!(matches!(
1415 HistoricalStateProviderRef::new(&db, 4, OverlayManager::default()).storage(ADDRESS, STORAGE),
1416 Ok(Some(v)) if v == U256::from(7)
1417 ));
1418 assert!(matches!(
1419 HistoricalStateProviderRef::new(&db, 7, OverlayManager::default()).storage(ADDRESS, STORAGE),
1420 Ok(Some(v)) if v == U256::from(7)
1421 ));
1422 assert!(matches!(
1423 HistoricalStateProviderRef::new(&db, 9, OverlayManager::default()).storage(ADDRESS, STORAGE),
1424 Ok(Some(v)) if v == U256::from(10)
1425 ));
1426 assert!(matches!(
1427 HistoricalStateProviderRef::new(&db, 10, OverlayManager::default()).storage(ADDRESS, STORAGE),
1428 Ok(Some(v)) if v == U256::from(10)
1429 ));
1430 assert!(matches!(
1431 HistoricalStateProviderRef::new(&db, 11, OverlayManager::default()).storage(ADDRESS, STORAGE),
1432 Ok(Some(v)) if v == U256::from(15)
1433 ));
1434 assert!(matches!(
1435 HistoricalStateProviderRef::new(&db, 16, OverlayManager::default()).storage(ADDRESS, STORAGE),
1436 Ok(Some(v)) if v == U256::from(100)
1437 ));
1438 assert!(matches!(
1439 HistoricalStateProviderRef::new(&db, 1, OverlayManager::default())
1440 .storage(HIGHER_ADDRESS, STORAGE),
1441 Ok(None)
1442 ));
1443 assert!(matches!(
1444 HistoricalStateProviderRef::new(&db, 1000, OverlayManager::default()).storage(HIGHER_ADDRESS, STORAGE),
1445 Ok(Some(v)) if v == U256::from(1000)
1446 ));
1447 }
1448
1449 #[test]
1450 fn test_needs_prev_shard_check() {
1451 assert!(needs_prev_shard_check(0, Some(10), 5));
1453 assert!(needs_prev_shard_check(0, None, 5));
1454 assert!(!needs_prev_shard_check(0, Some(5), 5)); assert!(!needs_prev_shard_check(1, Some(10), 5)); }
1457}