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};
15use reth_storage_api::{
16 BlockNumReader, BytecodeReader, DBProvider, NodePrimitivesProvider, StateProofProvider,
17 StorageChangeSetReader, StorageRootProvider, StorageSettingsCache,
18};
19use reth_storage_errors::provider::ProviderResult;
20use reth_trie::{
21 hashed_cursor::HashedPostStateCursorFactory,
22 proof::{Proof, StorageProof},
23 trie_cursor::InMemoryTrieCursorFactory,
24 updates::TrieUpdates,
25 witness::TrieWitness,
26 AccountProof, ExecutionWitnessMode, HashedPostState, HashedPostStateSorted, HashedStorage,
27 KeccakKeyHasher, MultiProof, MultiProofTargets, StateRoot, StorageMultiProof, StorageRoot,
28 TrieInput, TrieInputSorted,
29};
30use reth_trie_db::{
31 hashed_storage_from_reverts_with_provider, DatabaseProof, DatabaseStateRoot,
32 DatabaseStorageProof, DatabaseStorageRoot,
33};
34
35use std::fmt::Debug;
36
37type DbStateRoot<'a, TX, A> = StateRoot<
38 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
39 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
40>;
41type DbStorageRoot<'a, TX, A> = StorageRoot<
42 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
43 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
44>;
45type DbStorageProof<'a, TX, A> = StorageProof<
46 'static,
47 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
48 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
49>;
50type DbProof<'a, TX, A> = Proof<
51 reth_trie_db::DatabaseTrieCursorFactory<&'a TX, A>,
52 reth_trie_db::DatabaseHashedCursorFactory<&'a TX>,
53>;
54
55#[derive(Debug, Eq, PartialEq)]
59pub enum HistoryInfo {
60 NotYetWritten,
63 InChangeset(u64),
66 InPlainState,
69 MaybeInPlainState,
72}
73
74impl HistoryInfo {
75 pub const fn from_lookup(
86 found_block: Option<u64>,
87 is_before_first_write: bool,
88 lowest_available: Option<BlockNumber>,
89 ) -> Self {
90 if is_before_first_write {
91 if let (Some(_), Some(block_number)) = (lowest_available, found_block) {
92 return Self::InChangeset(block_number)
95 }
96 return Self::NotYetWritten
98 }
99
100 if let Some(block_number) = found_block {
101 Self::InChangeset(block_number)
103 } else {
104 Self::InPlainState
107 }
108 }
109}
110
111#[derive(Debug)]
123pub struct HistoricalStateProviderRef<'b, Provider> {
124 provider: &'b Provider,
126 block_number: BlockNumber,
128 lowest_available_blocks: LowestAvailableBlocks,
130}
131
132impl<'b, Provider: DBProvider + ChangeSetReader + StorageChangeSetReader + BlockNumReader>
133 HistoricalStateProviderRef<'b, Provider>
134{
135 pub fn new(provider: &'b Provider, block_number: BlockNumber) -> Self {
137 Self { provider, block_number, lowest_available_blocks: Default::default() }
138 }
139
140 pub const fn new_with_lowest_available_blocks(
143 provider: &'b Provider,
144 block_number: BlockNumber,
145 lowest_available_blocks: LowestAvailableBlocks,
146 ) -> Self {
147 Self { provider, block_number, lowest_available_blocks }
148 }
149
150 pub fn account_history_lookup(&self, address: Address) -> ProviderResult<HistoryInfo>
152 where
153 Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
154 {
155 if !self.lowest_available_blocks.is_account_history_available(self.block_number) {
156 return Err(ProviderError::StateAtBlockPruned(self.block_number))
157 }
158
159 let visible_tip = self.provider.best_block_number()?;
160
161 self.provider.with_rocksdb_snapshot(|rocksdb_ref| {
162 let mut reader = EitherReader::new_accounts_history(self.provider, rocksdb_ref)?;
163 reader.account_history_info(
164 address,
165 self.block_number,
166 self.lowest_available_blocks.account_history_block_number,
167 visible_tip,
168 )
169 })
170 }
171
172 pub fn storage_history_lookup(
176 &self,
177 address: Address,
178 lookup_key: B256,
179 ) -> ProviderResult<HistoryInfo>
180 where
181 Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
182 {
183 if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
184 return Err(ProviderError::StateAtBlockPruned(self.block_number))
185 }
186
187 let visible_tip = self.provider.best_block_number()?;
188
189 self.provider.with_rocksdb_snapshot(|rocksdb_ref| {
190 let mut reader = EitherReader::new_storages_history(self.provider, rocksdb_ref)?;
191 reader.storage_history_info(
192 address,
193 lookup_key,
194 self.block_number,
195 self.lowest_available_blocks.storage_history_block_number,
196 visible_tip,
197 )
198 })
199 }
200
201 fn storage_by_lookup_key(
206 &self,
207 address: Address,
208 lookup_key: B256,
209 ) -> ProviderResult<Option<StorageValue>>
210 where
211 Provider: StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider,
212 {
213 match self.storage_history_lookup(address, lookup_key)? {
214 HistoryInfo::NotYetWritten => Ok(None),
215 HistoryInfo::InChangeset(changeset_block_number) => self
216 .provider
217 .get_storage_before_block(changeset_block_number, address, lookup_key)?
218 .ok_or_else(|| ProviderError::StorageChangesetNotFound {
219 block_number: changeset_block_number,
220 address,
221 storage_key: Box::new(lookup_key),
222 })
223 .map(|entry| entry.value)
224 .map(Some),
225 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
226 if self.provider.cached_storage_settings().use_hashed_state() {
227 let hashed_address = alloy_primitives::keccak256(address);
228 let hashed_slot = alloy_primitives::keccak256(lookup_key);
229 Ok(self
230 .tx()
231 .cursor_dup_read::<tables::HashedStorages>()?
232 .seek_by_key_subkey(hashed_address, hashed_slot)?
233 .filter(|entry| entry.key == hashed_slot)
234 .map(|entry| entry.value)
235 .or(Some(StorageValue::ZERO)))
236 } else {
237 Ok(self
238 .tx()
239 .cursor_dup_read::<tables::PlainStorageState>()?
240 .seek_by_key_subkey(address, lookup_key)?
241 .filter(|entry| entry.key == lookup_key)
242 .map(|entry| entry.value)
243 .or(Some(StorageValue::ZERO)))
244 }
245 }
246 }
247 }
248
249 fn check_distance_against_limit(&self, limit: u64) -> ProviderResult<bool> {
251 let tip = self.provider.last_block_number()?;
252
253 Ok(tip.saturating_sub(self.block_number) > limit)
254 }
255
256 fn revert_state(&self) -> ProviderResult<HashedPostStateSorted>
258 where
259 Provider: StorageSettingsCache,
260 {
261 if !self.lowest_available_blocks.is_account_history_available(self.block_number) ||
262 !self.lowest_available_blocks.is_storage_history_available(self.block_number)
263 {
264 return Err(ProviderError::StateAtBlockPruned(self.block_number))
265 }
266
267 if self.check_distance_against_limit(EPOCH_SLOTS)? {
268 tracing::warn!(
269 target: "providers::historical_sp",
270 target = self.block_number,
271 "Attempt to calculate state root for an old block might result in OOM"
272 );
273 }
274
275 reth_trie_db::from_reverts_auto(self.provider, self.block_number..)
276 }
277
278 fn revert_storage(&self, address: Address) -> ProviderResult<HashedStorage>
280 where
281 Provider: StorageSettingsCache,
282 {
283 if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
284 return Err(ProviderError::StateAtBlockPruned(self.block_number))
285 }
286
287 if self.check_distance_against_limit(EPOCH_SLOTS * 10)? {
288 tracing::warn!(
289 target: "providers::historical_sp",
290 target = self.block_number,
291 "Attempt to calculate storage root for an old block might result in OOM"
292 );
293 }
294
295 hashed_storage_from_reverts_with_provider(self.provider, address, self.block_number)
296 }
297
298 pub const fn with_lowest_available_account_history_block_number(
300 mut self,
301 block_number: BlockNumber,
302 ) -> Self {
303 self.lowest_available_blocks.account_history_block_number = Some(block_number);
304 self
305 }
306
307 pub const fn with_lowest_available_storage_history_block_number(
309 mut self,
310 block_number: BlockNumber,
311 ) -> Self {
312 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
313 self
314 }
315}
316
317impl<Provider: DBProvider + BlockNumReader> HistoricalStateProviderRef<'_, Provider> {
318 fn tx(&self) -> &Provider::Tx {
319 self.provider.tx_ref()
320 }
321}
322
323impl<
324 Provider: DBProvider
325 + BlockNumReader
326 + ChangeSetReader
327 + StorageChangeSetReader
328 + StorageSettingsCache
329 + RocksDBProviderFactory
330 + NodePrimitivesProvider,
331 > AccountReader for HistoricalStateProviderRef<'_, Provider>
332{
333 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
335 match self.account_history_lookup(*address)? {
336 HistoryInfo::NotYetWritten => Ok(None),
337 HistoryInfo::InChangeset(changeset_block_number) => {
338 self.provider
340 .get_account_before_block(changeset_block_number, *address)?
341 .ok_or(ProviderError::AccountChangesetNotFound {
342 block_number: changeset_block_number,
343 address: *address,
344 })
345 .map(|account_before| account_before.info)
346 }
347 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
348 if self.provider.cached_storage_settings().use_hashed_state() {
349 let hashed_address = alloy_primitives::keccak256(address);
350 Ok(self.tx().get_by_encoded_key::<tables::HashedAccounts>(&hashed_address)?)
351 } else {
352 Ok(self.tx().get_by_encoded_key::<tables::PlainAccountState>(address)?)
353 }
354 }
355 }
356 }
357}
358
359impl<Provider: DBProvider + BlockNumReader + BlockHashReader> BlockHashReader
360 for HistoricalStateProviderRef<'_, Provider>
361{
362 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
364 self.provider.block_hash(number)
365 }
366
367 fn canonical_hashes_range(
368 &self,
369 start: BlockNumber,
370 end: BlockNumber,
371 ) -> ProviderResult<Vec<B256>> {
372 self.provider.canonical_hashes_range(start, end)
373 }
374}
375
376impl<
377 Provider: DBProvider
378 + ChangeSetReader
379 + StorageChangeSetReader
380 + BlockNumReader
381 + StorageSettingsCache,
382 > StateRootProvider for HistoricalStateProviderRef<'_, Provider>
383{
384 fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
385 reth_trie_db::with_adapter!(self.provider, |A| {
386 let mut revert_state = self.revert_state()?;
387 let hashed_state_sorted = hashed_state.into_sorted();
388 revert_state.extend_ref_and_sort(&hashed_state_sorted);
389 Ok(<DbStateRoot<'_, _, A>>::overlay_root(self.tx(), &revert_state)?)
390 })
391 }
392
393 fn state_root_from_nodes(&self, input: TrieInput) -> ProviderResult<B256> {
394 reth_trie_db::with_adapter!(self.provider, |A| {
395 let mut input = input;
396 input.prepend(self.revert_state()?.into());
397 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes(
398 self.tx(),
399 TrieInputSorted::from_unsorted(input),
400 )?)
401 })
402 }
403
404 fn state_root_with_updates(
405 &self,
406 hashed_state: HashedPostState,
407 ) -> ProviderResult<(B256, TrieUpdates)> {
408 reth_trie_db::with_adapter!(self.provider, |A| {
409 let mut revert_state = self.revert_state()?;
410 let hashed_state_sorted = hashed_state.into_sorted();
411 revert_state.extend_ref_and_sort(&hashed_state_sorted);
412 Ok(<DbStateRoot<'_, _, A>>::overlay_root_with_updates(self.tx(), &revert_state)?)
413 })
414 }
415
416 fn state_root_from_nodes_with_updates(
417 &self,
418 input: TrieInput,
419 ) -> ProviderResult<(B256, TrieUpdates)> {
420 reth_trie_db::with_adapter!(self.provider, |A| {
421 let mut input = input;
422 input.prepend(self.revert_state()?.into());
423 Ok(<DbStateRoot<'_, _, A>>::overlay_root_from_nodes_with_updates(
424 self.tx(),
425 TrieInputSorted::from_unsorted(input),
426 )?)
427 })
428 }
429}
430
431impl<
432 Provider: DBProvider
433 + ChangeSetReader
434 + StorageChangeSetReader
435 + BlockNumReader
436 + StorageSettingsCache,
437 > StorageRootProvider for HistoricalStateProviderRef<'_, Provider>
438{
439 fn storage_root(
440 &self,
441 address: Address,
442 hashed_storage: HashedStorage,
443 ) -> ProviderResult<B256> {
444 reth_trie_db::with_adapter!(self.provider, |A| {
445 let mut revert_storage = self.revert_storage(address)?;
446 revert_storage.extend(&hashed_storage);
447 <DbStorageRoot<'_, _, A>>::overlay_root(self.tx(), address, revert_storage)
448 .map_err(|err| ProviderError::Database(err.into()))
449 })
450 }
451
452 fn storage_proof(
453 &self,
454 address: Address,
455 slot: B256,
456 hashed_storage: HashedStorage,
457 ) -> ProviderResult<reth_trie::StorageProof> {
458 reth_trie_db::with_adapter!(self.provider, |A| {
459 let mut revert_storage = self.revert_storage(address)?;
460 revert_storage.extend(&hashed_storage);
461 <DbStorageProof<'_, _, A>>::overlay_storage_proof(
462 self.tx(),
463 address,
464 slot,
465 revert_storage,
466 )
467 .map_err(ProviderError::from)
468 })
469 }
470
471 fn storage_multiproof(
472 &self,
473 address: Address,
474 slots: &[B256],
475 hashed_storage: HashedStorage,
476 ) -> ProviderResult<StorageMultiProof> {
477 reth_trie_db::with_adapter!(self.provider, |A| {
478 let mut revert_storage = self.revert_storage(address)?;
479 revert_storage.extend(&hashed_storage);
480 <DbStorageProof<'_, _, A>>::overlay_storage_multiproof(
481 self.tx(),
482 address,
483 slots,
484 revert_storage,
485 )
486 .map_err(ProviderError::from)
487 })
488 }
489}
490
491impl<
492 Provider: DBProvider
493 + ChangeSetReader
494 + StorageChangeSetReader
495 + BlockNumReader
496 + StorageSettingsCache,
497 > StateProofProvider for HistoricalStateProviderRef<'_, Provider>
498{
499 fn proof(
501 &self,
502 input: TrieInput,
503 address: Address,
504 slots: &[B256],
505 ) -> ProviderResult<AccountProof> {
506 reth_trie_db::with_adapter!(self.provider, |A| {
507 let mut input = input;
508 input.prepend(self.revert_state()?.into());
509 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.tx());
510 proof.overlay_account_proof(input, address, slots).map_err(ProviderError::from)
511 })
512 }
513
514 fn multiproof(
515 &self,
516 input: TrieInput,
517 targets: MultiProofTargets,
518 ) -> ProviderResult<MultiProof> {
519 reth_trie_db::with_adapter!(self.provider, |A| {
520 let mut input = input;
521 input.prepend(self.revert_state()?.into());
522 let proof = <DbProof<'_, _, A> as DatabaseProof>::from_tx(self.tx());
523 proof.overlay_multiproof(input, targets).map_err(ProviderError::from)
524 })
525 }
526
527 fn witness(
528 &self,
529 input: TrieInput,
530 target: HashedPostState,
531 mode: ExecutionWitnessMode,
532 ) -> ProviderResult<Vec<Bytes>> {
533 reth_trie_db::with_adapter!(self.provider, |A| {
534 let mut input = input;
535 input.prepend(self.revert_state()?.into());
536 let nodes_sorted = input.nodes.into_sorted();
537 let state_sorted = input.state.into_sorted();
538 let witness = TrieWitness::new(
539 InMemoryTrieCursorFactory::new(
540 reth_trie_db::DatabaseTrieCursorFactory::<_, A>::new(self.tx()),
541 &nodes_sorted,
542 ),
543 HashedPostStateCursorFactory::new(
544 reth_trie_db::DatabaseHashedCursorFactory::new(self.tx()),
545 &state_sorted,
546 ),
547 )
548 .with_prefix_sets_mut(input.prefix_sets)
549 .with_execution_witness_mode(mode);
550 let witness =
551 if mode.is_canonical() { witness } else { witness.always_include_root_node() };
552 witness.compute(target).map_err(ProviderError::from).map(|hm| {
553 let mut values: Vec<_> = hm.into_values().collect();
554 if mode.is_canonical() {
555 values.sort_unstable();
556 }
557 values
558 })
559 })
560 }
561}
562
563impl<Provider> HashedPostStateProvider for HistoricalStateProviderRef<'_, Provider> {
564 fn hashed_post_state(&self, bundle_state: &revm_database::BundleState) -> HashedPostState {
565 HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
566 }
567}
568
569impl<
570 Provider: DBProvider
571 + BlockNumReader
572 + BlockHashReader
573 + ChangeSetReader
574 + StorageChangeSetReader
575 + StorageSettingsCache
576 + RocksDBProviderFactory
577 + NodePrimitivesProvider,
578 > StateProvider for HistoricalStateProviderRef<'_, Provider>
579{
580 fn storage(
582 &self,
583 address: Address,
584 storage_key: StorageKey,
585 ) -> ProviderResult<Option<StorageValue>> {
586 self.storage_by_lookup_key(address, storage_key)
587 }
588}
589
590impl<Provider: DBProvider + BlockNumReader> BytecodeReader
591 for HistoricalStateProviderRef<'_, Provider>
592{
593 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
595 self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
596 }
597}
598
599#[derive(Debug)]
602pub struct HistoricalStateProvider<Provider> {
603 provider: Provider,
605 block_number: BlockNumber,
607 lowest_available_blocks: LowestAvailableBlocks,
609}
610
611impl<Provider: DBProvider + ChangeSetReader + StorageChangeSetReader + BlockNumReader>
612 HistoricalStateProvider<Provider>
613{
614 pub fn new(provider: Provider, block_number: BlockNumber) -> Self {
616 Self { provider, block_number, lowest_available_blocks: Default::default() }
617 }
618
619 pub const fn with_lowest_available_account_history_block_number(
621 mut self,
622 block_number: BlockNumber,
623 ) -> Self {
624 self.lowest_available_blocks.account_history_block_number = Some(block_number);
625 self
626 }
627
628 pub const fn with_lowest_available_storage_history_block_number(
630 mut self,
631 block_number: BlockNumber,
632 ) -> Self {
633 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
634 self
635 }
636
637 #[inline(always)]
639 const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
640 HistoricalStateProviderRef::new_with_lowest_available_blocks(
641 &self.provider,
642 self.block_number,
643 self.lowest_available_blocks,
644 )
645 }
646}
647
648reth_storage_api::macros::delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + ChangeSetReader + StorageChangeSetReader + StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider]);
650
651#[derive(Clone, Copy, Debug, Default)]
654pub struct LowestAvailableBlocks {
655 pub account_history_block_number: Option<BlockNumber>,
659 pub storage_history_block_number: Option<BlockNumber>,
663}
664
665impl LowestAvailableBlocks {
666 pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
669 self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
670 }
671
672 pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
675 self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
676 }
677}
678
679#[inline]
691pub fn compute_history_rank(
692 chunk: &reth_db_api::BlockNumberList,
693 block_number: BlockNumber,
694) -> (u64, Option<u64>) {
695 let mut rank = chunk.rank(block_number);
696 if rank.checked_sub(1).and_then(|r| chunk.select(r)) == Some(block_number) {
700 rank -= 1;
701 }
702 (rank, chunk.select(rank))
703}
704
705#[inline]
710pub fn needs_prev_shard_check(
711 rank: u64,
712 found_block: Option<u64>,
713 block_number: BlockNumber,
714) -> bool {
715 rank == 0 && found_block != Some(block_number)
716}
717
718pub fn history_info<T, K, C>(
723 cursor: &mut C,
724 key: K,
725 block_number: BlockNumber,
726 key_filter: impl Fn(&K) -> bool,
727 lowest_available_block_number: Option<BlockNumber>,
728) -> ProviderResult<HistoryInfo>
729where
730 T: Table<Key = K, Value = BlockNumberList>,
731 C: DbCursorRO<T>,
732{
733 if let Some(chunk) = cursor.seek(key)?.filter(|(k, _)| key_filter(k)).map(|x| x.1) {
737 let (rank, found_block) = compute_history_rank(&chunk, block_number);
738
739 let is_before_first_write = needs_prev_shard_check(rank, found_block, block_number) &&
746 !cursor.prev()?.is_some_and(|(k, _)| key_filter(&k));
747
748 Ok(HistoryInfo::from_lookup(
749 found_block,
750 is_before_first_write,
751 lowest_available_block_number,
752 ))
753 } else if lowest_available_block_number.is_some() {
754 Ok(HistoryInfo::MaybeInPlainState)
757 } else {
758 Ok(HistoryInfo::NotYetWritten)
760 }
761}
762
763#[cfg(test)]
764mod tests {
765 use super::needs_prev_shard_check;
766 use crate::{
767 providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
768 test_utils::create_test_provider_factory,
769 AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, RocksDBProviderFactory,
770 StateProvider,
771 };
772 use alloy_primitives::{address, b256, Address, B256, U256};
773 use reth_db_api::{
774 models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
775 tables,
776 transaction::{DbTx, DbTxMut},
777 BlockNumberList,
778 };
779 use reth_primitives_traits::{Account, StorageEntry};
780 use reth_storage_api::{
781 BlockHashReader, BlockNumReader, ChangeSetReader, DBProvider, DatabaseProviderFactory,
782 NodePrimitivesProvider, StorageChangeSetReader, StorageSettingsCache,
783 };
784 use reth_storage_errors::provider::ProviderError;
785
786 const ADDRESS: Address = address!("0x0000000000000000000000000000000000000001");
787 const HIGHER_ADDRESS: Address = address!("0x0000000000000000000000000000000000000005");
788 const STORAGE: B256 =
789 b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
790
791 const fn assert_state_provider<T: StateProvider>() {}
792 #[expect(dead_code)]
793 const fn assert_historical_state_provider<
794 T: DBProvider
795 + BlockNumReader
796 + BlockHashReader
797 + ChangeSetReader
798 + StorageChangeSetReader
799 + StorageSettingsCache
800 + RocksDBProviderFactory
801 + NodePrimitivesProvider,
802 >() {
803 assert_state_provider::<HistoricalStateProvider<T>>();
804 }
805
806 #[test]
807 fn history_provider_get_account() {
808 let factory = create_test_provider_factory();
809 let tx = factory.provider_rw().unwrap().into_tx();
810
811 tx.put::<tables::AccountsHistory>(
812 ShardedKey { key: ADDRESS, highest_block_number: 7 },
813 BlockNumberList::new([1, 3, 7]).unwrap(),
814 )
815 .unwrap();
816 tx.put::<tables::AccountsHistory>(
817 ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
818 BlockNumberList::new([10, 15]).unwrap(),
819 )
820 .unwrap();
821 tx.put::<tables::AccountsHistory>(
822 ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
823 BlockNumberList::new([4]).unwrap(),
824 )
825 .unwrap();
826
827 let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
828 let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
829 let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
830 let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
831 let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
832
833 let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
834
835 tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
837 .unwrap();
838 tx.put::<tables::AccountChangeSets>(
839 3,
840 AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
841 )
842 .unwrap();
843 tx.put::<tables::AccountChangeSets>(
844 4,
845 AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
846 )
847 .unwrap();
848 tx.put::<tables::AccountChangeSets>(
849 7,
850 AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
851 )
852 .unwrap();
853 tx.put::<tables::AccountChangeSets>(
854 10,
855 AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
856 )
857 .unwrap();
858 tx.put::<tables::AccountChangeSets>(
859 15,
860 AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
861 )
862 .unwrap();
863
864 tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
866 tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
867 tx.commit().unwrap();
868
869 let db = factory.provider().unwrap();
870
871 assert!(matches!(
873 HistoricalStateProviderRef::new(&db, 1).basic_account(&ADDRESS),
874 Ok(None)
875 ));
876 assert!(matches!(
877 HistoricalStateProviderRef::new(&db, 2).basic_account(&ADDRESS),
878 Ok(Some(acc)) if acc == acc_at3
879 ));
880 assert!(matches!(
881 HistoricalStateProviderRef::new(&db, 3).basic_account(&ADDRESS),
882 Ok(Some(acc)) if acc == acc_at3
883 ));
884 assert!(matches!(
885 HistoricalStateProviderRef::new(&db, 4).basic_account(&ADDRESS),
886 Ok(Some(acc)) if acc == acc_at7
887 ));
888 assert!(matches!(
889 HistoricalStateProviderRef::new(&db, 7).basic_account(&ADDRESS),
890 Ok(Some(acc)) if acc == acc_at7
891 ));
892 assert!(matches!(
893 HistoricalStateProviderRef::new(&db, 9).basic_account(&ADDRESS),
894 Ok(Some(acc)) if acc == acc_at10
895 ));
896 assert!(matches!(
897 HistoricalStateProviderRef::new(&db, 10).basic_account(&ADDRESS),
898 Ok(Some(acc)) if acc == acc_at10
899 ));
900 assert!(matches!(
901 HistoricalStateProviderRef::new(&db, 11).basic_account(&ADDRESS),
902 Ok(Some(acc)) if acc == acc_at15
903 ));
904 assert!(matches!(
905 HistoricalStateProviderRef::new(&db, 16).basic_account(&ADDRESS),
906 Ok(Some(acc)) if acc == acc_plain
907 ));
908
909 assert!(matches!(
910 HistoricalStateProviderRef::new(&db, 1).basic_account(&HIGHER_ADDRESS),
911 Ok(None)
912 ));
913 assert!(matches!(
914 HistoricalStateProviderRef::new(&db, 1000).basic_account(&HIGHER_ADDRESS),
915 Ok(Some(acc)) if acc == higher_acc_plain
916 ));
917 }
918
919 #[test]
920 fn history_provider_get_storage() {
921 let factory = create_test_provider_factory();
922 let tx = factory.provider_rw().unwrap().into_tx();
923
924 tx.put::<tables::StoragesHistory>(
925 StorageShardedKey {
926 address: ADDRESS,
927 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
928 },
929 BlockNumberList::new([3, 7]).unwrap(),
930 )
931 .unwrap();
932 tx.put::<tables::StoragesHistory>(
933 StorageShardedKey {
934 address: ADDRESS,
935 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
936 },
937 BlockNumberList::new([10, 15]).unwrap(),
938 )
939 .unwrap();
940 tx.put::<tables::StoragesHistory>(
941 StorageShardedKey {
942 address: HIGHER_ADDRESS,
943 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
944 },
945 BlockNumberList::new([4]).unwrap(),
946 )
947 .unwrap();
948
949 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
950 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
951 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
952 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
953 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
954 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
955 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
956
957 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
959 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
960 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
961 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
962 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
963
964 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
966 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
967 tx.commit().unwrap();
968
969 let db = factory.provider().unwrap();
970
971 assert!(matches!(
973 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
974 Ok(None)
975 ));
976 assert!(matches!(
977 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
978 Ok(Some(U256::ZERO))
979 ));
980 assert!(matches!(
981 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
982 Ok(Some(expected_value)) if expected_value == entry_at7.value
983 ));
984 assert!(matches!(
985 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
986 Ok(Some(expected_value)) if expected_value == entry_at7.value
987 ));
988 assert!(matches!(
989 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
990 Ok(Some(expected_value)) if expected_value == entry_at10.value
991 ));
992 assert!(matches!(
993 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
994 Ok(Some(expected_value)) if expected_value == entry_at10.value
995 ));
996 assert!(matches!(
997 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
998 Ok(Some(expected_value)) if expected_value == entry_at15.value
999 ));
1000 assert!(matches!(
1001 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
1002 Ok(Some(expected_value)) if expected_value == entry_plain.value
1003 ));
1004 assert!(matches!(
1005 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
1006 Ok(None)
1007 ));
1008 assert!(matches!(
1009 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
1010 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1011 ));
1012 }
1013
1014 #[test]
1015 fn history_provider_unavailable() {
1016 let factory = create_test_provider_factory();
1017 let db = factory.database_provider_rw().unwrap();
1018
1019 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1022 &db,
1023 2,
1024 LowestAvailableBlocks {
1025 account_history_block_number: Some(3),
1026 storage_history_block_number: Some(3),
1027 },
1028 );
1029 assert!(matches!(
1030 provider.account_history_lookup(ADDRESS),
1031 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1032 ));
1033 assert!(matches!(
1034 provider.storage_history_lookup(ADDRESS, STORAGE),
1035 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1036 ));
1037
1038 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1041 &db,
1042 2,
1043 LowestAvailableBlocks {
1044 account_history_block_number: Some(2),
1045 storage_history_block_number: Some(2),
1046 },
1047 );
1048 assert!(matches!(
1049 provider.account_history_lookup(ADDRESS),
1050 Ok(HistoryInfo::MaybeInPlainState)
1051 ));
1052 assert!(matches!(
1053 provider.storage_history_lookup(ADDRESS, STORAGE),
1054 Ok(HistoryInfo::MaybeInPlainState)
1055 ));
1056
1057 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1060 &db,
1061 2,
1062 LowestAvailableBlocks {
1063 account_history_block_number: Some(1),
1064 storage_history_block_number: Some(1),
1065 },
1066 );
1067 assert!(matches!(
1068 provider.account_history_lookup(ADDRESS),
1069 Ok(HistoryInfo::MaybeInPlainState)
1070 ));
1071 assert!(matches!(
1072 provider.storage_history_lookup(ADDRESS, STORAGE),
1073 Ok(HistoryInfo::MaybeInPlainState)
1074 ));
1075 }
1076
1077 #[test]
1078 fn test_history_info_from_lookup() {
1079 assert_eq!(HistoryInfo::from_lookup(Some(10), true, None), HistoryInfo::NotYetWritten);
1081 assert_eq!(HistoryInfo::from_lookup(None, true, None), HistoryInfo::NotYetWritten);
1082
1083 assert_eq!(HistoryInfo::from_lookup(Some(10), true, Some(5)), HistoryInfo::InChangeset(10));
1085 assert_eq!(HistoryInfo::from_lookup(None, true, Some(5)), HistoryInfo::NotYetWritten);
1086
1087 assert_eq!(HistoryInfo::from_lookup(Some(10), false, None), HistoryInfo::InChangeset(10));
1089 assert_eq!(HistoryInfo::from_lookup(None, false, None), HistoryInfo::InPlainState);
1090 }
1091
1092 #[test]
1093 fn history_provider_get_storage_legacy() {
1094 let factory = create_test_provider_factory();
1095
1096 assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
1097
1098 let tx = factory.provider_rw().unwrap().into_tx();
1099
1100 tx.put::<tables::StoragesHistory>(
1101 StorageShardedKey {
1102 address: ADDRESS,
1103 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1104 },
1105 BlockNumberList::new([3, 7]).unwrap(),
1106 )
1107 .unwrap();
1108 tx.put::<tables::StoragesHistory>(
1109 StorageShardedKey {
1110 address: ADDRESS,
1111 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1112 },
1113 BlockNumberList::new([10, 15]).unwrap(),
1114 )
1115 .unwrap();
1116 tx.put::<tables::StoragesHistory>(
1117 StorageShardedKey {
1118 address: HIGHER_ADDRESS,
1119 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1120 },
1121 BlockNumberList::new([4]).unwrap(),
1122 )
1123 .unwrap();
1124
1125 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1126 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1127 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1128 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1129 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1130 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1131 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1132
1133 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1134 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1135 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1136 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1137 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1138
1139 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1140 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1141 tx.commit().unwrap();
1142
1143 let db = factory.provider().unwrap();
1144
1145 assert!(matches!(
1146 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
1147 Ok(None)
1148 ));
1149 assert!(matches!(
1150 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
1151 Ok(Some(U256::ZERO))
1152 ));
1153 assert!(matches!(
1154 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
1155 Ok(Some(expected_value)) if expected_value == entry_at7.value
1156 ));
1157 assert!(matches!(
1158 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
1159 Ok(Some(expected_value)) if expected_value == entry_at7.value
1160 ));
1161 assert!(matches!(
1162 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
1163 Ok(Some(expected_value)) if expected_value == entry_at10.value
1164 ));
1165 assert!(matches!(
1166 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
1167 Ok(Some(expected_value)) if expected_value == entry_at10.value
1168 ));
1169 assert!(matches!(
1170 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
1171 Ok(Some(expected_value)) if expected_value == entry_at15.value
1172 ));
1173 assert!(matches!(
1174 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
1175 Ok(Some(expected_value)) if expected_value == entry_plain.value
1176 ));
1177 assert!(matches!(
1178 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
1179 Ok(None)
1180 ));
1181 assert!(matches!(
1182 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
1183 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1184 ));
1185 }
1186
1187 #[test]
1188 fn history_provider_get_storage_hashed_state() {
1189 use crate::BlockWriter;
1190 use alloy_primitives::keccak256;
1191 use reth_db_api::models::StorageSettings;
1192 use reth_execution_types::ExecutionOutcome;
1193 use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
1194 use revm_database::BundleState;
1195 use std::collections::HashMap;
1196
1197 let factory = create_test_provider_factory();
1198 factory.set_storage_settings_cache(StorageSettings::v2());
1199
1200 let slot = U256::from_be_bytes(*STORAGE);
1201 let account: revm_state::AccountInfo =
1202 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None }.into();
1203 let higher_account: revm_state::AccountInfo =
1204 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None }.into();
1205
1206 let mut rng = generators::rng();
1207 let blocks = random_block_range(
1208 &mut rng,
1209 0..=15,
1210 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1211 );
1212
1213 let mut addr_storage = HashMap::default();
1214 addr_storage.insert(slot, (U256::ZERO, U256::from(100)));
1215 let mut higher_storage = HashMap::default();
1216 higher_storage.insert(slot, (U256::ZERO, U256::from(1000)));
1217
1218 type Revert = Vec<(Address, Option<Option<revm_state::AccountInfo>>, Vec<(U256, U256)>)>;
1219 let mut reverts: Vec<Revert> = vec![Vec::new(); 16];
1220
1221 reverts[3] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::ZERO)])];
1222 reverts[4] =
1223 vec![(HIGHER_ADDRESS, Some(Some(higher_account.clone())), vec![(slot, U256::ZERO)])];
1224 reverts[7] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(7))])];
1225 reverts[10] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(10))])];
1226 reverts[15] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(15))])];
1227
1228 let bundle = BundleState::new(
1229 [
1230 (ADDRESS, None, Some(account), addr_storage),
1231 (HIGHER_ADDRESS, None, Some(higher_account), higher_storage),
1232 ],
1233 reverts,
1234 [],
1235 );
1236
1237 let provider_rw = factory.provider_rw().unwrap();
1238 provider_rw
1239 .append_blocks_with_state(
1240 blocks
1241 .into_iter()
1242 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1243 .collect(),
1244 &ExecutionOutcome { bundle, first_block: 0, ..Default::default() },
1245 Default::default(),
1246 )
1247 .unwrap();
1248
1249 let hashed_address = keccak256(ADDRESS);
1250 let hashed_higher_address = keccak256(HIGHER_ADDRESS);
1251 let hashed_storage = keccak256(STORAGE);
1252
1253 provider_rw
1254 .tx_ref()
1255 .put::<tables::HashedStorages>(
1256 hashed_address,
1257 StorageEntry { key: hashed_storage, value: U256::from(100) },
1258 )
1259 .unwrap();
1260 provider_rw
1261 .tx_ref()
1262 .put::<tables::HashedStorages>(
1263 hashed_higher_address,
1264 StorageEntry { key: hashed_storage, value: U256::from(1000) },
1265 )
1266 .unwrap();
1267 provider_rw
1268 .tx_ref()
1269 .put::<tables::HashedAccounts>(
1270 hashed_address,
1271 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None },
1272 )
1273 .unwrap();
1274 provider_rw
1275 .tx_ref()
1276 .put::<tables::HashedAccounts>(
1277 hashed_higher_address,
1278 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None },
1279 )
1280 .unwrap();
1281 provider_rw.commit().unwrap();
1282
1283 let db = factory.provider().unwrap();
1284
1285 assert!(matches!(
1286 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
1287 Ok(None)
1288 ));
1289 assert!(matches!(
1290 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
1291 Ok(Some(U256::ZERO))
1292 ));
1293 assert!(matches!(
1294 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
1295 Ok(Some(v)) if v == U256::from(7)
1296 ));
1297 assert!(matches!(
1298 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
1299 Ok(Some(v)) if v == U256::from(7)
1300 ));
1301 assert!(matches!(
1302 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
1303 Ok(Some(v)) if v == U256::from(10)
1304 ));
1305 assert!(matches!(
1306 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
1307 Ok(Some(v)) if v == U256::from(10)
1308 ));
1309 assert!(matches!(
1310 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
1311 Ok(Some(v)) if v == U256::from(15)
1312 ));
1313 assert!(matches!(
1314 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
1315 Ok(Some(v)) if v == U256::from(100)
1316 ));
1317 assert!(matches!(
1318 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
1319 Ok(None)
1320 ));
1321 assert!(matches!(
1322 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
1323 Ok(Some(v)) if v == U256::from(1000)
1324 ));
1325 }
1326
1327 #[test]
1328 fn test_needs_prev_shard_check() {
1329 assert!(needs_prev_shard_check(0, Some(10), 5));
1331 assert!(needs_prev_shard_check(0, None, 5));
1332 assert!(!needs_prev_shard_check(0, Some(5), 5)); assert!(!needs_prev_shard_check(1, Some(10), 5)); }
1335}