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_storage_api::{BlockNumReader, StorageChangeSetReader};
8use reth_storage_errors::provider::ProviderResult;
9use reth_trie::{
10 hashed_cursor::HashedPostStateCursorFactory, HashedPostState, HashedStorage, StorageRoot,
11};
12
13#[cfg(feature = "metrics")]
14use reth_trie::metrics::TrieRootMetrics;
15
16pub trait DatabaseStorageRoot<'a, TX> {
18 fn from_tx(tx: &'a TX, address: Address) -> Self;
20
21 fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self;
23
24 fn overlay_root(
26 tx: &'a TX,
27 address: Address,
28 hashed_storage: HashedStorage,
29 ) -> Result<B256, StorageRootError>;
30}
31
32pub trait DatabaseHashedStorage<TX>: Sized {
34 fn from_reverts(tx: &TX, address: Address, from: BlockNumber) -> Result<Self, DatabaseError>;
37}
38
39pub fn hashed_storage_from_reverts_with_provider<P>(
41 provider: &P,
42 address: Address,
43 from: BlockNumber,
44) -> ProviderResult<HashedStorage>
45where
46 P: StorageChangeSetReader + BlockNumReader,
47{
48 let mut storage = HashedStorage::new(false);
49 let tip = provider.last_block_number()?;
50
51 if from > tip {
52 return Ok(storage)
53 }
54
55 for (BlockNumberAddress((_, storage_address)), storage_change) in
56 provider.storage_changesets_range(from..=tip)?
57 {
58 if storage_address == address {
59 let hashed_slot = keccak256(storage_change.key);
60 if let hash_map::Entry::Vacant(entry) = storage.storage.entry(hashed_slot) {
61 entry.insert(storage_change.value);
62 }
63 }
64 }
65
66 Ok(storage)
67}
68
69impl<'a, TX: DbTx> DatabaseStorageRoot<'a, TX>
70 for StorageRoot<DatabaseTrieCursorFactory<&'a TX>, DatabaseHashedCursorFactory<&'a TX>>
71{
72 fn from_tx(tx: &'a TX, address: Address) -> Self {
73 Self::new(
74 DatabaseTrieCursorFactory::new(tx),
75 DatabaseHashedCursorFactory::new(tx),
76 address,
77 Default::default(),
78 #[cfg(feature = "metrics")]
79 TrieRootMetrics::new(reth_trie::TrieType::Storage),
80 )
81 }
82
83 fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self {
84 Self::new_hashed(
85 DatabaseTrieCursorFactory::new(tx),
86 DatabaseHashedCursorFactory::new(tx),
87 hashed_address,
88 Default::default(),
89 #[cfg(feature = "metrics")]
90 TrieRootMetrics::new(reth_trie::TrieType::Storage),
91 )
92 }
93
94 fn overlay_root(
95 tx: &'a TX,
96 address: Address,
97 hashed_storage: HashedStorage,
98 ) -> Result<B256, StorageRootError> {
99 let prefix_set = hashed_storage.construct_prefix_set().freeze();
100 let state_sorted =
101 HashedPostState::from_hashed_storage(keccak256(address), hashed_storage).into_sorted();
102 StorageRoot::new(
103 DatabaseTrieCursorFactory::new(tx),
104 HashedPostStateCursorFactory::new(DatabaseHashedCursorFactory::new(tx), &state_sorted),
105 address,
106 prefix_set,
107 #[cfg(feature = "metrics")]
108 TrieRootMetrics::new(reth_trie::TrieType::Storage),
109 )
110 .root()
111 }
112}
113
114impl<TX: DbTx> DatabaseHashedStorage<TX> for HashedStorage {
115 fn from_reverts(tx: &TX, address: Address, from: BlockNumber) -> Result<Self, DatabaseError> {
116 let mut storage = Self::new(false);
117 let mut storage_changesets_cursor = tx.cursor_read::<tables::StorageChangeSets>()?;
118 for entry in storage_changesets_cursor.walk_range(BlockNumberAddress((from, address))..)? {
119 let (BlockNumberAddress((_, storage_address)), storage_change) = entry?;
120 if storage_address == address {
121 let hashed_slot = keccak256(storage_change.key);
122 if let hash_map::Entry::Vacant(entry) = storage.storage.entry(hashed_slot) {
123 entry.insert(storage_change.value);
124 }
125 }
126 }
127 Ok(storage)
128 }
129}