reth_trie_db/
storage.rs

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