ethrex_vm/backends/levm/
db.rs1use ethrex_common::U256 as CoreU256;
2use ethrex_common::constants::EMPTY_KECCAK_HASH;
3use ethrex_common::types::{AccountState, Code, CodeMetadata};
4use ethrex_common::{Address as CoreAddress, H256 as CoreH256};
5use ethrex_levm::db::Database as LevmDatabase;
6
7use crate::VmDatabase;
8use crate::db::DynVmDatabase;
9use ethrex_levm::errors::DatabaseError;
10use std::collections::HashMap;
11use std::result::Result;
12use std::sync::{Arc, Mutex};
13
14#[derive(Clone)]
15pub struct DatabaseLogger {
16 pub block_hashes_accessed: Arc<Mutex<HashMap<u64, CoreH256>>>,
17 pub state_accessed: Arc<Mutex<HashMap<CoreAddress, Vec<CoreH256>>>>,
18 pub code_accessed: Arc<Mutex<Vec<CoreH256>>>,
19 pub store: Arc<dyn LevmDatabase>,
20}
21
22impl DatabaseLogger {
23 pub fn new(store: Arc<dyn LevmDatabase>) -> Self {
24 Self {
25 block_hashes_accessed: Arc::new(Mutex::new(HashMap::new())),
26 state_accessed: Arc::new(Mutex::new(HashMap::new())),
27 code_accessed: Arc::new(Mutex::new(vec![])),
28 store,
29 }
30 }
31}
32
33impl LevmDatabase for DatabaseLogger {
34 fn get_account_state(&self, address: CoreAddress) -> Result<AccountState, DatabaseError> {
35 self.state_accessed
36 .lock()
37 .map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?
38 .entry(address)
39 .or_default();
40 let state = self.store.as_ref().get_account_state(address)?;
41 Ok(state)
42 }
43
44 fn get_storage_value(
45 &self,
46 address: CoreAddress,
47 key: CoreH256,
48 ) -> Result<CoreU256, DatabaseError> {
49 self.state_accessed
50 .lock()
51 .map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?
52 .entry(address)
53 .and_modify(|keys| keys.push(key))
54 .or_insert(vec![key]);
55 self.store.as_ref().get_storage_value(address, key)
56 }
57
58 fn get_block_hash(&self, block_number: u64) -> Result<CoreH256, DatabaseError> {
59 let block_hash = self.store.as_ref().get_block_hash(block_number)?;
60 self.block_hashes_accessed
61 .lock()
62 .map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?
63 .insert(block_number, block_hash);
64 Ok(block_hash)
65 }
66
67 fn get_chain_config(&self) -> Result<ethrex_common::types::ChainConfig, DatabaseError> {
68 self.store.as_ref().get_chain_config()
69 }
70
71 fn get_account_code(&self, code_hash: CoreH256) -> Result<Code, DatabaseError> {
72 if code_hash != *EMPTY_KECCAK_HASH {
73 let mut code_accessed = self
74 .code_accessed
75 .lock()
76 .map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?;
77 code_accessed.push(code_hash);
78 }
79 self.store.as_ref().get_account_code(code_hash)
80 }
81
82 fn code_cache_budget_bytes(&self) -> u64 {
83 self.store.as_ref().code_cache_budget_bytes()
84 }
85
86 fn prefetch_codes(&self, code_hashes: &[CoreH256]) -> Result<u64, DatabaseError> {
87 {
90 let mut code_accessed = self
91 .code_accessed
92 .lock()
93 .map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?;
94 code_accessed.extend(
95 code_hashes
96 .iter()
97 .filter(|h| **h != *EMPTY_KECCAK_HASH)
98 .copied(),
99 );
100 }
101 self.store.as_ref().prefetch_codes(code_hashes)
102 }
103
104 fn get_code_metadata(&self, code_hash: CoreH256) -> Result<CodeMetadata, DatabaseError> {
105 if code_hash != *EMPTY_KECCAK_HASH {
109 self.code_accessed
110 .lock()
111 .map_err(|_| DatabaseError::Custom("Could not lock mutex".to_string()))?
112 .push(code_hash);
113 }
114 self.store.get_code_metadata(code_hash)
115 }
116}
117
118impl LevmDatabase for DynVmDatabase {
119 fn get_account_state(&self, address: CoreAddress) -> Result<AccountState, DatabaseError> {
120 let acc_state = <dyn VmDatabase>::get_account_state(self.as_ref(), address)
121 .map_err(|e| DatabaseError::Custom(e.to_string()))?
122 .unwrap_or_default();
123
124 Ok(acc_state)
125 }
126
127 fn get_account_states_batch(
128 &self,
129 addresses: &[CoreAddress],
130 ) -> Result<Vec<AccountState>, DatabaseError> {
131 let states = <dyn VmDatabase>::get_account_states_batch(self.as_ref(), addresses)
132 .map_err(|e| DatabaseError::Custom(e.to_string()))?;
133 Ok(states
134 .into_iter()
135 .map(|opt| opt.unwrap_or_default())
136 .collect())
137 }
138
139 fn code_cache_budget_bytes(&self) -> u64 {
140 <dyn VmDatabase>::code_cache_budget_bytes(self.as_ref())
141 }
142
143 fn get_storage_value(
144 &self,
145 address: CoreAddress,
146 key: CoreH256,
147 ) -> Result<ethrex_common::U256, DatabaseError> {
148 Ok(
149 <dyn VmDatabase>::get_storage_slot(self.as_ref(), address, key)
150 .map_err(|e| DatabaseError::Custom(e.to_string()))?
151 .unwrap_or_default(),
152 )
153 }
154
155 fn get_storage_values_batch(
156 &self,
157 keys: &[(CoreAddress, CoreH256)],
158 ) -> Result<Vec<CoreU256>, DatabaseError> {
159 let values = <dyn VmDatabase>::get_storage_slots_batch(self.as_ref(), keys)
160 .map_err(|e| DatabaseError::Custom(e.to_string()))?;
161 Ok(values
162 .into_iter()
163 .map(|opt| opt.unwrap_or_default())
164 .collect())
165 }
166
167 fn get_block_hash(&self, block_number: u64) -> Result<CoreH256, DatabaseError> {
168 <dyn VmDatabase>::get_block_hash(self.as_ref(), block_number)
169 .map_err(|e| DatabaseError::Custom(e.to_string()))
170 }
171
172 fn get_chain_config(&self) -> Result<ethrex_common::types::ChainConfig, DatabaseError> {
173 <dyn VmDatabase>::get_chain_config(self.as_ref())
174 .map_err(|e| DatabaseError::Custom(e.to_string()))
175 }
176
177 fn get_account_code(&self, code_hash: CoreH256) -> Result<Code, DatabaseError> {
178 <dyn VmDatabase>::get_account_code(self.as_ref(), code_hash)
179 .map_err(|e| DatabaseError::Custom(e.to_string()))
180 }
181
182 fn get_account_codes_batch(
183 &self,
184 code_hashes: &[CoreH256],
185 ) -> Result<Vec<Option<Code>>, DatabaseError> {
186 <dyn VmDatabase>::get_account_codes_batch(self.as_ref(), code_hashes)
187 .map_err(|e| DatabaseError::Custom(e.to_string()))
188 }
189
190 fn get_code_metadata(&self, code_hash: CoreH256) -> Result<CodeMetadata, DatabaseError> {
191 <dyn VmDatabase>::get_code_metadata(self.as_ref(), code_hash)
192 .map_err(|e| DatabaseError::Custom(e.to_string()))
193 }
194}