1use core::convert::Infallible;
2use database_interface::{
3 Database, DatabaseCommit, DatabaseRef, EmptyDB, BENCH_CALLER, BENCH_CALLER_BALANCE,
4 BENCH_TARGET, BENCH_TARGET_BALANCE,
5};
6use primitives::{
7 hash_map::Entry, Address, AddressMap, B256Map, HashMap, Log, StorageKey, StorageValue, B256,
8 KECCAK_EMPTY, U256,
9};
10use state::{Account, AccountInfo, Bytecode};
11use std::vec::Vec;
12
13pub type InMemoryDB = CacheDB<EmptyDB>;
15
16#[derive(Debug, Clone)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Cache {
24 pub accounts: AddressMap<DbAccount>,
27 pub contracts: B256Map<Bytecode>,
29 pub logs: Vec<Log>,
31 pub block_hashes: HashMap<U256, B256>,
33}
34
35impl Default for Cache {
36 fn default() -> Self {
37 let mut contracts = HashMap::default();
38 contracts.insert(KECCAK_EMPTY, Bytecode::default());
39 contracts.insert(B256::ZERO, Bytecode::default());
40
41 Cache {
42 accounts: HashMap::default(),
43 contracts,
44 logs: Vec::default(),
45 block_hashes: HashMap::default(),
46 }
47 }
48}
49
50#[derive(Debug, Clone)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55pub struct CacheDB<ExtDB> {
56 pub cache: Cache,
58 pub db: ExtDB,
62}
63
64impl<ExtDB: Default> Default for CacheDB<ExtDB> {
65 fn default() -> Self {
66 Self::new(ExtDB::default())
67 }
68}
69
70impl<ExtDb> CacheDB<CacheDB<ExtDb>> {
71 pub fn flatten(self) -> CacheDB<ExtDb> {
79 let CacheDB {
80 cache:
81 Cache {
82 accounts,
83 contracts,
84 logs,
85 block_hashes,
86 },
87 db: mut inner,
88 ..
89 } = self;
90
91 inner.cache.accounts.extend(accounts);
92 inner.cache.contracts.extend(contracts);
93 inner.cache.logs.extend(logs);
94 inner.cache.block_hashes.extend(block_hashes);
95 inner
96 }
97
98 pub fn discard_outer(self) -> CacheDB<ExtDb> {
100 self.db
101 }
102}
103
104impl<ExtDB> CacheDB<ExtDB> {
105 pub fn new(db: ExtDB) -> Self {
107 Self {
108 cache: Cache::default(),
109 db,
110 }
111 }
112
113 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
119 if let Some(code) = &account.code {
120 if !code.is_empty() {
121 if account.code_hash == KECCAK_EMPTY {
122 account.code_hash = code.hash_slow();
123 }
124 self.cache
125 .contracts
126 .entry(account.code_hash)
127 .or_insert_with(|| code.clone());
128 }
129 }
130 if account.code_hash.is_zero() {
131 account.code_hash = KECCAK_EMPTY;
132 }
133 }
134
135 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
137 self.insert_contract(&mut info);
138 let account_entry = self.cache.accounts.entry(address).or_default();
139 account_entry.update_info(info);
140 if account_entry.account_state == AccountState::NotExisting {
141 account_entry.update_account_state(AccountState::None);
142 }
143 }
144
145 pub fn nest(self) -> CacheDB<Self> {
147 CacheDB::new(self)
148 }
149}
150
151impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
152 pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, ExtDB::Error> {
156 let db = &self.db;
157 match self.cache.accounts.entry(address) {
158 Entry::Occupied(entry) => Ok(entry.into_mut()),
159 Entry::Vacant(entry) => Ok(entry.insert(
160 db.basic_ref(address)?
161 .map(|info| DbAccount {
162 info,
163 ..Default::default()
164 })
165 .unwrap_or_else(DbAccount::new_not_existing),
166 )),
167 }
168 }
169
170 pub fn insert_account_storage(
172 &mut self,
173 address: Address,
174 slot: StorageKey,
175 value: StorageValue,
176 ) -> Result<(), ExtDB::Error> {
177 let account = self.load_account(address)?;
178 account.storage.insert(slot, value);
179 Ok(())
180 }
181
182 pub fn replace_account_storage(
184 &mut self,
185 address: Address,
186 storage: HashMap<StorageKey, StorageValue>,
187 ) -> Result<(), ExtDB::Error> {
188 let account = self.load_account(address)?;
189 account.account_state = AccountState::StorageCleared;
190 account.storage = storage.into_iter().collect();
191 Ok(())
192 }
193
194 #[cfg(feature = "std")]
196 pub fn pretty_print(&self) -> String {
197 let mut output = String::new();
198 output.push_str("CacheDB:\n");
199 output.push_str(&format!(
200 " accounts: {} total\n",
201 self.cache.accounts.len()
202 ));
203
204 let mut accounts: Vec<_> = self.cache.accounts.iter().collect();
206 accounts.sort_by_key(|(addr, _)| *addr);
207
208 for (address, db_account) in accounts {
209 output.push_str(&format!(" [{address}]:\n"));
210 output.push_str(&format!(" state: {:?}\n", db_account.account_state));
211
212 if let Some(info) = db_account.info() {
213 output.push_str(&format!(" balance: {}\n", info.balance));
214 output.push_str(&format!(" nonce: {}\n", info.nonce));
215 output.push_str(&format!(" code_hash: {}\n", info.code_hash));
216
217 if let Some(code) = info.code {
218 if !code.is_empty() {
219 output.push_str(&format!(" code: {} bytes\n", code.len()));
220 }
221 }
222 } else {
223 output.push_str(" account: None (not existing)\n");
224 }
225
226 if !db_account.storage.is_empty() {
227 output.push_str(&format!(
228 " storage: {} slots\n",
229 db_account.storage.len()
230 ));
231 let mut storage: Vec<_> = db_account.storage.iter().collect();
232 storage.sort_by_key(|(k, _)| *k);
233 for (key, value) in storage {
234 output.push_str(&format!(" [{key:#x}]: {value:#x}\n"));
235 }
236 }
237 }
238
239 if !self.cache.contracts.is_empty() {
240 output.push_str(&format!(
241 " contracts: {} total\n",
242 self.cache.contracts.len()
243 ));
244 let mut contracts: Vec<_> = self.cache.contracts.iter().collect();
245 contracts.sort_by_key(|(h, _)| *h);
246 for (hash, bytecode) in contracts {
247 output.push_str(&format!(" [{hash}]: {} bytes\n", bytecode.len()));
248 }
249 }
250
251 if !self.cache.logs.is_empty() {
253 output.push_str(&format!(" logs: {} total\n", self.cache.logs.len()));
254 for (i, log) in self.cache.logs.iter().enumerate() {
255 output.push_str(&format!(
257 " [{i}]: address: {:?}, topics: {}\n",
258 log.address,
259 log.data.topics().len()
260 ));
261 }
262 }
263
264 if !self.cache.block_hashes.is_empty() {
266 output.push_str(&format!(
267 " block_hashes: {} total\n",
268 self.cache.block_hashes.len()
269 ));
270 let mut block_hashes: Vec<_> = self.cache.block_hashes.iter().collect();
271 block_hashes.sort_by_key(|(num, _)| *num);
272 for (num, hash) in block_hashes {
273 output.push_str(&format!(" [{num}]: {hash}\n"));
274 }
275 }
276
277 output.push_str("}\n");
278 output
279 }
280}
281
282impl<ExtDB> DatabaseCommit for CacheDB<ExtDB> {
283 fn commit(&mut self, changes: HashMap<Address, Account>) {
284 for (address, mut account) in changes {
285 if !account.is_touched() {
286 continue;
287 }
288 if account.is_selfdestructed() {
289 let db_account = self.cache.accounts.entry(address).or_default();
290 db_account.storage.clear();
291 db_account.account_state = AccountState::NotExisting;
292 db_account.info = AccountInfo::default();
293 continue;
294 }
295 let is_newly_created = account.is_created();
296 self.insert_contract(&mut account.info);
297
298 let db_account = self.cache.accounts.entry(address).or_default();
299 db_account.info = account.info;
300
301 db_account.account_state = if is_newly_created {
302 db_account.storage.clear();
303 AccountState::StorageCleared
304 } else if db_account.account_state.is_storage_cleared() {
305 AccountState::StorageCleared
307 } else {
308 AccountState::Touched
309 };
310 db_account.storage.extend(
311 account
312 .storage
313 .into_iter()
314 .map(|(key, value)| (key, value.present_value())),
315 );
316 }
317 }
318}
319
320impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
321 type Error = ExtDB::Error;
322
323 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
324 let basic = match self.cache.accounts.entry(address) {
325 Entry::Occupied(entry) => entry.into_mut(),
326 Entry::Vacant(entry) => entry.insert(
327 self.db
328 .basic_ref(address)?
329 .map(|info| DbAccount {
330 info,
331 ..Default::default()
332 })
333 .unwrap_or_else(DbAccount::new_not_existing),
334 ),
335 };
336 Ok(basic.info())
337 }
338
339 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
340 match self.cache.contracts.entry(code_hash) {
341 Entry::Occupied(entry) => Ok(entry.get().clone()),
342 Entry::Vacant(entry) => {
343 Ok(entry.insert(self.db.code_by_hash_ref(code_hash)?).clone())
345 }
346 }
347 }
348
349 fn storage(
353 &mut self,
354 address: Address,
355 index: StorageKey,
356 ) -> Result<StorageValue, Self::Error> {
357 match self.cache.accounts.entry(address) {
358 Entry::Occupied(mut acc_entry) => {
359 let acc_entry = acc_entry.get_mut();
360 match acc_entry.storage.entry(index) {
361 Entry::Occupied(entry) => Ok(*entry.get()),
362 Entry::Vacant(entry) => {
363 if matches!(
364 acc_entry.account_state,
365 AccountState::StorageCleared | AccountState::NotExisting
366 ) {
367 Ok(StorageValue::ZERO)
368 } else {
369 let slot = self.db.storage_ref(address, index)?;
370 entry.insert(slot);
371 Ok(slot)
372 }
373 }
374 }
375 }
376 Entry::Vacant(acc_entry) => {
377 let info = self.db.basic_ref(address)?;
379 let (account, value) = if info.is_some() {
380 let value = self.db.storage_ref(address, index)?;
381 let mut account: DbAccount = info.into();
382 account.storage.insert(index, value);
383 (account, value)
384 } else {
385 (info.into(), StorageValue::ZERO)
386 };
387 acc_entry.insert(account);
388 Ok(value)
389 }
390 }
391 }
392
393 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
394 match self.cache.block_hashes.entry(U256::from(number)) {
395 Entry::Occupied(entry) => Ok(*entry.get()),
396 Entry::Vacant(entry) => {
397 let hash = self.db.block_hash_ref(number)?;
398 entry.insert(hash);
399 Ok(hash)
400 }
401 }
402 }
403}
404
405impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
406 type Error = ExtDB::Error;
407
408 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
409 match self.cache.accounts.get(&address) {
410 Some(acc) => Ok(acc.info()),
411 None => self.db.basic_ref(address),
412 }
413 }
414
415 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
416 match self.cache.contracts.get(&code_hash) {
417 Some(entry) => Ok(entry.clone()),
418 None => self.db.code_by_hash_ref(code_hash),
419 }
420 }
421
422 fn storage_ref(
423 &self,
424 address: Address,
425 index: StorageKey,
426 ) -> Result<StorageValue, Self::Error> {
427 match self.cache.accounts.get(&address) {
428 Some(acc_entry) => match acc_entry.storage.get(&index) {
429 Some(entry) => Ok(*entry),
430 None => {
431 if matches!(
432 acc_entry.account_state,
433 AccountState::StorageCleared | AccountState::NotExisting
434 ) {
435 Ok(StorageValue::ZERO)
436 } else {
437 self.db.storage_ref(address, index)
438 }
439 }
440 },
441 None => self.db.storage_ref(address, index),
442 }
443 }
444
445 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
446 match self.cache.block_hashes.get(&U256::from(number)) {
447 Some(entry) => Ok(*entry),
448 None => self.db.block_hash_ref(number),
449 }
450 }
451}
452
453#[derive(Debug, Clone, Default)]
455#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
456pub struct DbAccount {
457 pub info: AccountInfo,
459 pub account_state: AccountState,
461 pub storage: HashMap<StorageKey, StorageValue>,
463}
464
465impl DbAccount {
466 pub fn new_not_existing() -> Self {
468 Self {
469 account_state: AccountState::NotExisting,
470 ..Default::default()
471 }
472 }
473
474 pub fn info(&self) -> Option<AccountInfo> {
476 if matches!(self.account_state, AccountState::NotExisting) {
477 None
478 } else {
479 Some(self.info.clone())
480 }
481 }
482
483 #[inline(always)]
485 pub fn update_info(&mut self, info: AccountInfo) {
486 self.info = info;
487 }
488
489 #[inline(always)]
491 pub fn update_account_state(&mut self, account_state: AccountState) {
492 self.account_state = account_state;
493 }
494}
495
496impl From<Option<AccountInfo>> for DbAccount {
497 fn from(from: Option<AccountInfo>) -> Self {
498 from.map(Self::from).unwrap_or_else(Self::new_not_existing)
499 }
500}
501
502impl From<AccountInfo> for DbAccount {
503 fn from(info: AccountInfo) -> Self {
504 Self {
505 info,
506 account_state: AccountState::None,
507 ..Default::default()
508 }
509 }
510}
511
512#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
514#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
515pub enum AccountState {
516 NotExisting,
519 Touched,
521 StorageCleared,
524 #[default]
526 None,
527}
528
529impl AccountState {
530 pub fn is_storage_cleared(&self) -> bool {
532 matches!(self, AccountState::StorageCleared)
533 }
534}
535
536#[derive(Debug, Default, Clone)]
540pub struct BenchmarkDB(pub Bytecode, B256);
541
542impl BenchmarkDB {
543 pub fn new_bytecode(bytecode: Bytecode) -> Self {
545 let hash = bytecode.hash_slow();
546 Self(bytecode, hash)
547 }
548}
549
550impl Database for BenchmarkDB {
551 type Error = Infallible;
552 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
554 if address == BENCH_TARGET {
555 return Ok(Some(AccountInfo {
556 nonce: 1,
557 balance: BENCH_TARGET_BALANCE,
558 code: Some(self.0.clone()),
559 code_hash: self.1,
560 ..Default::default()
561 }));
562 }
563 if address == BENCH_CALLER {
564 return Ok(Some(AccountInfo {
565 nonce: 0,
566 balance: BENCH_CALLER_BALANCE,
567 code: None,
568 code_hash: KECCAK_EMPTY,
569 ..Default::default()
570 }));
571 }
572 Ok(None)
573 }
574
575 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
577 if code_hash == self.1 {
578 Ok(self.0.clone())
579 } else {
580 Ok(Bytecode::default())
581 }
582 }
583
584 fn storage(
586 &mut self,
587 _address: Address,
588 _index: StorageKey,
589 ) -> Result<StorageValue, Self::Error> {
590 Ok(StorageValue::default())
591 }
592
593 fn block_hash(&mut self, _number: u64) -> Result<B256, Self::Error> {
595 Ok(B256::default())
596 }
597}
598
599#[cfg(test)]
600mod tests {
601 use super::{CacheDB, EmptyDB};
602 use database_interface::Database;
603 use primitives::{Address, HashMap, StorageKey, StorageValue};
604 use state::AccountInfo;
605
606 #[test]
607 fn test_insert_account_storage() {
608 let account = Address::with_last_byte(42);
609 let nonce = 42;
610 let mut init_state = CacheDB::new(EmptyDB::default());
611 init_state.insert_account_info(
612 account,
613 AccountInfo {
614 nonce,
615 ..Default::default()
616 },
617 );
618
619 let (key, value) = (StorageKey::from(123), StorageValue::from(456));
620 let mut new_state = CacheDB::new(init_state);
621 new_state
622 .insert_account_storage(account, key, value)
623 .unwrap();
624
625 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
626 assert_eq!(new_state.storage(account, key), Ok(value));
627 }
628
629 #[test]
630 fn test_replace_account_storage() {
631 let account = Address::with_last_byte(42);
632 let nonce = 42;
633 let mut init_state = CacheDB::new(EmptyDB::default());
634 init_state.insert_account_info(
635 account,
636 AccountInfo {
637 nonce,
638 ..Default::default()
639 },
640 );
641
642 let (key0, value0) = (StorageKey::from(123), StorageValue::from(456));
643 let (key1, value1) = (StorageKey::from(789), StorageValue::from(999));
644 init_state
645 .insert_account_storage(account, key0, value0)
646 .unwrap();
647
648 let mut new_state = CacheDB::new(init_state);
649 new_state
650 .replace_account_storage(account, HashMap::from_iter([(key1, value1)]))
651 .unwrap();
652
653 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
654 assert_eq!(new_state.storage(account, key0), Ok(StorageValue::ZERO));
655 assert_eq!(new_state.storage(account, key1), Ok(value1));
656 }
657
658 #[cfg(feature = "std")]
659 #[test]
660 fn test_pretty_print_cachedb() {
661 use primitives::{Bytes, Log, LogData, B256, U256};
662
663 let account = Address::with_last_byte(55);
664 let mut cachedb = CacheDB::new(EmptyDB::default());
665 cachedb.insert_account_info(
666 account,
667 AccountInfo {
668 nonce: 7,
669 ..Default::default()
670 },
671 );
672 let key = StorageKey::from(1);
673 let value = StorageValue::from(2);
674 cachedb.insert_account_storage(account, key, value).unwrap();
675
676 let log = Log {
678 address: account,
679 data: LogData::new(Vec::new(), Bytes::from(vec![0x01u8]))
680 .expect("LogData should have <=4 topics"),
681 };
682 cachedb.cache.logs.push(log);
683
684 cachedb
686 .cache
687 .block_hashes
688 .insert(U256::from(123u64), B256::from([1u8; 32]));
689
690 let s = cachedb.pretty_print();
691 assert!(s.contains("CacheDB:"));
692 assert!(s.contains("accounts: 1 total"));
693 assert!(s.contains("storage: 1 slots"));
695
696 assert!(s.contains("logs: 1 total"));
698 assert!(s.contains("block_hashes: 1 total"));
699 }
700
701 #[cfg(feature = "serde")]
702 #[test]
703 fn test_serialize_deserialize_cachedb() {
704 let account = Address::with_last_byte(69);
705 let nonce = 420;
706 let mut init_state = CacheDB::new(EmptyDB::default());
707 init_state.insert_account_info(
708 account,
709 AccountInfo {
710 nonce,
711 ..Default::default()
712 },
713 );
714
715 let serialized = serde_json::to_string(&init_state).unwrap();
716 let deserialized: CacheDB<EmptyDB> = serde_json::from_str(&serialized).unwrap();
717
718 assert!(deserialized.cache.accounts.contains_key(&account));
719 assert_eq!(
720 deserialized
721 .cache
722 .accounts
723 .get(&account)
724 .unwrap()
725 .info
726 .nonce,
727 nonce
728 );
729 }
730}