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::{map::B256HashMap, Address, BlockNumber, Bytes, StorageKey, B256};
7use reth_db::{tables, BlockNumberList};
8use reth_db_api::{
9 cursor::{DbCursorRO, DbDupCursorRO},
10 models::{storage_sharded_key::StorageShardedKey, ShardedKey},
11 table::Table,
12 transaction::DbTx,
13};
14use reth_primitives::{Account, Bytecode};
15use reth_storage_api::{
16 BlockNumReader, DBProvider, StateCommitmentProvider, StateProofProvider, StorageRootProvider,
17};
18use reth_storage_errors::provider::ProviderResult;
19use reth_trie::{
20 proof::{Proof, StorageProof},
21 updates::TrieUpdates,
22 witness::TrieWitness,
23 AccountProof, HashedPostState, HashedStorage, MultiProof, MultiProofTargets, StateRoot,
24 StorageMultiProof, StorageRoot, TrieInput,
25};
26use reth_trie_db::{
27 DatabaseHashedPostState, DatabaseHashedStorage, DatabaseProof, DatabaseStateRoot,
28 DatabaseStorageProof, DatabaseStorageRoot, DatabaseTrieWitness, StateCommitment,
29};
30use revm::primitives::FlaggedStorage;
31use std::fmt::Debug;
32
33#[derive(Debug)]
45pub struct HistoricalStateProviderRef<'b, Provider> {
46 provider: &'b Provider,
48 block_number: BlockNumber,
50 lowest_available_blocks: LowestAvailableBlocks,
52}
53
54#[derive(Debug, Eq, PartialEq)]
55pub enum HistoryInfo {
56 NotYetWritten,
57 InChangeset(u64),
58 InPlainState,
59 MaybeInPlainState,
60}
61
62impl<'b, Provider: DBProvider + BlockNumReader + StateCommitmentProvider>
63 HistoricalStateProviderRef<'b, Provider>
64{
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<HashedPostState> {
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 Ok(HashedPostState::from_reverts::<
138 <Provider::StateCommitment as StateCommitment>::KeyHasher,
139 >(self.tx(), self.block_number)?)
140 }
141
142 fn revert_storage(&self, address: Address) -> ProviderResult<HashedStorage> {
144 if !self.lowest_available_blocks.is_storage_history_available(self.block_number) {
145 return Err(ProviderError::StateAtBlockPruned(self.block_number))
146 }
147
148 if self.check_distance_against_limit(EPOCH_SLOTS * 10)? {
149 tracing::warn!(
150 target: "provider::historical_sp",
151 target = self.block_number,
152 "Attempt to calculate storage root for an old block might result in OOM"
153 );
154 }
155
156 Ok(HashedStorage::from_reverts(self.tx(), address, self.block_number)?)
157 }
158
159 fn history_info<T, K>(
160 &self,
161 key: K,
162 key_filter: impl Fn(&K) -> bool,
163 lowest_available_block_number: Option<BlockNumber>,
164 ) -> ProviderResult<HistoryInfo>
165 where
166 T: Table<Key = K, Value = BlockNumberList>,
167 {
168 let mut cursor = self.tx().cursor_read::<T>()?;
169
170 if let Some(chunk) = cursor.seek(key)?.filter(|(key, _)| key_filter(key)).map(|x| x.1 .0) {
174 let mut rank = chunk.rank(self.block_number);
176
177 if rank.checked_sub(1).and_then(|rank| chunk.select(rank)) == Some(self.block_number) {
180 rank -= 1
181 };
182
183 let block_number = chunk.select(rank);
184
185 if rank == 0 &&
192 block_number != Some(self.block_number) &&
193 !cursor.prev()?.is_some_and(|(key, _)| key_filter(&key))
194 {
195 if let (Some(_), Some(block_number)) = (lowest_available_block_number, block_number)
196 {
197 Ok(HistoryInfo::InChangeset(block_number))
200 } else {
201 Ok(HistoryInfo::NotYetWritten)
203 }
204 } else if let Some(block_number) = block_number {
205 Ok(HistoryInfo::InChangeset(block_number))
207 } else {
208 Ok(HistoryInfo::InPlainState)
211 }
212 } else if lowest_available_block_number.is_some() {
213 Ok(HistoryInfo::MaybeInPlainState)
216 } else {
217 Ok(HistoryInfo::NotYetWritten)
219 }
220 }
221
222 pub const fn with_lowest_available_account_history_block_number(
224 mut self,
225 block_number: BlockNumber,
226 ) -> Self {
227 self.lowest_available_blocks.account_history_block_number = Some(block_number);
228 self
229 }
230
231 pub const fn with_lowest_available_storage_history_block_number(
233 mut self,
234 block_number: BlockNumber,
235 ) -> Self {
236 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
237 self
238 }
239}
240
241impl<Provider: DBProvider + BlockNumReader> HistoricalStateProviderRef<'_, Provider> {
242 fn tx(&self) -> &Provider::Tx {
243 self.provider.tx_ref()
244 }
245}
246
247impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> AccountReader
248 for HistoricalStateProviderRef<'_, Provider>
249{
250 fn basic_account(&self, address: Address) -> ProviderResult<Option<Account>> {
252 match self.account_history_lookup(address)? {
253 HistoryInfo::NotYetWritten => Ok(None),
254 HistoryInfo::InChangeset(changeset_block_number) => Ok(self
255 .tx()
256 .cursor_dup_read::<tables::AccountChangeSets>()?
257 .seek_by_key_subkey(changeset_block_number, address)?
258 .filter(|acc| acc.address == address)
259 .ok_or(ProviderError::AccountChangesetNotFound {
260 block_number: changeset_block_number,
261 address,
262 })?
263 .info),
264 HistoryInfo::InPlainState | HistoryInfo::MaybeInPlainState => {
265 Ok(self.tx().get::<tables::PlainAccountState>(address)?)
266 }
267 }
268 }
269}
270
271impl<Provider: DBProvider + BlockNumReader + BlockHashReader> BlockHashReader
272 for HistoricalStateProviderRef<'_, Provider>
273{
274 fn block_hash(&self, number: u64) -> ProviderResult<Option<B256>> {
276 self.provider.block_hash(number)
277 }
278
279 fn canonical_hashes_range(
280 &self,
281 start: BlockNumber,
282 end: BlockNumber,
283 ) -> ProviderResult<Vec<B256>> {
284 self.provider.canonical_hashes_range(start, end)
285 }
286}
287
288impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StateRootProvider
289 for HistoricalStateProviderRef<'_, Provider>
290{
291 fn state_root(&self, hashed_state: HashedPostState) -> ProviderResult<B256> {
292 let mut revert_state = self.revert_state()?;
293 revert_state.extend(hashed_state);
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()?);
300 StateRoot::overlay_root_from_nodes(self.tx(), 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 revert_state.extend(hashed_state);
310 StateRoot::overlay_root_with_updates(self.tx(), revert_state)
311 .map_err(|err| ProviderError::Database(err.into()))
312 }
313
314 fn state_root_from_nodes_with_updates(
315 &self,
316 mut input: TrieInput,
317 ) -> ProviderResult<(B256, TrieUpdates)> {
318 input.prepend(self.revert_state()?);
319 StateRoot::overlay_root_from_nodes_with_updates(self.tx(), input)
320 .map_err(|err| ProviderError::Database(err.into()))
321 }
322}
323
324impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StorageRootProvider
325 for HistoricalStateProviderRef<'_, Provider>
326{
327 fn storage_root(
328 &self,
329 address: Address,
330 hashed_storage: HashedStorage,
331 ) -> ProviderResult<B256> {
332 let mut revert_storage = self.revert_storage(address)?;
333 revert_storage.extend(&hashed_storage);
334 StorageRoot::overlay_root(self.tx(), address, revert_storage)
335 .map_err(|err| ProviderError::Database(err.into()))
336 }
337
338 fn storage_proof(
339 &self,
340 address: Address,
341 slot: B256,
342 hashed_storage: HashedStorage,
343 ) -> ProviderResult<reth_trie::StorageProof> {
344 let mut revert_storage = self.revert_storage(address)?;
345 revert_storage.extend(&hashed_storage);
346 StorageProof::overlay_storage_proof(self.tx(), address, slot, revert_storage)
347 .map_err(ProviderError::from)
348 }
349
350 fn storage_multiproof(
351 &self,
352 address: Address,
353 slots: &[B256],
354 hashed_storage: HashedStorage,
355 ) -> ProviderResult<StorageMultiProof> {
356 let mut revert_storage = self.revert_storage(address)?;
357 revert_storage.extend(&hashed_storage);
358 StorageProof::overlay_storage_multiproof(self.tx(), address, slots, revert_storage)
359 .map_err(ProviderError::from)
360 }
361}
362
363impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider> StateProofProvider
364 for HistoricalStateProviderRef<'_, Provider>
365{
366 fn proof(
368 &self,
369 mut input: TrieInput,
370 address: Address,
371 slots: &[B256],
372 ) -> ProviderResult<AccountProof> {
373 input.prepend(self.revert_state()?);
374 Proof::overlay_account_proof(self.tx(), input, address, slots).map_err(ProviderError::from)
375 }
376
377 fn multiproof(
378 &self,
379 mut input: TrieInput,
380 targets: MultiProofTargets,
381 ) -> ProviderResult<MultiProof> {
382 input.prepend(self.revert_state()?);
383 Proof::overlay_multiproof(self.tx(), input, targets).map_err(ProviderError::from)
384 }
385
386 fn witness(
387 &self,
388 mut input: TrieInput,
389 target: HashedPostState,
390 ) -> ProviderResult<B256HashMap<Bytes>> {
391 input.prepend(self.revert_state()?);
392 TrieWitness::overlay_witness(self.tx(), input, target).map_err(ProviderError::from)
393 }
394}
395
396impl<Provider: StateCommitmentProvider> HashedPostStateProvider
397 for HistoricalStateProviderRef<'_, Provider>
398{
399 fn hashed_post_state(&self, bundle_state: &revm::db::BundleState) -> HashedPostState {
400 HashedPostState::from_bundle_state::<
401 <Provider::StateCommitment as StateCommitment>::KeyHasher,
402 >(bundle_state.state())
403 }
404}
405
406impl<Provider: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider>
407 StateProvider for HistoricalStateProviderRef<'_, Provider>
408{
409 fn storage(
411 &self,
412 address: Address,
413 storage_key: StorageKey,
414 ) -> ProviderResult<Option<FlaggedStorage>> {
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 .into(),
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.into())
435 .or(Some(FlaggedStorage::ZERO))),
436 }
437 }
438
439 fn bytecode_by_hash(&self, code_hash: B256) -> ProviderResult<Option<Bytecode>> {
441 self.tx().get::<tables::Bytecodes>(code_hash).map_err(Into::into)
442 }
443}
444
445impl<Provider: StateCommitmentProvider> StateCommitmentProvider
446 for HistoricalStateProviderRef<'_, Provider>
447{
448 type StateCommitment = Provider::StateCommitment;
449}
450
451#[derive(Debug)]
454pub struct HistoricalStateProvider<Provider> {
455 provider: Provider,
457 block_number: BlockNumber,
459 lowest_available_blocks: LowestAvailableBlocks,
461}
462
463impl<Provider: DBProvider + BlockNumReader + StateCommitmentProvider>
464 HistoricalStateProvider<Provider>
465{
466 pub fn new(provider: Provider, block_number: BlockNumber) -> Self {
468 Self { provider, block_number, lowest_available_blocks: Default::default() }
469 }
470
471 pub const fn with_lowest_available_account_history_block_number(
473 mut self,
474 block_number: BlockNumber,
475 ) -> Self {
476 self.lowest_available_blocks.account_history_block_number = Some(block_number);
477 self
478 }
479
480 pub const fn with_lowest_available_storage_history_block_number(
482 mut self,
483 block_number: BlockNumber,
484 ) -> Self {
485 self.lowest_available_blocks.storage_history_block_number = Some(block_number);
486 self
487 }
488
489 #[inline(always)]
491 const fn as_ref(&self) -> HistoricalStateProviderRef<'_, Provider> {
492 HistoricalStateProviderRef::new_with_lowest_available_blocks(
493 &self.provider,
494 self.block_number,
495 self.lowest_available_blocks,
496 )
497 }
498}
499
500impl<Provider: StateCommitmentProvider> StateCommitmentProvider
501 for HistoricalStateProvider<Provider>
502{
503 type StateCommitment = Provider::StateCommitment;
504}
505
506delegate_provider_impls!(HistoricalStateProvider<Provider> where [Provider: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider]);
508
509#[derive(Clone, Copy, Debug, Default)]
512pub struct LowestAvailableBlocks {
513 pub account_history_block_number: Option<BlockNumber>,
517 pub storage_history_block_number: Option<BlockNumber>,
521}
522
523impl LowestAvailableBlocks {
524 pub fn is_account_history_available(&self, at: BlockNumber) -> bool {
527 self.account_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
528 }
529
530 pub fn is_storage_history_available(&self, at: BlockNumber) -> bool {
533 self.storage_history_block_number.map(|block_number| block_number <= at).unwrap_or(true)
534 }
535}
536
537#[cfg(test)]
538mod tests {
539 use crate::{
540 providers::state::historical::{HistoryInfo, LowestAvailableBlocks},
541 test_utils::create_test_provider_factory,
542 AccountReader, HistoricalStateProvider, HistoricalStateProviderRef, StateProvider,
543 };
544 use alloy_primitives::{address, b256, Address, B256, U256};
545 use reth_db::{tables, BlockNumberList};
546 use reth_db_api::{
547 models::{storage_sharded_key::StorageShardedKey, AccountBeforeTx, ShardedKey},
548 transaction::{DbTx, DbTxMut},
549 };
550 use reth_primitives::{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::primitives::FlaggedStorage;
557
558 const ADDRESS: Address = address!("0000000000000000000000000000000000000001");
559 const HIGHER_ADDRESS: Address = address!("0000000000000000000000000000000000000005");
560 const STORAGE: B256 = b256!("0000000000000000000000000000000000000000000000000000000000000001");
561
562 const fn assert_state_provider<T: StateProvider>() {}
563 #[allow(dead_code)]
564 const fn assert_historical_state_provider<
565 T: DBProvider + BlockNumReader + BlockHashReader + StateCommitmentProvider,
566 >() {
567 assert_state_provider::<HistoricalStateProvider<T>>();
568 }
569
570 #[test]
571 fn history_provider_get_account() {
572 let factory = create_test_provider_factory();
573 let tx = factory.provider_rw().unwrap().into_tx();
574
575 tx.put::<tables::AccountsHistory>(
576 ShardedKey { key: ADDRESS, highest_block_number: 7 },
577 BlockNumberList::new([1, 3, 7]).unwrap(),
578 )
579 .unwrap();
580 tx.put::<tables::AccountsHistory>(
581 ShardedKey { key: ADDRESS, highest_block_number: u64::MAX },
582 BlockNumberList::new([10, 15]).unwrap(),
583 )
584 .unwrap();
585 tx.put::<tables::AccountsHistory>(
586 ShardedKey { key: HIGHER_ADDRESS, highest_block_number: u64::MAX },
587 BlockNumberList::new([4]).unwrap(),
588 )
589 .unwrap();
590
591 let acc_plain = Account { nonce: 100, balance: U256::ZERO, bytecode_hash: None };
592 let acc_at15 = Account { nonce: 15, balance: U256::ZERO, bytecode_hash: None };
593 let acc_at10 = Account { nonce: 10, balance: U256::ZERO, bytecode_hash: None };
594 let acc_at7 = Account { nonce: 7, balance: U256::ZERO, bytecode_hash: None };
595 let acc_at3 = Account { nonce: 3, balance: U256::ZERO, bytecode_hash: None };
596
597 let higher_acc_plain = Account { nonce: 4, balance: U256::ZERO, bytecode_hash: None };
598
599 tx.put::<tables::AccountChangeSets>(1, AccountBeforeTx { address: ADDRESS, info: None })
601 .unwrap();
602 tx.put::<tables::AccountChangeSets>(
603 3,
604 AccountBeforeTx { address: ADDRESS, info: Some(acc_at3) },
605 )
606 .unwrap();
607 tx.put::<tables::AccountChangeSets>(
608 4,
609 AccountBeforeTx { address: HIGHER_ADDRESS, info: None },
610 )
611 .unwrap();
612 tx.put::<tables::AccountChangeSets>(
613 7,
614 AccountBeforeTx { address: ADDRESS, info: Some(acc_at7) },
615 )
616 .unwrap();
617 tx.put::<tables::AccountChangeSets>(
618 10,
619 AccountBeforeTx { address: ADDRESS, info: Some(acc_at10) },
620 )
621 .unwrap();
622 tx.put::<tables::AccountChangeSets>(
623 15,
624 AccountBeforeTx { address: ADDRESS, info: Some(acc_at15) },
625 )
626 .unwrap();
627
628 tx.put::<tables::PlainAccountState>(ADDRESS, acc_plain).unwrap();
630 tx.put::<tables::PlainAccountState>(HIGHER_ADDRESS, higher_acc_plain).unwrap();
631 tx.commit().unwrap();
632
633 let db = factory.provider().unwrap();
634
635 assert_eq!(HistoricalStateProviderRef::new(&db, 1).basic_account(ADDRESS), Ok(None));
637 assert_eq!(
638 HistoricalStateProviderRef::new(&db, 2).basic_account(ADDRESS),
639 Ok(Some(acc_at3))
640 );
641 assert_eq!(
642 HistoricalStateProviderRef::new(&db, 3).basic_account(ADDRESS),
643 Ok(Some(acc_at3))
644 );
645 assert_eq!(
646 HistoricalStateProviderRef::new(&db, 4).basic_account(ADDRESS),
647 Ok(Some(acc_at7))
648 );
649 assert_eq!(
650 HistoricalStateProviderRef::new(&db, 7).basic_account(ADDRESS),
651 Ok(Some(acc_at7))
652 );
653 assert_eq!(
654 HistoricalStateProviderRef::new(&db, 9).basic_account(ADDRESS),
655 Ok(Some(acc_at10))
656 );
657 assert_eq!(
658 HistoricalStateProviderRef::new(&db, 10).basic_account(ADDRESS),
659 Ok(Some(acc_at10))
660 );
661 assert_eq!(
662 HistoricalStateProviderRef::new(&db, 11).basic_account(ADDRESS),
663 Ok(Some(acc_at15))
664 );
665 assert_eq!(
666 HistoricalStateProviderRef::new(&db, 16).basic_account(ADDRESS),
667 Ok(Some(acc_plain))
668 );
669
670 assert_eq!(HistoricalStateProviderRef::new(&db, 1).basic_account(HIGHER_ADDRESS), Ok(None));
671 assert_eq!(
672 HistoricalStateProviderRef::new(&db, 1000).basic_account(HIGHER_ADDRESS),
673 Ok(Some(higher_acc_plain))
674 );
675 }
676
677 #[test]
678 fn history_provider_get_storage() {
679 let factory = create_test_provider_factory();
680 let tx = factory.provider_rw().unwrap().into_tx();
681
682 tx.put::<tables::StoragesHistory>(
683 StorageShardedKey {
684 address: ADDRESS,
685 sharded_key: ShardedKey { key: STORAGE, highest_block_number: 7 },
686 },
687 BlockNumberList::new([3, 7]).unwrap(),
688 )
689 .unwrap();
690 tx.put::<tables::StoragesHistory>(
691 StorageShardedKey {
692 address: ADDRESS,
693 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
694 },
695 BlockNumberList::new([10, 15]).unwrap(),
696 )
697 .unwrap();
698 tx.put::<tables::StoragesHistory>(
699 StorageShardedKey {
700 address: HIGHER_ADDRESS,
701 sharded_key: ShardedKey { key: STORAGE, highest_block_number: u64::MAX },
702 },
703 BlockNumberList::new([4]).unwrap(),
704 )
705 .unwrap();
706
707 let higher_entry_plain =
708 StorageEntry { key: STORAGE, value: U256::from(1000), is_private: false };
709 let higher_entry_at4 =
710 StorageEntry { key: STORAGE, value: U256::from(0), is_private: false };
711 let entry_plain = StorageEntry { key: STORAGE, value: U256::from(100), is_private: false };
712 let entry_at15 = StorageEntry { key: STORAGE, value: U256::from(15), is_private: false };
713 let entry_at10 = StorageEntry { key: STORAGE, value: U256::from(10), is_private: false };
714 let entry_at7 = StorageEntry { key: STORAGE, value: U256::from(7), is_private: false };
715 let entry_at3 = StorageEntry { key: STORAGE, value: U256::from(0), is_private: false };
716
717 tx.put::<tables::StorageChangeSets>((3, ADDRESS).into(), entry_at3).unwrap();
719 tx.put::<tables::StorageChangeSets>((4, HIGHER_ADDRESS).into(), higher_entry_at4).unwrap();
720 tx.put::<tables::StorageChangeSets>((7, ADDRESS).into(), entry_at7).unwrap();
721 tx.put::<tables::StorageChangeSets>((10, ADDRESS).into(), entry_at10).unwrap();
722 tx.put::<tables::StorageChangeSets>((15, ADDRESS).into(), entry_at15).unwrap();
723
724 tx.put::<tables::PlainStorageState>(ADDRESS, entry_plain).unwrap();
726 tx.put::<tables::PlainStorageState>(HIGHER_ADDRESS, higher_entry_plain).unwrap();
727 tx.commit().unwrap();
728
729 let db = factory.provider().unwrap();
730
731 assert_eq!(HistoricalStateProviderRef::new(&db, 0).storage(ADDRESS, STORAGE), Ok(None));
733 assert_eq!(
734 HistoricalStateProviderRef::new(&db, 3).storage(ADDRESS, STORAGE),
735 Ok(Some(FlaggedStorage::ZERO))
736 );
737 assert_eq!(
738 HistoricalStateProviderRef::new(&db, 4).storage(ADDRESS, STORAGE),
739 Ok(Some(FlaggedStorage::new_from_value(entry_at7.value)))
740 );
741 assert_eq!(
742 HistoricalStateProviderRef::new(&db, 7).storage(ADDRESS, STORAGE),
743 Ok(Some(FlaggedStorage::new_from_value(entry_at7.value)))
744 );
745 assert_eq!(
746 HistoricalStateProviderRef::new(&db, 9).storage(ADDRESS, STORAGE),
747 Ok(Some(FlaggedStorage::new_from_value(entry_at10.value)))
748 );
749 assert_eq!(
750 HistoricalStateProviderRef::new(&db, 10).storage(ADDRESS, STORAGE),
751 Ok(Some(FlaggedStorage::new_from_value(entry_at10.value)))
752 );
753 assert_eq!(
754 HistoricalStateProviderRef::new(&db, 11).storage(ADDRESS, STORAGE),
755 Ok(Some(FlaggedStorage::new_from_value(entry_at15.value)))
756 );
757 assert_eq!(
758 HistoricalStateProviderRef::new(&db, 16).storage(ADDRESS, STORAGE),
759 Ok(Some(FlaggedStorage::new_from_value(entry_plain.value)))
760 );
761 assert_eq!(
762 HistoricalStateProviderRef::new(&db, 1).storage(HIGHER_ADDRESS, STORAGE),
763 Ok(None)
764 );
765 assert_eq!(
766 HistoricalStateProviderRef::new(&db, 1000).storage(HIGHER_ADDRESS, STORAGE),
767 Ok(Some(FlaggedStorage::new_from_value(higher_entry_plain.value)))
768 );
769 }
770
771 #[test]
772 fn history_provider_unavailable() {
773 let factory = create_test_provider_factory();
774 let db = factory.database_provider_rw().unwrap();
775
776 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
779 &db,
780 2,
781 LowestAvailableBlocks {
782 account_history_block_number: Some(3),
783 storage_history_block_number: Some(3),
784 },
785 );
786 assert_eq!(
787 provider.account_history_lookup(ADDRESS),
788 Err(ProviderError::StateAtBlockPruned(provider.block_number))
789 );
790 assert_eq!(
791 provider.storage_history_lookup(ADDRESS, STORAGE),
792 Err(ProviderError::StateAtBlockPruned(provider.block_number))
793 );
794
795 let provider = HistoricalStateProviderRef::new_with_lowest_available_blocks(
798 &db,
799 2,
800 LowestAvailableBlocks {
801 account_history_block_number: Some(2),
802 storage_history_block_number: Some(2),
803 },
804 );
805 assert_eq!(provider.account_history_lookup(ADDRESS), Ok(HistoryInfo::MaybeInPlainState));
806 assert_eq!(
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_eq!(provider.account_history_lookup(ADDRESS), Ok(HistoryInfo::MaybeInPlainState));
822 assert_eq!(
823 provider.storage_history_lookup(ADDRESS, STORAGE),
824 Ok(HistoryInfo::MaybeInPlainState)
825 );
826 }
827}