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