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