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
15pub trait DatabaseStorageRoot<'a, TX> {
17 fn from_tx(tx: &'a TX, address: Address) -> Self;
19
20 fn from_tx_hashed(tx: &'a TX, hashed_address: B256) -> Self;
22
23 fn overlay_root(
25 tx: &'a TX,
26 address: Address,
27 hashed_storage: HashedStorage,
28 ) -> Result<B256, StorageRootError>;
29}
30
31pub trait DatabaseHashedStorage<TX>: Sized {
33 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}