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