reth_trie_db/
storage.rs

1use crate::{DatabaseHashedCursorFactory, DatabaseTrieCursorFactory};
2use alloy_primitives::{keccak256, map::hash_map, Address, BlockNumber, B256};
3use reth_db_api::{
4    cursor::DbCursorRO, models::BlockNumberAddress, tables, transaction::DbTx, DatabaseError,
5};
6use reth_execution_errors::StorageRootError;
7use reth_trie::{
8    hashed_cursor::HashedPostStateCursorFactory, HashedPostState, HashedStorage, StorageRoot,
9};
10
11#[cfg(feature = "metrics")]
12use reth_trie::metrics::TrieRootMetrics;
13
14/// Extends [`StorageRoot`] with operations specific for working with a database transaction.
15pub trait DatabaseStorageRoot<'a, TX> {
16    /// Create a new storage root calculator from database transaction and raw address.
17    fn from_tx(tx: &'a TX, address: Address) -> Self;
18
19    /// Create a new storage root calculator from database transaction and hashed address.
20    fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self;
21
22    /// Calculates the storage root for this [`HashedStorage`] and returns it.
23    fn overlay_root(
24        tx: &'a TX,
25        address: Address,
26        hashed_storage: HashedStorage,
27    ) -> Result<B256, StorageRootError>;
28}
29
30/// Extends [`HashedStorage`] with operations specific for working with a database transaction.
31pub trait DatabaseHashedStorage<TX>: Sized {
32    /// Initializes [`HashedStorage`] from reverts. Iterates over storage reverts from the specified
33    /// block up to the current tip and aggregates them into hashed storage in reverse.
34    fn from_reverts(tx: &TX, address: Address, from: BlockNumber) -> Result<Self, DatabaseError>;
35}
36
37impl<'a, TX: DbTx> DatabaseStorageRoot<'a, TX>
38    for StorageRoot<DatabaseTrieCursorFactory<'a, TX>, DatabaseHashedCursorFactory<'a, TX>>
39{
40    fn from_tx(tx: &'a TX, address: Address) -> Self {
41        Self::new(
42            DatabaseTrieCursorFactory::new(tx),
43            DatabaseHashedCursorFactory::new(tx),
44            address,
45            Default::default(),
46            #[cfg(feature = "metrics")]
47            TrieRootMetrics::new(reth_trie::TrieType::Storage),
48        )
49    }
50
51    fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self {
52        Self::new_hashed(
53            DatabaseTrieCursorFactory::new(tx),
54            DatabaseHashedCursorFactory::new(tx),
55            hashed_address,
56            Default::default(),
57            #[cfg(feature = "metrics")]
58            TrieRootMetrics::new(reth_trie::TrieType::Storage),
59        )
60    }
61
62    fn overlay_root(
63        tx: &'a TX,
64        address: Address,
65        hashed_storage: HashedStorage,
66    ) -> Result<B256, StorageRootError> {
67        let prefix_set = hashed_storage.construct_prefix_set().freeze();
68        let state_sorted =
69            HashedPostState::from_hashed_storage(keccak256(address), hashed_storage).into_sorted();
70        StorageRoot::new(
71            DatabaseTrieCursorFactory::new(tx),
72            HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted),
73            address,
74            prefix_set,
75            #[cfg(feature = "metrics")]
76            TrieRootMetrics::new(reth_trie::TrieType::Storage),
77        )
78        .root()
79    }
80}
81
82impl<TX: DbTx> DatabaseHashedStorage<TX> for HashedStorage {
83    fn from_reverts(tx: &TX, address: Address, from: BlockNumber) -> Result<Self, DatabaseError> {
84        let mut storage = Self::new(false);
85        let mut storage_changesets_cursor = tx.cursor_read::<tables::StorageChangeSets>()?;
86        for entry in storage_changesets_cursor.walk_range(BlockNumberAddress((from, address))..)? {
87            let (BlockNumberAddress((_, storage_address)), storage_change) = entry?;
88            if storage_address == address {
89                let hashed_slot = keccak256(storage_change.key);
90                if let hash_map::Entry::Vacant(entry) = storage.storage.entry(hashed_slot) {
91                    entry.insert(storage_change.value);
92                }
93            }
94        }
95        Ok(storage)
96    }
97}