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