Skip to main content

reth_storage_api/
storage.rs

1use alloc::{
2    collections::{BTreeMap, BTreeSet},
3    vec::Vec,
4};
5use alloy_primitives::{Address, BlockNumber, B256, U256};
6use core::ops::{RangeBounds, RangeInclusive};
7use reth_primitives_traits::{StorageEntry, StorageSlotKey};
8use reth_storage_errors::provider::ProviderResult;
9
10/// A storage changeset entry whose key is tagged as [`StorageSlotKey::Plain`] or
11/// [`StorageSlotKey::Hashed`] by the reader that produced it.
12///
13/// Unlike [`StorageEntry`] (the raw DB row type with an untagged `B256` key),
14/// this type carries provenance so downstream code can call
15/// [`StorageSlotKey::to_hashed`] without consulting `StorageSettings`.
16#[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
17pub struct ChangesetEntry {
18    /// Storage slot key, tagged with its hashing status.
19    pub key: StorageSlotKey,
20    /// Value at this storage slot before the change.
21    pub value: U256,
22}
23
24impl ChangesetEntry {
25    /// Convert to a raw [`StorageEntry`] (drops the tag).
26    pub const fn into_storage_entry(self) -> StorageEntry {
27        StorageEntry { key: self.key.as_b256(), value: self.value }
28    }
29}
30
31impl From<ChangesetEntry> for StorageEntry {
32    fn from(e: ChangesetEntry) -> Self {
33        e.into_storage_entry()
34    }
35}
36
37/// Storage reader
38#[auto_impl::auto_impl(&, Box)]
39pub trait StorageReader: Send {
40    /// Get plainstate storages for addresses and storage keys.
41    fn plain_state_storages(
42        &self,
43        addresses_with_keys: impl IntoIterator<Item = (Address, impl IntoIterator<Item = B256>)>,
44    ) -> ProviderResult<Vec<(Address, Vec<StorageEntry>)>>;
45
46    /// Iterate over storage changesets and return all storage slots that were changed.
47    fn changed_storages_with_range(
48        &self,
49        range: RangeInclusive<BlockNumber>,
50    ) -> ProviderResult<BTreeMap<Address, BTreeSet<B256>>>;
51
52    /// Iterate over storage changesets and return all storage slots that were changed alongside
53    /// each specific set of blocks.
54    ///
55    /// NOTE: Get inclusive range of blocks.
56    fn changed_storages_and_blocks_with_range(
57        &self,
58        range: RangeInclusive<BlockNumber>,
59    ) -> ProviderResult<BTreeMap<(Address, B256), Vec<u64>>>;
60}
61
62/// Storage `ChangeSet` reader
63#[cfg(feature = "db-api")]
64#[auto_impl::auto_impl(&, Box)]
65pub trait StorageChangeSetReader: Send {
66    /// Iterate over storage changesets and return the storage state from before this block.
67    ///
68    /// Returned entries have their keys tagged as [`StorageSlotKey::Plain`] or
69    /// [`StorageSlotKey::Hashed`] based on the current storage mode.
70    fn storage_changeset(
71        &self,
72        block_number: BlockNumber,
73    ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, ChangesetEntry)>>;
74
75    /// Search the block's changesets for the given address and storage key, and return the result.
76    ///
77    /// The `storage_key` must match the key format used by the storage mode
78    /// (plain in v1, keccak256-hashed in v2).
79    ///
80    /// Returns `None` if the storage slot was not changed in this block.
81    fn get_storage_before_block(
82        &self,
83        block_number: BlockNumber,
84        address: Address,
85        storage_key: B256,
86    ) -> ProviderResult<Option<ChangesetEntry>>;
87
88    /// Get all storage changesets in a range of blocks.
89    ///
90    /// Returned entries have their keys tagged as [`StorageSlotKey::Plain`] or
91    /// [`StorageSlotKey::Hashed`] based on the current storage mode.
92    fn storage_changesets_range(
93        &self,
94        range: impl RangeBounds<BlockNumber>,
95    ) -> ProviderResult<Vec<(reth_db_api::models::BlockNumberAddress, ChangesetEntry)>>;
96
97    /// Get the total count of all storage changes.
98    fn storage_changeset_count(&self) -> ProviderResult<usize>;
99
100    /// Get storage changesets for a block as static-file rows.
101    ///
102    /// Default implementation uses `storage_changeset` and maps to `StorageBeforeTx`.
103    fn storage_block_changeset(
104        &self,
105        block_number: BlockNumber,
106    ) -> ProviderResult<Vec<reth_db_models::StorageBeforeTx>> {
107        self.storage_changeset(block_number).map(|changesets| {
108            changesets
109                .into_iter()
110                .map(|(block_address, entry)| reth_db_models::StorageBeforeTx {
111                    address: block_address.address(),
112                    key: entry.key.as_b256(),
113                    value: entry.value,
114                })
115                .collect()
116        })
117    }
118}