1use crate::{
2 providers::state::macros::delegate_provider_impls, AccountReader, BlockHashReader,
3 HashedPostStateProvider, ProviderError, StateProvider, StateRootProvider,
4};
5use alloy_eips::merge::EPOCH_SLOTS;
6use alloy_primitives::{Address, BlockNumber, Bytes, StorageKey, B256};
7use reth_db_api::{
8 cursor::{DbCursorRO, DbDupCursorRO},
9 models::{storage_sharded_key::StorageShardedKey, ShardedKey},
10 table::Table,
11 tables,
12 transaction::DbTx,
13 BlockNumberList,
14};
15use reth_primitives_traits::{Account, Bytecode};
16use reth_storage_api::{
17 BlockNumReader, DBProvider, StateCommitmentProvider, StateProofProvider, StorageRootProvider,
18};
19use reth_storage_errors::provider::ProviderResult;
20use reth_trie::{
21 proof::{Proof, StorageProof},
22 updates::TrieUpdates,
23 witness::TrieWitness,
24 AccountProof, HashedPostState, HashedStorage, MultiProof, MultiProofTargets, StateRoot,
25 StorageMultiProof, StorageRoot, TrieInput,
26};
27use reth_trie_db::{
28 DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot,
29 DatabaseStorageProof, DatabaseStorageRoot, DatabaseTrieWitness, StateCommitment,
30};
31use revm_state::FlaggedStorage;
32use std::fmt::Debug;
33
34#[derive(Debug)]
46pub struct HistoricalStateProviderRef<'b, Provider> {
47 provider: &'b Provider,
49 block_number: BlockNumber,
51 lowest_available_blocks: LowestAvailableBlocks,
53}
54
55#[derive(Debug, Eq, PartialEq)]
56pub enum HistoryInfo {
57 NotYetWritten,
58 InChangeset(u64),
59 InPlainState,
60 MaybeInPlainState,
61}
62
63impl<'b, Provider: DBProvider + BlockNumReader + StateCommitmentProvider>
64 HistoricalStateProviderRef<'b, Provider>
65{
66 pub fn new(provider: &'b Provider, block_number: BlockNumber) -> Self {
68 Self { provider, block_number, lowest_available_blocks: Default::default() }
69 }
70
71 pub const fn new_with_lowest_available_blocks(
74 provider: &'b Provider,
75 block_number: BlockNumber,
76 lowest_available_blocks: LowestAvailableBlocks,
77 ) -> Self {
78 Self { provider, block_number, lowest_available_blocks }
79 }
80
81 pub fn account_history_lookup(&self, address: Address) -> ProviderResult<HistoryInfo> {
83 if !self.lowest_available_blocks.is_account_history_available(self.block_number) {
84 return Err(ProviderError::StateAtBlockPruned(self.block_number))
85 }
86
87 let history_key = ShardedKey::new(address, self.block_number);
89 self.history_info::<tables::AccountsHistory, _>(
90 history_key,
91 |key| key.key == address,
92 self.lowest_available_blocks.account_history_block_number,
93 )
94 }
95
96 pub fn storage_history_lookup(
98 &self,
99 address: Address,
100 storage_key: StorageKey,
101 ) -> ProviderResult<HistoryInfo> {
102 if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
103 return Err(ProviderError::StateAtBlockPruned(self.block_number))
104 }
105
106 let history_key = StorageShardedKey::new(address, storage_key, self.block_number);
108 self.history_info::<tables::StoragesHistory, _>(
109 history_key,
110 |key| key.address == address && key.sharded_key.key == storage_key,
111 self.lowest_available_blocks.storage_history_block_number,
112 )
113 }
114
115 fn check_distance_against_limit(&self, limit: u64) -> ProviderResult<bool> {
117 let tip = self.provider.last_block_number()?;
118
119 Ok(tip.saturating_sub(self.block_number) > limit)
120 }
121
122 fn revert_state(&self) -> ProviderResult<HashedPostState> {
124 if !self.lowest_available_blocks.is_account_history_available(self.block_number) ||
125 !self.lowest_available_blocks.is_storage_history_available(self.block_number)
126 {
127 return Err(ProviderError::StateAtBlockPruned(self.block_number))
128 }
129
130 if self.check_distance_against_limit(EPOCH_SLOTS)? {
131 tracing::warn!(
132 target: "provider::historical_sp",
133 target = self.block_number,
134 "Attempt to calculate state root for an old block might result in OOM"
135 );
136 }
137
138 Ok(HashedPostState::from_reverts::<
139 <Provider::StateCommitment as StateCommitment>::KeyHasher,
140 >(self.tx(), self.block_number)?)
141 }
142
143 fn revert_storage(&self, address: Address) -> ProviderResult<HashedStorage> {
145 if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
146 return Err(ProviderError::StateAtBlockPruned(self.block_number))
147 }
148
149 if self.check_distance_against_limit(EPOCH_SLOTS * 10)? {
150 tracing::warn!(
151 target: "provider::historical_sp",
152 target = self.block_number,
153 "Attempt to calculate storage root for an old block might result in OOM"
154 );
155 }
156
157 Ok(HashedStorage::from_reverts(self.tx(), address, self.block_number)?)
158 }
159
160 fn history_info<T, K>(
161 &self,
162 key: K,
163 key_filter: impl Fn(&K) -> bool,
164 lowest_available_block_number: Option<BlockNumber>,
165 ) -> ProviderResult<HistoryInfo>
166 where
167 T: Table<Key = K, Value = BlockNumberList>,
168 {
169 let mut cursor = self.tx().cursor_read::<T>()?;
170
171 if let Some(chunk) = cursor.seek(key)?.filter(|(key, _)| key_filter(key)).map(|x| x.1 .0) {
175 let mut rank = chunk.rank(self.block_number);
177
178 if rank.checked_sub(1).and_then(|rank| chunk.select(rank)) == Some(self.block_number) {
181 rank -= 1
182 };
183
184 let block_number = chunk.select(rank);
185
186 if rank == 0 &&
193 block_number != Some(self.block_number) &&
194 !cursor.prev()?.is_some_and(|(key, _)| key_filter(&key))
195 {
196 if let (Some(_), Some(block_number)) = (lowest_available_block_number, block_number)
197 {
198 Ok(HistoryInfo::InChangeset(block_number))
201 } else {
202 Ok(HistoryInfo::NotYetWritten)
204 }
205 } else if let Some(block_number) = block_number {
206 Ok(HistoryInfo::InChangeset(block_number))
208 } else {
209 Ok(HistoryInfo::InPlainState)
212 }
213 } else if lowest_available_block_number.is_some() {
214 Ok(HistoryInfo::MaybeInPlainState)
217 } else {
218 Ok(HistoryInfo::NotYetWritten)
220 }
221 }
222
223 pub const fn with_lowest_available_account_history_block_number(
225 mut self,
226 block_number: BlockNumber,
227 ) -> Self {
228 self.lowest_available_blocks.account_history_block_number = Some(block_number);
229 self
230 }
231
232 pub const fn with_lowest_available_storage_history_block_number(
234 mut self,
235 block_number: BlockNumber,
236 ) -> Self {
237 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
238 self
239 }
240}
241
242impl<Provider: DBProvider + BlockNumReader> HistoricalStateProviderRef<'_, Provider> {
243 fn tx(&self) -> &Provider::Tx {
244 self.provider.tx_ref()
245 }
246}
247
248impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> AccountReader
249 for HistoricalStateProviderRef<'_, Provider>
250{
251 fn basic_account(&self, address: &Address) -> ProviderResult<Option<Account>> {
253 match self.account_history_lookup(*address)? {
254 HistoryInfo::NotYetWritten => Ok(None),
255 HistoryInfo::InChangeset(changeset_block_number) => Ok(self
256 .tx()
257 .cursor_dup_read::<tables::AccountChangeSets>()?
258 .seek_by_key_subkey(changeset_block_number, *address)?
259 .filter(|acc| &acc.address == address)
260 .ok_or(ProviderError::AccountChangesetNotFound {
261 block_number: changeset_block_number,
262 address: *address,
263 })?
264 .info),
265 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
266 Ok(self.tx().get_by_encoded_key::<tables::PlainAccountState>(address)?)
267 }
268 }
269 }
270}
271
272impl<Provider: DBProvider + BlockNumReader + BlockHashReader> BlockHashReader
273 for HistoricalStateProviderRef<'_, Provider>
274{
275 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
277 self.provider.block_hash(number)
278 }
279
280 fn canonical_hashes_range(
281 &self,
282 start: BlockNumber,
283 end: BlockNumber,
284 ) -> ProviderResult<Vec<B256>> {
285 self.provider.canonical_hashes_range(start, end)
286 }
287}
288
289impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StateRootProvider
290 for HistoricalStateProviderRef<'_, Provider>
291{
292 fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
293 let mut revert_state = self.revert_state()?;
294 revert_state.extend(hashed_state);
295 StateRoot::overlay_root(self.tx(), revert_state)
296 .map_err(|err| ProviderError::Database(err.into()))
297 }
298
299 fn state_root_from_nodes(&self, mut input: TrieInput) -> ProviderResult<B256> {
300 input.prepend(self.revert_state()?);
301 StateRoot::overlay_root_from_nodes(self.tx(), input)
302 .map_err(|err| ProviderError::Database(err.into()))
303 }
304
305 fn state_root_with_updates(
306 &self,
307 hashed_state: HashedPostState,
308 ) -> ProviderResult<(B256, TrieUpdates)> {
309 let mut revert_state = self.revert_state()?;
310 revert_state.extend(hashed_state);
311 StateRoot::overlay_root_with_updates(self.tx(), revert_state)
312 .map_err(|err| ProviderError::Database(err.into()))
313 }
314
315 fn state_root_from_nodes_with_updates(
316 &self,
317 mut input: TrieInput,
318 ) -> ProviderResult<(B256, TrieUpdates)> {
319 input.prepend(self.revert_state()?);
320 StateRoot::overlay_root_from_nodes_with_updates(self.tx(), input)
321 .map_err(|err| ProviderError::Database(err.into()))
322 }
323}
324
325impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StorageRootProvider
326 for HistoricalStateProviderRef<'_, Provider>
327{
328 fn storage_root(
329 &self,
330 address: Address,
331 hashed_storage: HashedStorage,
332 ) -> ProviderResult<B256> {
333 let mut revert_storage = self.revert_storage(address)?;
334 revert_storage.extend(&hashed_storage);
335 StorageRoot::overlay_root(self.tx(), address, revert_storage)
336 .map_err(|err| ProviderError::Database(err.into()))
337 }
338
339 fn storage_proof(
340 &self,
341 address: Address,
342 slot: B256,
343 hashed_storage: HashedStorage,
344 ) -> ProviderResult<reth_trie::StorageProof> {
345 let mut revert_storage = self.revert_storage(address)?;
346 revert_storage.extend(&hashed_storage);
347 StorageProof::overlay_storage_proof(self.tx(), address, slot, revert_storage)
348 .map_err(ProviderError::from)
349 }
350
351 fn storage_multiproof(
352 &self,
353 address: Address,
354 slots: &[B256],
355 hashed_storage: HashedStorage,
356 ) -> ProviderResult<StorageMultiProof> {
357 let mut revert_storage = self.revert_storage(address)?;
358 revert_storage.extend(&hashed_storage);
359 StorageProof::overlay_storage_multiproof(self.tx(), address, slots, revert_storage)
360 .map_err(ProviderError::from)
361 }
362}
363
364impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StateProofProvider
365 for HistoricalStateProviderRef<'_, Provider>
366{
367 fn proof(
369 &self,
370 mut input: TrieInput,
371 address: Address,
372 slots: &[B256],
373 ) -> ProviderResult<AccountProof> {
374 input.prepend(self.revert_state()?);
375 Proof::overlay_account_proof(self.tx(), input, address, slots).map_err(ProviderError::from)
376 }
377
378 fn multiproof(
379 &self,
380 mut input: TrieInput,
381 targets: MultiProofTargets,
382 ) -> ProviderResult<MultiProof> {
383 input.prepend(self.revert_state()?);
384 Proof::overlay_multiproof(self.tx(), input, targets).map_err(ProviderError::from)
385 }
386
387 fn witness(&self, mut input: TrieInput, target: HashedPostState) -> ProviderResult<Vec<Bytes>> {
388 input.prepend(self.revert_state()?);
389 TrieWitness::overlay_witness(self.tx(), input, target)
390 .map_err(ProviderError::from)
391 .map(|hm| hm.into_values().collect())
392 }
393}
394
395impl<Provider: StateCommitmentProvider> HashedPostStateProvider
396 for HistoricalStateProviderRef<'_, Provider>
397{
398 fn hashed_post_state(&self, bundle_state: &revm_database::BundleState) -> HashedPostState {
399 HashedPostState::from_bundle_state::<
400 <Provider::StateCommitment as StateCommitment>::KeyHasher,
401 >(bundle_state.state())
402 }
403}
404
405impl<Provider: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider>
406 StateProvider for HistoricalStateProviderRef<'_, Provider>
407{
408 fn storage(
410 &self,
411 address: Address,
412 storage_key: StorageKey,
413 ) -> ProviderResult<Option<FlaggedStorage>> {
414 match self.storage_history_lookup(address, storage_key)? {
415 HistoryInfo::NotYetWritten => Ok(None),
416 HistoryInfo::InChangeset(changeset_block_number) => Ok(Some(
417 self.tx()
418 .cursor_dup_read::<tables::StorageChangeSets>()?
419 .seek_by_key_subkey((changeset_block_number, address).into(), storage_key)?
420 .filter(|entry| entry.key == storage_key)
421 .ok_or_else(|| ProviderError::StorageChangesetNotFound {
422 block_number: changeset_block_number,
423 address,
424 storage_key: Box::new(storage_key),
425 })?
426 .into(),
427 )),
428 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => Ok(self
429 .tx()
430 .cursor_dup_read::<tables::PlainStorageState>()?
431 .seek_by_key_subkey(address, storage_key)?
432 .filter(|entry| entry.key == storage_key)
433 .map(|entry| entry.into())
434 .or(Some(FlaggedStorage::ZERO))),
435 }
436 }
437
438 fn bytecode_by_hash(&self, code_hash: &B256) -> ProviderResult<Option<Bytecode>> {
440 self.tx().get_by_encoded_key::<tables::Bytecodes>(code_hash).map_err(Into::into)
441 }
442}
443
444impl<Provider: StateCommitmentProvider> StateCommitmentProvider
445 for HistoricalStateProviderRef<'_, Provider>
446{
447 type StateCommitment = Provider::StateCommitment;
448}
449
450#[derive(Debug)]
453pub struct HistoricalStateProvider<Provider> {
454 provider: Provider,
456 block_number: BlockNumber,
458 lowest_available_blocks: LowestAvailableBlocks,
460}
461
462impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider>
463 HistoricalStateProvider<Provider>
464{
465 pub fn new(provider: Provider, block_number: BlockNumber) -> Self {
467 Self { provider, block_number, lowest_available_blocks: Default::default() }
468 }
469
470 pub const fn with_lowest_available_account_history_block_number(
472 mut self,
473 block_number: BlockNumber,
474 ) -> Self {
475 self.lowest_available_blocks.account_history_block_number = Some(block_number);
476 self
477 }
478
479 pub const fn with_lowest_available_storage_history_block_number(
481 mut self,
482 block_number: BlockNumber,
483 ) -> Self {
484 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
485 self
486 }
487
488 #[inline(always)]
490 const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
491 HistoricalStateProviderRef::new_with_lowest_available_blocks(
492 &self.provider,
493 self.block_number,
494 self.lowest_available_blocks,
495 )
496 }
497}
498
499impl<Provider: StateCommitmentProvider> StateCommitmentProvider
500 for HistoricalStateProvider<Provider>
501{
502 type StateCommitment = Provider::StateCommitment;
503}
504
505delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider]);
507
508#[derive(Clone, Copy, Debug, Default)]
511pub struct LowestAvailableBlocks {
512 pub account_history_block_number: Option<BlockNumber>,
516 pub storage_history_block_number: Option<BlockNumber>,
520}
521
522impl LowestAvailableBlocks {
523 pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
526 self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
527 }
528
529 pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
532 self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
533 }
534}
535
536#[cfg(test)]
537mod tests {
538 use crate::{
539 providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
540 test_utils::create_test_provider_factory,
541 AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, StateProvider,
542 };
543 use alloy_primitives::{address, b256, Address, B256, U256};
544 use reth_db_api::{
545 models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
546 tables,
547 transaction::{DbTx, DbTxMut},
548 BlockNumberList,
549 };
550 use reth_primitives_traits::{Account, StorageEntry};
551 use reth_storage_api::{
552 BlockHashReader, BlockNumReader, DBProvider, DatabaseProviderFactory,
553 StateCommitmentProvider,
554 };
555 use reth_storage_errors::provider::ProviderError;
556 use revm_state::FlaggedStorage;
557
558 const ADDRESS: Address = address!("0x0000000000000000000000000000000000000001");
559 const HIGHER_ADDRESS: Address = address!("0x0000000000000000000000000000000000000005");
560 const STORAGE: B256 =
561 b256!("0x0000000000000000000000000000000000000000000000000000000000000001");
562
563 const fn assert_state_provider<T: StateProvider>() {}
564 #[expect(dead_code)]
565 const fn assert_historical_state_provider<
566 T: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider,
567 >() {
568 assert_state_provider::<HistoricalStateProvider<T>>();
569 }
570
571 #[test]
572 fn history_provider_get_account() {
573 let factory = create_test_provider_factory();
574 let tx = factory.provider_rw().unwrap().into_tx();
575
576 tx.put::<tables::AccountsHistory>(
577 ShardedKey { key: ADDRESS, highest_block_number: 7 },
578 BlockNumberList::new([1, 3, 7]).unwrap(),
579 )
580 .unwrap();
581 tx.put::<tables::AccountsHistory>(
582 ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
583 BlockNumberList::new([10, 15]).unwrap(),
584 )
585 .unwrap();
586 tx.put::<tables::AccountsHistory>(
587 ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
588 BlockNumberList::new([4]).unwrap(),
589 )
590 .unwrap();
591
592 let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
593 let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
594 let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
595 let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
596 let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
597
598 let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
599
600 tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
602 .unwrap();
603 tx.put::<tables::AccountChangeSets>(
604 3,
605 AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
606 )
607 .unwrap();
608 tx.put::<tables::AccountChangeSets>(
609 4,
610 AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
611 )
612 .unwrap();
613 tx.put::<tables::AccountChangeSets>(
614 7,
615 AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
616 )
617 .unwrap();
618 tx.put::<tables::AccountChangeSets>(
619 10,
620 AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
621 )
622 .unwrap();
623 tx.put::<tables::AccountChangeSets>(
624 15,
625 AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
626 )
627 .unwrap();
628
629 tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
631 tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
632 tx.commit().unwrap();
633
634 let db = factory.provider().unwrap();
635
636 assert!(matches!(
638 HistoricalStateProviderRef::new(&db, 1).basic_account(&ADDRESS),
639 Ok(None)
640 ));
641 assert!(matches!(
642 HistoricalStateProviderRef::new(&db, 2).basic_account(&ADDRESS),
643 Ok(Some(acc)) if acc == acc_at3
644 ));
645 assert!(matches!(
646 HistoricalStateProviderRef::new(&db, 3).basic_account(&ADDRESS),
647 Ok(Some(acc)) if acc == acc_at3
648 ));
649 assert!(matches!(
650 HistoricalStateProviderRef::new(&db, 4).basic_account(&ADDRESS),
651 Ok(Some(acc)) if acc == acc_at7
652 ));
653 assert!(matches!(
654 HistoricalStateProviderRef::new(&db, 7).basic_account(&ADDRESS),
655 Ok(Some(acc)) if acc == acc_at7
656 ));
657 assert!(matches!(
658 HistoricalStateProviderRef::new(&db, 9).basic_account(&ADDRESS),
659 Ok(Some(acc)) if acc == acc_at10
660 ));
661 assert!(matches!(
662 HistoricalStateProviderRef::new(&db, 10).basic_account(&ADDRESS),
663 Ok(Some(acc)) if acc == acc_at10
664 ));
665 assert!(matches!(
666 HistoricalStateProviderRef::new(&db, 11).basic_account(&ADDRESS),
667 Ok(Some(acc)) if acc == acc_at15
668 ));
669 assert!(matches!(
670 HistoricalStateProviderRef::new(&db, 16).basic_account(&ADDRESS),
671 Ok(Some(acc)) if acc == acc_plain
672 ));
673
674 assert!(matches!(
675 HistoricalStateProviderRef::new(&db, 1).basic_account(&HIGHER_ADDRESS),
676 Ok(None)
677 ));
678 assert!(matches!(
679 HistoricalStateProviderRef::new(&db, 1000).basic_account(&HIGHER_ADDRESS),
680 Ok(Some(acc)) if acc == higher_acc_plain
681 ));
682 }
683
684 #[test]
685 fn history_provider_get_storage() {
686 let factory = create_test_provider_factory();
687 let tx = factory.provider_rw().unwrap().into_tx();
688
689 tx.put::<tables::StoragesHistory>(
690 StorageShardedKey {
691 address: ADDRESS,
692 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
693 },
694 BlockNumberList::new([3, 7]).unwrap(),
695 )
696 .unwrap();
697 tx.put::<tables::StoragesHistory>(
698 StorageShardedKey {
699 address: ADDRESS,
700 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
701 },
702 BlockNumberList::new([10, 15]).unwrap(),
703 )
704 .unwrap();
705 tx.put::<tables::StoragesHistory>(
706 StorageShardedKey {
707 address: HIGHER_ADDRESS,
708 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
709 },
710 BlockNumberList::new([4]).unwrap(),
711 )
712 .unwrap();
713
714 let higher_entry_plain =
715 StorageEntry { key: STORAGE, value: U256::from(1000), is_private: false };
716 let higher_entry_at4 =
717 StorageEntry { key: STORAGE, value: U256::from(0), is_private: false };
718 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100), is_private: false };
719 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15), is_private: false };
720 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10), is_private: false };
721 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7), is_private: false };
722 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0), is_private: false };
723
724 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
726 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
727 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
728 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
729 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
730
731 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
733 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
734 tx.commit().unwrap();
735
736 let db = factory.provider().unwrap();
737
738 assert!(matches!(
740 HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE),
741 Ok(None)
742 ));
743 assert!(matches!(
744 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
745 Ok(Some(FlaggedStorage::ZERO))
746 ));
747 assert!(matches!(
748 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
749 Ok(Some(expected_value)) if expected_value == entry_at7.value.into()
750 ));
751 assert!(matches!(
752 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
753 Ok(Some(expected_value)) if expected_value == entry_at7.value.into()
754 ));
755 assert!(matches!(
756 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
757 Ok(Some(expected_value)) if expected_value == entry_at10.value.into()
758 ));
759 assert!(matches!(
760 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
761 Ok(Some(expected_value)) if expected_value == entry_at10.value.into()
762 ));
763 assert!(matches!(
764 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
765 Ok(Some(expected_value)) if expected_value == entry_at15.value.into()
766 ));
767 assert!(matches!(
768 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
769 Ok(Some(expected_value)) if expected_value == entry_plain.value.into()
770 ));
771 assert!(matches!(
772 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
773 Ok(None)
774 ));
775 assert!(matches!(
776 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
777 Ok(Some(expected_value)) if expected_value == higher_entry_plain.value.into()
778 ));
779 }
780
781 #[test]
782 fn history_provider_unavailable() {
783 let factory = create_test_provider_factory();
784 let db = factory.database_provider_rw().unwrap();
785
786 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
789 &db,
790 2,
791 LowestAvailableBlocks {
792 account_history_block_number: Some(3),
793 storage_history_block_number: Some(3),
794 },
795 );
796 assert!(matches!(
797 provider.account_history_lookup(ADDRESS),
798 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
799 ));
800 assert!(matches!(
801 provider.storage_history_lookup(ADDRESS, STORAGE),
802 Err(ProviderError::StateAtBlockPruned(number)) if number == provider.block_number
803 ));
804
805 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
808 &db,
809 2,
810 LowestAvailableBlocks {
811 account_history_block_number: Some(2),
812 storage_history_block_number: Some(2),
813 },
814 );
815 assert!(matches!(
816 provider.account_history_lookup(ADDRESS),
817 Ok(HistoryInfo::MaybeInPlainState)
818 ));
819 assert!(matches!(
820 provider.storage_history_lookup(ADDRESS, STORAGE),
821 Ok(HistoryInfo::MaybeInPlainState)
822 ));
823
824 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
827 &db,
828 2,
829 LowestAvailableBlocks {
830 account_history_block_number: Some(1),
831 storage_history_block_number: Some(1),
832 },
833 );
834 assert!(matches!(
835 provider.account_history_lookup(ADDRESS),
836 Ok(HistoryInfo::MaybeInPlainState)
837 ));
838 assert!(matches!(
839 provider.storage_history_lookup(ADDRESS, STORAGE),
840 Ok(HistoryInfo::MaybeInPlainState)
841 ));
842 }
843}