1use core::convert::Infallible;
2use database_interface::{Database, DatabaseCommit, DatabaseRef, EmptyDB};
3use primitives::{address, hash_map::Entry, Address, HashMap, Log, B256, KECCAK_EMPTY, U256};
4use state::{Account, AccountInfo, Bytecode};
5use std::vec::Vec;
6
7pub type InMemoryDB = CacheDB<EmptyDB>;
9
10#[derive(Debug, Clone)]
16#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
17pub struct Cache {
18 pub accounts: HashMap<Address, DbAccount>,
21 pub contracts: HashMap<B256, Bytecode>,
23 pub logs: Vec<Log>,
25 pub block_hashes: HashMap<U256, B256>,
27}
28
29impl Default for Cache {
30 fn default() -> Self {
31 let mut contracts = HashMap::default();
32 contracts.insert(KECCAK_EMPTY, Bytecode::default());
33 contracts.insert(B256::ZERO, Bytecode::default());
34
35 Cache {
36 accounts: HashMap::default(),
37 contracts,
38 logs: Vec::default(),
39 block_hashes: HashMap::default(),
40 }
41 }
42}
43
44#[derive(Debug, Clone)]
48#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
49pub struct CacheDB<ExtDB> {
50 pub cache: Cache,
52 pub db: ExtDB,
56}
57
58impl<ExtDB: Default> Default for CacheDB<ExtDB> {
59 fn default() -> Self {
60 Self::new(ExtDB::default())
61 }
62}
63
64impl<ExtDb> CacheDB<CacheDB<ExtDb>> {
65 pub fn flatten(self) -> CacheDB<ExtDb> {
73 let CacheDB {
74 cache:
75 Cache {
76 accounts,
77 contracts,
78 logs,
79 block_hashes,
80 },
81 db: mut inner,
82 } = self;
83
84 inner.cache.accounts.extend(accounts);
85 inner.cache.contracts.extend(contracts);
86 inner.cache.logs.extend(logs);
87 inner.cache.block_hashes.extend(block_hashes);
88 inner
89 }
90
91 pub fn discard_outer(self) -> CacheDB<ExtDb> {
93 self.db
94 }
95}
96
97impl<ExtDB> CacheDB<ExtDB> {
98 pub fn new(db: ExtDB) -> Self {
100 Self {
101 cache: Cache::default(),
102 db,
103 }
104 }
105
106 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
112 if let Some(code) = &account.code {
113 if !code.is_empty() {
114 if account.code_hash == KECCAK_EMPTY {
115 account.code_hash = code.hash_slow();
116 }
117 self.cache
118 .contracts
119 .entry(account.code_hash)
120 .or_insert_with(|| code.clone());
121 }
122 }
123 if account.code_hash.is_zero() {
124 account.code_hash = KECCAK_EMPTY;
125 }
126 }
127
128 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
130 self.insert_contract(&mut info);
131 self.cache.accounts.entry(address).or_default().info = info;
132 }
133
134 pub fn nest(self) -> CacheDB<Self> {
136 CacheDB::new(self)
137 }
138}
139
140impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
141 pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, ExtDB::Error> {
145 let db = &self.db;
146 match self.cache.accounts.entry(address) {
147 Entry::Occupied(entry) => Ok(entry.into_mut()),
148 Entry::Vacant(entry) => Ok(entry.insert(
149 db.basic_ref(address)?
150 .map(|info| DbAccount {
151 info,
152 ..Default::default()
153 })
154 .unwrap_or_else(DbAccount::new_not_existing),
155 )),
156 }
157 }
158
159 pub fn insert_account_storage(
161 &mut self,
162 address: Address,
163 slot: U256,
164 value: U256,
165 ) -> Result<(), ExtDB::Error> {
166 let account = self.load_account(address)?;
167 account.storage.insert(slot, value);
168 Ok(())
169 }
170
171 pub fn replace_account_storage(
173 &mut self,
174 address: Address,
175 storage: HashMap<U256, U256>,
176 ) -> Result<(), ExtDB::Error> {
177 let account = self.load_account(address)?;
178 account.account_state = AccountState::StorageCleared;
179 account.storage = storage.into_iter().collect();
180 Ok(())
181 }
182}
183
184impl<ExtDB> DatabaseCommit for CacheDB<ExtDB> {
185 fn commit(&mut self, changes: HashMap<Address, Account>) {
186 for (address, mut account) in changes {
187 if !account.is_touched() {
188 continue;
189 }
190 if account.is_selfdestructed() {
191 let db_account = self.cache.accounts.entry(address).or_default();
192 db_account.storage.clear();
193 db_account.account_state = AccountState::NotExisting;
194 db_account.info = AccountInfo::default();
195 continue;
196 }
197 let is_newly_created = account.is_created();
198 self.insert_contract(&mut account.info);
199
200 let db_account = self.cache.accounts.entry(address).or_default();
201 db_account.info = account.info;
202
203 db_account.account_state = if is_newly_created {
204 db_account.storage.clear();
205 AccountState::StorageCleared
206 } else if db_account.account_state.is_storage_cleared() {
207 AccountState::StorageCleared
209 } else {
210 AccountState::Touched
211 };
212 db_account.storage.extend(
213 account
214 .storage
215 .into_iter()
216 .map(|(key, value)| (key, value.present_value())),
217 );
218 }
219 }
220}
221
222impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
223 type Error = ExtDB::Error;
224
225 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
226 let basic = match self.cache.accounts.entry(address) {
227 Entry::Occupied(entry) => entry.into_mut(),
228 Entry::Vacant(entry) => entry.insert(
229 self.db
230 .basic_ref(address)?
231 .map(|info| DbAccount {
232 info,
233 ..Default::default()
234 })
235 .unwrap_or_else(DbAccount::new_not_existing),
236 ),
237 };
238 Ok(basic.info())
239 }
240
241 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
242 match self.cache.contracts.entry(code_hash) {
243 Entry::Occupied(entry) => Ok(entry.get().clone()),
244 Entry::Vacant(entry) => {
245 Ok(entry.insert(self.db.code_by_hash_ref(code_hash)?).clone())
247 }
248 }
249 }
250
251 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
255 match self.cache.accounts.entry(address) {
256 Entry::Occupied(mut acc_entry) => {
257 let acc_entry = acc_entry.get_mut();
258 match acc_entry.storage.entry(index) {
259 Entry::Occupied(entry) => Ok(*entry.get()),
260 Entry::Vacant(entry) => {
261 if matches!(
262 acc_entry.account_state,
263 AccountState::StorageCleared | AccountState::NotExisting
264 ) {
265 Ok(U256::ZERO)
266 } else {
267 let slot = self.db.storage_ref(address, index)?;
268 entry.insert(slot);
269 Ok(slot)
270 }
271 }
272 }
273 }
274 Entry::Vacant(acc_entry) => {
275 let info = self.db.basic_ref(address)?;
277 let (account, value) = if info.is_some() {
278 let value = self.db.storage_ref(address, index)?;
279 let mut account: DbAccount = info.into();
280 account.storage.insert(index, value);
281 (account, value)
282 } else {
283 (info.into(), U256::ZERO)
284 };
285 acc_entry.insert(account);
286 Ok(value)
287 }
288 }
289 }
290
291 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
292 match self.cache.block_hashes.entry(U256::from(number)) {
293 Entry::Occupied(entry) => Ok(*entry.get()),
294 Entry::Vacant(entry) => {
295 let hash = self.db.block_hash_ref(number)?;
296 entry.insert(hash);
297 Ok(hash)
298 }
299 }
300 }
301}
302
303impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
304 type Error = ExtDB::Error;
305
306 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
307 match self.cache.accounts.get(&address) {
308 Some(acc) => Ok(acc.info()),
309 None => self.db.basic_ref(address),
310 }
311 }
312
313 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
314 match self.cache.contracts.get(&code_hash) {
315 Some(entry) => Ok(entry.clone()),
316 None => self.db.code_by_hash_ref(code_hash),
317 }
318 }
319
320 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
321 match self.cache.accounts.get(&address) {
322 Some(acc_entry) => match acc_entry.storage.get(&index) {
323 Some(entry) => Ok(*entry),
324 None => {
325 if matches!(
326 acc_entry.account_state,
327 AccountState::StorageCleared | AccountState::NotExisting
328 ) {
329 Ok(U256::ZERO)
330 } else {
331 self.db.storage_ref(address, index)
332 }
333 }
334 },
335 None => self.db.storage_ref(address, index),
336 }
337 }
338
339 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
340 match self.cache.block_hashes.get(&U256::from(number)) {
341 Some(entry) => Ok(*entry),
342 None => self.db.block_hash_ref(number),
343 }
344 }
345}
346
347#[derive(Debug, Clone, Default)]
348#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
349pub struct DbAccount {
350 pub info: AccountInfo,
351 pub account_state: AccountState,
353 pub storage: HashMap<U256, U256>,
355}
356
357impl DbAccount {
358 pub fn new_not_existing() -> Self {
359 Self {
360 account_state: AccountState::NotExisting,
361 ..Default::default()
362 }
363 }
364
365 pub fn info(&self) -> Option<AccountInfo> {
366 if matches!(self.account_state, AccountState::NotExisting) {
367 None
368 } else {
369 Some(self.info.clone())
370 }
371 }
372}
373
374impl From<Option<AccountInfo>> for DbAccount {
375 fn from(from: Option<AccountInfo>) -> Self {
376 from.map(Self::from).unwrap_or_else(Self::new_not_existing)
377 }
378}
379
380impl From<AccountInfo> for DbAccount {
381 fn from(info: AccountInfo) -> Self {
382 Self {
383 info,
384 account_state: AccountState::None,
385 ..Default::default()
386 }
387 }
388}
389
390#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
391#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
392pub enum AccountState {
393 NotExisting,
396 Touched,
398 StorageCleared,
401 #[default]
403 None,
404}
405
406impl AccountState {
407 pub fn is_storage_cleared(&self) -> bool {
409 matches!(self, AccountState::StorageCleared)
410 }
411}
412
413#[derive(Debug, Default, Clone)]
417pub struct BenchmarkDB(pub Bytecode, B256);
418
419impl BenchmarkDB {
420 pub fn new_bytecode(bytecode: Bytecode) -> Self {
421 let hash = bytecode.hash_slow();
422 Self(bytecode, hash)
423 }
424}
425
426pub const FFADDRESS: Address = address!("0xffffffffffffffffffffffffffffffffffffffff");
428pub const BENCH_TARGET: Address = FFADDRESS;
429pub const BENCH_TARGET_BALANCE: U256 = U256::from_limbs([10_000_000, 0, 0, 0]);
430pub const EEADDRESS: Address = address!("0xeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee");
432pub const BENCH_CALLER: Address = EEADDRESS;
433pub const BENCH_CALLER_BALANCE: U256 = U256::from_limbs([10_000_000, 0, 0, 0]);
434
435impl Database for BenchmarkDB {
436 type Error = Infallible;
437 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
439 if address == BENCH_TARGET {
440 return Ok(Some(AccountInfo {
441 nonce: 1,
442 balance: BENCH_TARGET_BALANCE,
443 code: Some(self.0.clone()),
444 code_hash: self.1,
445 }));
446 }
447 if address == BENCH_CALLER {
448 return Ok(Some(AccountInfo {
449 nonce: 0,
450 balance: BENCH_CALLER_BALANCE,
451 code: None,
452 code_hash: KECCAK_EMPTY,
453 }));
454 }
455 Ok(None)
456 }
457
458 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
460 Ok(Bytecode::default())
461 }
462
463 fn storage(&mut self, _address: Address, _index: U256) -> Result<U256, Self::Error> {
465 Ok(U256::default())
466 }
467
468 fn block_hash(&mut self, _number: u64) -> Result<B256, Self::Error> {
470 Ok(B256::default())
471 }
472}
473
474#[cfg(test)]
475mod tests {
476 use super::{CacheDB, EmptyDB};
477 use database_interface::Database;
478 use primitives::{Address, HashMap, U256};
479 use state::AccountInfo;
480
481 #[test]
482 fn test_insert_account_storage() {
483 let account = Address::with_last_byte(42);
484 let nonce = 42;
485 let mut init_state = CacheDB::new(EmptyDB::default());
486 init_state.insert_account_info(
487 account,
488 AccountInfo {
489 nonce,
490 ..Default::default()
491 },
492 );
493
494 let (key, value) = (U256::from(123), U256::from(456));
495 let mut new_state = CacheDB::new(init_state);
496 new_state
497 .insert_account_storage(account, key, value)
498 .unwrap();
499
500 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
501 assert_eq!(new_state.storage(account, key), Ok(value));
502 }
503
504 #[test]
505 fn test_replace_account_storage() {
506 let account = Address::with_last_byte(42);
507 let nonce = 42;
508 let mut init_state = CacheDB::new(EmptyDB::default());
509 init_state.insert_account_info(
510 account,
511 AccountInfo {
512 nonce,
513 ..Default::default()
514 },
515 );
516
517 let (key0, value0) = (U256::from(123), U256::from(456));
518 let (key1, value1) = (U256::from(789), U256::from(999));
519 init_state
520 .insert_account_storage(account, key0, value0)
521 .unwrap();
522
523 let mut new_state = CacheDB::new(init_state);
524 new_state
525 .replace_account_storage(account, HashMap::from_iter([(key1, value1)]))
526 .unwrap();
527
528 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
529 assert_eq!(new_state.storage(account, key0), Ok(U256::ZERO));
530 assert_eq!(new_state.storage(account, key1), Ok(value1));
531 }
532
533 #[cfg(feature = "serde")]
534 #[test]
535 fn test_serialize_deserialize_cachedb() {
536 let account = Address::with_last_byte(69);
537 let nonce = 420;
538 let mut init_state = CacheDB::new(EmptyDB::default());
539 init_state.insert_account_info(
540 account,
541 AccountInfo {
542 nonce,
543 ..Default::default()
544 },
545 );
546
547 let serialized = serde_json::to_string(&init_state).unwrap();
548 let deserialized: CacheDB<EmptyDB> = serde_json::from_str(&serialized).unwrap();
549
550 assert!(deserialized.cache.accounts.contains_key(&account));
551 assert_eq!(
552 deserialized
553 .cache
554 .accounts
555 .get(&account)
556 .unwrap()
557 .info
558 .nonce,
559 nonce
560 );
561 }
562}