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, 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_snapshot(|rocksdb_ref| {
160 let mut reader = EitherReader::new_accounts_history(self.provider, rocksdb_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_snapshot(|rocksdb_ref| {
185 let mut reader = EitherReader::new_storages_history(self.provider, rocksdb_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 InMemoryTrieCursorFactory::new(
529 reth_trie_db::DatabaseTrieCursorFactory::<_, A>::new(self.tx()),
530 &nodes_sorted,
531 ),
532 HashedPostStateCursorFactory::new(
533 reth_trie_db::DatabaseHashedCursorFactory::new(self.tx()),
534 &state_sorted,
535 ),
536 )
537 .with_prefix_sets_mut(input.prefix_sets)
538 .always_include_root_node()
539 .compute(target)
540 .map_err(ProviderError::from)
541 .map(|hm| hm.into_values().collect())
542 })
543 }
544}
545
546impl<Provider> HashedPostStateProvider for HistoricalStateProviderRef<'_, Provider> {
547 fn hashed_post_state(&self, bundle_state: &revm_database::BundleState) -> HashedPostState {
548 HashedPostState::from_bundle_state::<KeccakKeyHasher>(bundle_state.state())
549 }
550}
551
552impl<
553 Provider: DBProvider
554 + BlockNumReader
555 + BlockHashReader
556 + ChangeSetReader
557 + StorageChangeSetReader
558 + StorageSettingsCache
559 + RocksDBProviderFactory
560 + NodePrimitivesProvider,
561 > StateProvider for HistoricalStateProviderRef<'_, Provider>
562{
563 fn storage(
565 &self,
566 address: Address,
567 storage_key: StorageKey,
568 ) -> ProviderResult<Option<StorageValue>> {
569 self.storage_by_lookup_key(address, storage_key)
570 }
571}
572
573impl<Provider: DBProvider + BlockNumReader> BytecodeReader
574 for HistoricalStateProviderRef<'_, Provider>
575{
576 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
578 self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
579 }
580}
581
582#[derive(Debug)]
585pub struct HistoricalStateProvider<Provider> {
586 provider: Provider,
588 block_number: BlockNumber,
590 lowest_available_blocks: LowestAvailableBlocks,
592}
593
594impl<Provider: DBProvider + ChangeSetReader + StorageChangeSetReader + BlockNumReader>
595 HistoricalStateProvider<Provider>
596{
597 pub fn new(provider: Provider, block_number: BlockNumber) -> Self {
599 Self { provider, block_number, lowest_available_blocks: Default::default() }
600 }
601
602 pub const fn with_lowest_available_account_history_block_number(
604 mut self,
605 block_number: BlockNumber,
606 ) -> Self {
607 self.lowest_available_blocks.account_history_block_number = Some(block_number);
608 self
609 }
610
611 pub const fn with_lowest_available_storage_history_block_number(
613 mut self,
614 block_number: BlockNumber,
615 ) -> Self {
616 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
617 self
618 }
619
620 #[inline(always)]
622 const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
623 HistoricalStateProviderRef::new_with_lowest_available_blocks(
624 &self.provider,
625 self.block_number,
626 self.lowest_available_blocks,
627 )
628 }
629}
630
631reth_storage_api::macros::delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + ChangeSetReader + StorageChangeSetReader + StorageSettingsCache + RocksDBProviderFactory + NodePrimitivesProvider]);
633
634#[derive(Clone, Copy, Debug, Default)]
637pub struct LowestAvailableBlocks {
638 pub account_history_block_number: Option<BlockNumber>,
642 pub storage_history_block_number: Option<BlockNumber>,
646}
647
648impl LowestAvailableBlocks {
649 pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
652 self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
653 }
654
655 pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
658 self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
659 }
660}
661
662#[inline]
674pub fn compute_history_rank(
675 chunk: &reth_db_api::BlockNumberList,
676 block_number: BlockNumber,
677) -> (u64, Option<u64>) {
678 let mut rank = chunk.rank(block_number);
679 if rank.checked_sub(1).and_then(|r| chunk.select(r)) == Some(block_number) {
683 rank -= 1;
684 }
685 (rank, chunk.select(rank))
686}
687
688#[inline]
693pub fn needs_prev_shard_check(
694 rank: u64,
695 found_block: Option<u64>,
696 block_number: BlockNumber,
697) -> bool {
698 rank == 0 && found_block != Some(block_number)
699}
700
701pub fn history_info<T, K, C>(
706 cursor: &mut C,
707 key: K,
708 block_number: BlockNumber,
709 key_filter: impl Fn(&K) -> bool,
710 lowest_available_block_number: Option<BlockNumber>,
711) -> ProviderResult<HistoryInfo>
712where
713 T: Table<Key = K, Value = BlockNumberList>,
714 C: DbCursorRO<T>,
715{
716 if let Some(chunk) = cursor.seek(key)?.filter(|(k, _)| key_filter(k)).map(|x| x.1) {
720 let (rank, found_block) = compute_history_rank(&chunk, block_number);
721
722 let is_before_first_write = needs_prev_shard_check(rank, found_block, block_number) &&
729 !cursor.prev()?.is_some_and(|(k, _)| key_filter(&k));
730
731 Ok(HistoryInfo::from_lookup(
732 found_block,
733 is_before_first_write,
734 lowest_available_block_number,
735 ))
736 } else if lowest_available_block_number.is_some() {
737 Ok(HistoryInfo::MaybeInPlainState)
740 } else {
741 Ok(HistoryInfo::NotYetWritten)
743 }
744}
745
746#[cfg(test)]
747mod tests {
748 use super::needs_prev_shard_check;
749 use crate::{
750 providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
751 test_utils::create_test_provider_factory,
752 AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, RocksDBProviderFactory,
753 StateProvider,
754 };
755 use alloy_primitives::{address, b256, Address, B256, U256};
756 use reth_db_api::{
757 models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
758 tables,
759 transaction::{DbTx, DbTxMut},
760 BlockNumberList,
761 };
762 use reth_primitives_traits::{Account, StorageEntry};
763 use reth_storage_api::{
764 BlockHashReader, BlockNumReader, ChangeSetReader, DBProvider, DatabaseProviderFactory,
765 NodePrimitivesProvider, StorageChangeSetReader, StorageSettingsCache,
766 };
767 use reth_storage_errors::provider::ProviderError;
768
769 const ADDRESS: Address = address!("0x0000000000000000000000000000000000000001");
770 const HIGHER_ADDRESS: Address = address!("0x0000000000000000000000000000000000000005");
771 const STORAGE: B256 =
772 b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
773
774 const fn assert_state_provider<T: StateProvider>() {}
775 #[expect(dead_code)]
776 const fn assert_historical_state_provider<
777 T: DBProvider
778 + BlockNumReader
779 + BlockHashReader
780 + ChangeSetReader
781 + StorageChangeSetReader
782 + StorageSettingsCache
783 + RocksDBProviderFactory
784 + NodePrimitivesProvider,
785 >() {
786 assert_state_provider::<HistoricalStateProvider<T>>();
787 }
788
789 #[test]
790 fn history_provider_get_account() {
791 let factory = create_test_provider_factory();
792 let tx = factory.provider_rw().unwrap().into_tx();
793
794 tx.put::<tables::AccountsHistory>(
795 ShardedKey { key: ADDRESS, highest_block_number: 7 },
796 BlockNumberList::new([1, 3, 7]).unwrap(),
797 )
798 .unwrap();
799 tx.put::<tables::AccountsHistory>(
800 ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
801 BlockNumberList::new([10, 15]).unwrap(),
802 )
803 .unwrap();
804 tx.put::<tables::AccountsHistory>(
805 ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
806 BlockNumberList::new([4]).unwrap(),
807 )
808 .unwrap();
809
810 let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
811 let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
812 let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
813 let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
814 let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
815
816 let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
817
818 tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
820 .unwrap();
821 tx.put::<tables::AccountChangeSets>(
822 3,
823 AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
824 )
825 .unwrap();
826 tx.put::<tables::AccountChangeSets>(
827 4,
828 AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
829 )
830 .unwrap();
831 tx.put::<tables::AccountChangeSets>(
832 7,
833 AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
834 )
835 .unwrap();
836 tx.put::<tables::AccountChangeSets>(
837 10,
838 AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
839 )
840 .unwrap();
841 tx.put::<tables::AccountChangeSets>(
842 15,
843 AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
844 )
845 .unwrap();
846
847 tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
849 tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
850 tx.commit().unwrap();
851
852 let db = factory.provider().unwrap();
853
854 assert!(matches!(
856 HistoricalStateProviderRef::new(&db, 1).basic_account(&ADDRESS),
857 Ok(None)
858 ));
859 assert!(matches!(
860 HistoricalStateProviderRef::new(&db, 2).basic_account(&ADDRESS),
861 Ok(Some(acc)) if acc == acc_at3
862 ));
863 assert!(matches!(
864 HistoricalStateProviderRef::new(&db, 3).basic_account(&ADDRESS),
865 Ok(Some(acc)) if acc == acc_at3
866 ));
867 assert!(matches!(
868 HistoricalStateProviderRef::new(&db, 4).basic_account(&ADDRESS),
869 Ok(Some(acc)) if acc == acc_at7
870 ));
871 assert!(matches!(
872 HistoricalStateProviderRef::new(&db, 7).basic_account(&ADDRESS),
873 Ok(Some(acc)) if acc == acc_at7
874 ));
875 assert!(matches!(
876 HistoricalStateProviderRef::new(&db, 9).basic_account(&ADDRESS),
877 Ok(Some(acc)) if acc == acc_at10
878 ));
879 assert!(matches!(
880 HistoricalStateProviderRef::new(&db, 10).basic_account(&ADDRESS),
881 Ok(Some(acc)) if acc == acc_at10
882 ));
883 assert!(matches!(
884 HistoricalStateProviderRef::new(&db, 11).basic_account(&ADDRESS),
885 Ok(Some(acc)) if acc == acc_at15
886 ));
887 assert!(matches!(
888 HistoricalStateProviderRef::new(&db, 16).basic_account(&ADDRESS),
889 Ok(Some(acc)) if acc == acc_plain
890 ));
891
892 assert!(matches!(
893 HistoricalStateProviderRef::new(&db, 1).basic_account(&HIGHER_ADDRESS),
894 Ok(None)
895 ));
896 assert!(matches!(
897 HistoricalStateProviderRef::new(&db, 1000).basic_account(&HIGHER_ADDRESS),
898 Ok(Some(acc)) if acc == higher_acc_plain
899 ));
900 }
901
902 #[test]
903 fn history_provider_get_storage() {
904 let factory = create_test_provider_factory();
905 let tx = factory.provider_rw().unwrap().into_tx();
906
907 tx.put::<tables::StoragesHistory>(
908 StorageShardedKey {
909 address: ADDRESS,
910 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
911 },
912 BlockNumberList::new([3, 7]).unwrap(),
913 )
914 .unwrap();
915 tx.put::<tables::StoragesHistory>(
916 StorageShardedKey {
917 address: ADDRESS,
918 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
919 },
920 BlockNumberList::new([10, 15]).unwrap(),
921 )
922 .unwrap();
923 tx.put::<tables::StoragesHistory>(
924 StorageShardedKey {
925 address: HIGHER_ADDRESS,
926 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
927 },
928 BlockNumberList::new([4]).unwrap(),
929 )
930 .unwrap();
931
932 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
933 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
934 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
935 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
936 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
937 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
938 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
939
940 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
942 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
943 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
944 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
945 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
946
947 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
949 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
950 tx.commit().unwrap();
951
952 let db = factory.provider().unwrap();
953
954 assert!(matches!(
956 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
957 Ok(None)
958 ));
959 assert!(matches!(
960 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
961 Ok(Some(U256::ZERO))
962 ));
963 assert!(matches!(
964 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
965 Ok(Some(expected_value)) if expected_value == entry_at7.value
966 ));
967 assert!(matches!(
968 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
969 Ok(Some(expected_value)) if expected_value == entry_at7.value
970 ));
971 assert!(matches!(
972 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
973 Ok(Some(expected_value)) if expected_value == entry_at10.value
974 ));
975 assert!(matches!(
976 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
977 Ok(Some(expected_value)) if expected_value == entry_at10.value
978 ));
979 assert!(matches!(
980 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
981 Ok(Some(expected_value)) if expected_value == entry_at15.value
982 ));
983 assert!(matches!(
984 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
985 Ok(Some(expected_value)) if expected_value == entry_plain.value
986 ));
987 assert!(matches!(
988 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
989 Ok(None)
990 ));
991 assert!(matches!(
992 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
993 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
994 ));
995 }
996
997 #[test]
998 fn history_provider_unavailable() {
999 let factory = create_test_provider_factory();
1000 let db = factory.database_provider_rw().unwrap();
1001
1002 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1005 &db,
1006 2,
1007 LowestAvailableBlocks {
1008 account_history_block_number: Some(3),
1009 storage_history_block_number: Some(3),
1010 },
1011 );
1012 assert!(matches!(
1013 provider.account_history_lookup(ADDRESS),
1014 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1015 ));
1016 assert!(matches!(
1017 provider.storage_history_lookup(ADDRESS, STORAGE),
1018 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
1019 ));
1020
1021 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1024 &db,
1025 2,
1026 LowestAvailableBlocks {
1027 account_history_block_number: Some(2),
1028 storage_history_block_number: Some(2),
1029 },
1030 );
1031 assert!(matches!(
1032 provider.account_history_lookup(ADDRESS),
1033 Ok(HistoryInfo::MaybeInPlainState)
1034 ));
1035 assert!(matches!(
1036 provider.storage_history_lookup(ADDRESS, STORAGE),
1037 Ok(HistoryInfo::MaybeInPlainState)
1038 ));
1039
1040 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
1043 &db,
1044 2,
1045 LowestAvailableBlocks {
1046 account_history_block_number: Some(1),
1047 storage_history_block_number: Some(1),
1048 },
1049 );
1050 assert!(matches!(
1051 provider.account_history_lookup(ADDRESS),
1052 Ok(HistoryInfo::MaybeInPlainState)
1053 ));
1054 assert!(matches!(
1055 provider.storage_history_lookup(ADDRESS, STORAGE),
1056 Ok(HistoryInfo::MaybeInPlainState)
1057 ));
1058 }
1059
1060 #[test]
1061 fn test_history_info_from_lookup() {
1062 assert_eq!(HistoryInfo::from_lookup(Some(10), true, None), HistoryInfo::NotYetWritten);
1064 assert_eq!(HistoryInfo::from_lookup(None, true, None), HistoryInfo::NotYetWritten);
1065
1066 assert_eq!(HistoryInfo::from_lookup(Some(10), true, Some(5)), HistoryInfo::InChangeset(10));
1068 assert_eq!(HistoryInfo::from_lookup(None, true, Some(5)), HistoryInfo::NotYetWritten);
1069
1070 assert_eq!(HistoryInfo::from_lookup(Some(10), false, None), HistoryInfo::InChangeset(10));
1072 assert_eq!(HistoryInfo::from_lookup(None, false, None), HistoryInfo::InPlainState);
1073 }
1074
1075 #[test]
1076 fn history_provider_get_storage_legacy() {
1077 let factory = create_test_provider_factory();
1078
1079 assert!(!factory.provider().unwrap().cached_storage_settings().use_hashed_state());
1080
1081 let tx = factory.provider_rw().unwrap().into_tx();
1082
1083 tx.put::<tables::StoragesHistory>(
1084 StorageShardedKey {
1085 address: ADDRESS,
1086 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
1087 },
1088 BlockNumberList::new([3, 7]).unwrap(),
1089 )
1090 .unwrap();
1091 tx.put::<tables::StoragesHistory>(
1092 StorageShardedKey {
1093 address: ADDRESS,
1094 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1095 },
1096 BlockNumberList::new([10, 15]).unwrap(),
1097 )
1098 .unwrap();
1099 tx.put::<tables::StoragesHistory>(
1100 StorageShardedKey {
1101 address: HIGHER_ADDRESS,
1102 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
1103 },
1104 BlockNumberList::new([4]).unwrap(),
1105 )
1106 .unwrap();
1107
1108 let higher_entry_plain = StorageEntry { key: STORAGE, value: U256::from(1000) };
1109 let higher_entry_at4 = StorageEntry { key: STORAGE, value: U256::from(0) };
1110 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100) };
1111 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15) };
1112 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10) };
1113 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7) };
1114 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0) };
1115
1116 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
1117 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
1118 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
1119 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
1120 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
1121
1122 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
1123 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
1124 tx.commit().unwrap();
1125
1126 let db = factory.provider().unwrap();
1127
1128 assert!(matches!(
1129 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
1130 Ok(None)
1131 ));
1132 assert!(matches!(
1133 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
1134 Ok(Some(U256::ZERO))
1135 ));
1136 assert!(matches!(
1137 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
1138 Ok(Some(expected_value)) if expected_value == entry_at7.value
1139 ));
1140 assert!(matches!(
1141 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
1142 Ok(Some(expected_value)) if expected_value == entry_at7.value
1143 ));
1144 assert!(matches!(
1145 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
1146 Ok(Some(expected_value)) if expected_value == entry_at10.value
1147 ));
1148 assert!(matches!(
1149 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
1150 Ok(Some(expected_value)) if expected_value == entry_at10.value
1151 ));
1152 assert!(matches!(
1153 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
1154 Ok(Some(expected_value)) if expected_value == entry_at15.value
1155 ));
1156 assert!(matches!(
1157 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
1158 Ok(Some(expected_value)) if expected_value == entry_plain.value
1159 ));
1160 assert!(matches!(
1161 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
1162 Ok(None)
1163 ));
1164 assert!(matches!(
1165 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
1166 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value
1167 ));
1168 }
1169
1170 #[test]
1171 fn history_provider_get_storage_hashed_state() {
1172 use crate::BlockWriter;
1173 use alloy_primitives::keccak256;
1174 use reth_db_api::models::StorageSettings;
1175 use reth_execution_types::ExecutionOutcome;
1176 use reth_testing_utils::generators::{self, random_block_range, BlockRangeParams};
1177 use revm_database::BundleState;
1178 use std::collections::HashMap;
1179
1180 let factory = create_test_provider_factory();
1181 factory.set_storage_settings_cache(StorageSettings::v2());
1182
1183 let slot = U256::from_be_bytes(*STORAGE);
1184 let account: revm_state::AccountInfo =
1185 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None }.into();
1186 let higher_account: revm_state::AccountInfo =
1187 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None }.into();
1188
1189 let mut rng = generators::rng();
1190 let blocks = random_block_range(
1191 &mut rng,
1192 0..=15,
1193 BlockRangeParams { parent: Some(B256::ZERO), tx_count: 0..1, ..Default::default() },
1194 );
1195
1196 let mut addr_storage = HashMap::default();
1197 addr_storage.insert(slot, (U256::ZERO, U256::from(100)));
1198 let mut higher_storage = HashMap::default();
1199 higher_storage.insert(slot, (U256::ZERO, U256::from(1000)));
1200
1201 type Revert = Vec<(Address, Option<Option<revm_state::AccountInfo>>, Vec<(U256, U256)>)>;
1202 let mut reverts: Vec<Revert> = vec![Vec::new(); 16];
1203
1204 reverts[3] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::ZERO)])];
1205 reverts[4] =
1206 vec![(HIGHER_ADDRESS, Some(Some(higher_account.clone())), vec![(slot, U256::ZERO)])];
1207 reverts[7] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(7))])];
1208 reverts[10] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(10))])];
1209 reverts[15] = vec![(ADDRESS, Some(Some(account.clone())), vec![(slot, U256::from(15))])];
1210
1211 let bundle = BundleState::new(
1212 [
1213 (ADDRESS, None, Some(account), addr_storage),
1214 (HIGHER_ADDRESS, None, Some(higher_account), higher_storage),
1215 ],
1216 reverts,
1217 [],
1218 );
1219
1220 let provider_rw = factory.provider_rw().unwrap();
1221 provider_rw
1222 .append_blocks_with_state(
1223 blocks
1224 .into_iter()
1225 .map(|b| b.try_recover().expect("failed to seal block with senders"))
1226 .collect(),
1227 &ExecutionOutcome { bundle, first_block: 0, ..Default::default() },
1228 Default::default(),
1229 )
1230 .unwrap();
1231
1232 let hashed_address = keccak256(ADDRESS);
1233 let hashed_higher_address = keccak256(HIGHER_ADDRESS);
1234 let hashed_storage = keccak256(STORAGE);
1235
1236 provider_rw
1237 .tx_ref()
1238 .put::<tables::HashedStorages>(
1239 hashed_address,
1240 StorageEntry { key: hashed_storage, value: U256::from(100) },
1241 )
1242 .unwrap();
1243 provider_rw
1244 .tx_ref()
1245 .put::<tables::HashedStorages>(
1246 hashed_higher_address,
1247 StorageEntry { key: hashed_storage, value: U256::from(1000) },
1248 )
1249 .unwrap();
1250 provider_rw
1251 .tx_ref()
1252 .put::<tables::HashedAccounts>(
1253 hashed_address,
1254 Account { nonce: 1, balance: U256::from(1000), bytecode_hash: None },
1255 )
1256 .unwrap();
1257 provider_rw
1258 .tx_ref()
1259 .put::<tables::HashedAccounts>(
1260 hashed_higher_address,
1261 Account { nonce: 1, balance: U256::from(2000), bytecode_hash: None },
1262 )
1263 .unwrap();
1264 provider_rw.commit().unwrap();
1265
1266 let db = factory.provider().unwrap();
1267
1268 assert!(matches!(
1269 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
1270 Ok(None)
1271 ));
1272 assert!(matches!(
1273 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
1274 Ok(Some(U256::ZERO))
1275 ));
1276 assert!(matches!(
1277 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
1278 Ok(Some(v)) if v == U256::from(7)
1279 ));
1280 assert!(matches!(
1281 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
1282 Ok(Some(v)) if v == U256::from(7)
1283 ));
1284 assert!(matches!(
1285 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
1286 Ok(Some(v)) if v == U256::from(10)
1287 ));
1288 assert!(matches!(
1289 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
1290 Ok(Some(v)) if v == U256::from(10)
1291 ));
1292 assert!(matches!(
1293 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
1294 Ok(Some(v)) if v == U256::from(15)
1295 ));
1296 assert!(matches!(
1297 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
1298 Ok(Some(v)) if v == U256::from(100)
1299 ));
1300 assert!(matches!(
1301 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
1302 Ok(None)
1303 ));
1304 assert!(matches!(
1305 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
1306 Ok(Some(v)) if v == U256::from(1000)
1307 ));
1308 }
1309
1310 #[test]
1311 fn test_needs_prev_shard_check() {
1312 assert!(needs_prev_shard_check(0, Some(10), 5));
1314 assert!(needs_prev_shard_check(0, None, 5));
1315 assert!(!needs_prev_shard_check(0, Some(5), 5)); assert!(!needs_prev_shard_check(1, Some(10), 5)); }
1318}