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, HashMap, Log, StorageKey, StorageValue, B256, KECCAK_EMPTY, U256,
8};
9use state::{Account, AccountInfo, Bytecode};
10use std::vec::Vec;
11
12pub type InMemoryDB = CacheDB<EmptyDB>;
14
15#[derive(Debug, Clone)]
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22pub struct Cache {
23 pub accounts: HashMap<Address, DbAccount>,
26 pub contracts: HashMap<B256, Bytecode>,
28 pub logs: Vec<Log>,
30 pub block_hashes: HashMap<U256, B256>,
32}
33
34impl Default for Cache {
35 fn default() -> Self {
36 let mut contracts = HashMap::default();
37 contracts.insert(KECCAK_EMPTY, Bytecode::default());
38 contracts.insert(B256::ZERO, Bytecode::default());
39
40 Cache {
41 accounts: HashMap::default(),
42 contracts,
43 logs: Vec::default(),
44 block_hashes: HashMap::default(),
45 }
46 }
47}
48
49#[derive(Debug, Clone)]
53#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
54pub struct CacheDB<ExtDB> {
55 pub cache: Cache,
57 pub db: ExtDB,
61}
62
63impl<ExtDB: Default> Default for CacheDB<ExtDB> {
64 fn default() -> Self {
65 Self::new(ExtDB::default())
66 }
67}
68
69impl<ExtDb> CacheDB<CacheDB<ExtDb>> {
70 pub fn flatten(self) -> CacheDB<ExtDb> {
78 let CacheDB {
79 cache:
80 Cache {
81 accounts,
82 contracts,
83 logs,
84 block_hashes,
85 },
86 db: mut inner,
87 } = self;
88
89 inner.cache.accounts.extend(accounts);
90 inner.cache.contracts.extend(contracts);
91 inner.cache.logs.extend(logs);
92 inner.cache.block_hashes.extend(block_hashes);
93 inner
94 }
95
96 pub fn discard_outer(self) -> CacheDB<ExtDb> {
98 self.db
99 }
100}
101
102impl<ExtDB> CacheDB<ExtDB> {
103 pub fn new(db: ExtDB) -> Self {
105 Self {
106 cache: Cache::default(),
107 db,
108 }
109 }
110
111 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
117 if let Some(code) = &account.code {
118 if !code.is_empty() {
119 if account.code_hash == KECCAK_EMPTY {
120 account.code_hash = code.hash_slow();
121 }
122 self.cache
123 .contracts
124 .entry(account.code_hash)
125 .or_insert_with(|| code.clone());
126 }
127 }
128 if account.code_hash.is_zero() {
129 account.code_hash = KECCAK_EMPTY;
130 }
131 }
132
133 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
135 self.insert_contract(&mut info);
136 let account_entry = self.cache.accounts.entry(address).or_default();
137 account_entry.update_info(info);
138 if account_entry.account_state == AccountState::NotExisting {
139 account_entry.update_account_state(AccountState::None);
140 }
141 }
142
143 pub fn nest(self) -> CacheDB<Self> {
145 CacheDB::new(self)
146 }
147}
148
149impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
150 pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, ExtDB::Error> {
154 let db = &self.db;
155 match self.cache.accounts.entry(address) {
156 Entry::Occupied(entry) => Ok(entry.into_mut()),
157 Entry::Vacant(entry) => Ok(entry.insert(
158 db.basic_ref(address)?
159 .map(|info| DbAccount {
160 info,
161 ..Default::default()
162 })
163 .unwrap_or_else(DbAccount::new_not_existing),
164 )),
165 }
166 }
167
168 pub fn insert_account_storage(
170 &mut self,
171 address: Address,
172 slot: StorageKey,
173 value: StorageValue,
174 ) -> Result<(), ExtDB::Error> {
175 let account = self.load_account(address)?;
176 account.storage.insert(slot, value);
177 Ok(())
178 }
179
180 pub fn replace_account_storage(
182 &mut self,
183 address: Address,
184 storage: HashMap<StorageKey, StorageValue>,
185 ) -> Result<(), ExtDB::Error> {
186 let account = self.load_account(address)?;
187 account.account_state = AccountState::StorageCleared;
188 account.storage = storage.into_iter().collect();
189 Ok(())
190 }
191}
192
193impl<ExtDB> DatabaseCommit for CacheDB<ExtDB> {
194 fn commit(&mut self, changes: HashMap<Address, Account>) {
195 for (address, mut account) in changes {
196 if !account.is_touched() {
197 continue;
198 }
199 if account.is_selfdestructed() {
200 let db_account = self.cache.accounts.entry(address).or_default();
201 db_account.storage.clear();
202 db_account.account_state = AccountState::NotExisting;
203 db_account.info = AccountInfo::default();
204 continue;
205 }
206 let is_newly_created = account.is_created();
207 self.insert_contract(&mut account.info);
208
209 let db_account = self.cache.accounts.entry(address).or_default();
210 db_account.info = account.info;
211
212 db_account.account_state = if is_newly_created {
213 db_account.storage.clear();
214 AccountState::StorageCleared
215 } else if db_account.account_state.is_storage_cleared() {
216 AccountState::StorageCleared
218 } else {
219 AccountState::Touched
220 };
221 db_account.storage.extend(
222 account
223 .storage
224 .into_iter()
225 .map(|(key, value)| (key, value.present_value())),
226 );
227 }
228 }
229}
230
231impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
232 type Error = ExtDB::Error;
233
234 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
235 let basic = match self.cache.accounts.entry(address) {
236 Entry::Occupied(entry) => entry.into_mut(),
237 Entry::Vacant(entry) => entry.insert(
238 self.db
239 .basic_ref(address)?
240 .map(|info| DbAccount {
241 info,
242 ..Default::default()
243 })
244 .unwrap_or_else(DbAccount::new_not_existing),
245 ),
246 };
247 Ok(basic.info())
248 }
249
250 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
251 match self.cache.contracts.entry(code_hash) {
252 Entry::Occupied(entry) => Ok(entry.get().clone()),
253 Entry::Vacant(entry) => {
254 Ok(entry.insert(self.db.code_by_hash_ref(code_hash)?).clone())
256 }
257 }
258 }
259
260 fn storage(
264 &mut self,
265 address: Address,
266 index: StorageKey,
267 ) -> Result<StorageValue, Self::Error> {
268 match self.cache.accounts.entry(address) {
269 Entry::Occupied(mut acc_entry) => {
270 let acc_entry = acc_entry.get_mut();
271 match acc_entry.storage.entry(index) {
272 Entry::Occupied(entry) => Ok(*entry.get()),
273 Entry::Vacant(entry) => {
274 if matches!(
275 acc_entry.account_state,
276 AccountState::StorageCleared | AccountState::NotExisting
277 ) {
278 Ok(StorageValue::ZERO)
279 } else {
280 let slot = self.db.storage_ref(address, index)?;
281 entry.insert(slot);
282 Ok(slot)
283 }
284 }
285 }
286 }
287 Entry::Vacant(acc_entry) => {
288 let info = self.db.basic_ref(address)?;
290 let (account, value) = if info.is_some() {
291 let value = self.db.storage_ref(address, index)?;
292 let mut account: DbAccount = info.into();
293 account.storage.insert(index, value);
294 (account, value)
295 } else {
296 (info.into(), StorageValue::ZERO)
297 };
298 acc_entry.insert(account);
299 Ok(value)
300 }
301 }
302 }
303
304 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
305 match self.cache.block_hashes.entry(U256::from(number)) {
306 Entry::Occupied(entry) => Ok(*entry.get()),
307 Entry::Vacant(entry) => {
308 let hash = self.db.block_hash_ref(number)?;
309 entry.insert(hash);
310 Ok(hash)
311 }
312 }
313 }
314}
315
316impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
317 type Error = ExtDB::Error;
318
319 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
320 match self.cache.accounts.get(&address) {
321 Some(acc) => Ok(acc.info()),
322 None => self.db.basic_ref(address),
323 }
324 }
325
326 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
327 match self.cache.contracts.get(&code_hash) {
328 Some(entry) => Ok(entry.clone()),
329 None => self.db.code_by_hash_ref(code_hash),
330 }
331 }
332
333 fn storage_ref(
334 &self,
335 address: Address,
336 index: StorageKey,
337 ) -> Result<StorageValue, Self::Error> {
338 match self.cache.accounts.get(&address) {
339 Some(acc_entry) => match acc_entry.storage.get(&index) {
340 Some(entry) => Ok(*entry),
341 None => {
342 if matches!(
343 acc_entry.account_state,
344 AccountState::StorageCleared | AccountState::NotExisting
345 ) {
346 Ok(StorageValue::ZERO)
347 } else {
348 self.db.storage_ref(address, index)
349 }
350 }
351 },
352 None => self.db.storage_ref(address, index),
353 }
354 }
355
356 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
357 match self.cache.block_hashes.get(&U256::from(number)) {
358 Some(entry) => Ok(*entry),
359 None => self.db.block_hash_ref(number),
360 }
361 }
362}
363
364#[derive(Debug, Clone, Default)]
366#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
367pub struct DbAccount {
368 pub info: AccountInfo,
370 pub account_state: AccountState,
372 pub storage: HashMap<StorageKey, StorageValue>,
374}
375
376impl DbAccount {
377 pub fn new_not_existing() -> Self {
379 Self {
380 account_state: AccountState::NotExisting,
381 ..Default::default()
382 }
383 }
384
385 pub fn info(&self) -> Option<AccountInfo> {
387 if matches!(self.account_state, AccountState::NotExisting) {
388 None
389 } else {
390 Some(self.info.clone())
391 }
392 }
393
394 #[inline(always)]
396 pub fn update_info(&mut self, info: AccountInfo) {
397 self.info = info;
398 }
399
400 #[inline(always)]
402 pub fn update_account_state(&mut self, account_state: AccountState) {
403 self.account_state = account_state;
404 }
405}
406
407impl From<Option<AccountInfo>> for DbAccount {
408 fn from(from: Option<AccountInfo>) -> Self {
409 from.map(Self::from).unwrap_or_else(Self::new_not_existing)
410 }
411}
412
413impl From<AccountInfo> for DbAccount {
414 fn from(info: AccountInfo) -> Self {
415 Self {
416 info,
417 account_state: AccountState::None,
418 ..Default::default()
419 }
420 }
421}
422
423#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
425#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
426pub enum AccountState {
427 NotExisting,
430 Touched,
432 StorageCleared,
435 #[default]
437 None,
438}
439
440impl AccountState {
441 pub fn is_storage_cleared(&self) -> bool {
443 matches!(self, AccountState::StorageCleared)
444 }
445}
446
447#[derive(Debug, Default, Clone)]
451pub struct BenchmarkDB(pub Bytecode, B256);
452
453impl BenchmarkDB {
454 pub fn new_bytecode(bytecode: Bytecode) -> Self {
456 let hash = bytecode.hash_slow();
457 Self(bytecode, hash)
458 }
459}
460
461impl Database for BenchmarkDB {
462 type Error = Infallible;
463 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
465 if address == BENCH_TARGET {
466 return Ok(Some(AccountInfo {
467 nonce: 1,
468 balance: BENCH_TARGET_BALANCE,
469 code: Some(self.0.clone()),
470 code_hash: self.1,
471 }));
472 }
473 if address == BENCH_CALLER {
474 return Ok(Some(AccountInfo {
475 nonce: 0,
476 balance: BENCH_CALLER_BALANCE,
477 code: None,
478 code_hash: KECCAK_EMPTY,
479 }));
480 }
481 Ok(None)
482 }
483
484 fn code_by_hash(&mut self, _code_hash: B256) -> Result<Bytecode, Self::Error> {
486 Ok(Bytecode::default())
487 }
488
489 fn storage(
491 &mut self,
492 _address: Address,
493 _index: StorageKey,
494 ) -> Result<StorageValue, Self::Error> {
495 Ok(StorageValue::default())
496 }
497
498 fn block_hash(&mut self, _number: u64) -> Result<B256, Self::Error> {
500 Ok(B256::default())
501 }
502}
503
504#[cfg(test)]
505mod tests {
506 use super::{CacheDB, EmptyDB};
507 use database_interface::Database;
508 use primitives::{Address, HashMap, StorageKey, StorageValue};
509 use state::AccountInfo;
510
511 #[test]
512 fn test_insert_account_storage() {
513 let account = Address::with_last_byte(42);
514 let nonce = 42;
515 let mut init_state = CacheDB::new(EmptyDB::default());
516 init_state.insert_account_info(
517 account,
518 AccountInfo {
519 nonce,
520 ..Default::default()
521 },
522 );
523
524 let (key, value) = (StorageKey::from(123), StorageValue::from(456));
525 let mut new_state = CacheDB::new(init_state);
526 new_state
527 .insert_account_storage(account, key, value)
528 .unwrap();
529
530 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
531 assert_eq!(new_state.storage(account, key), Ok(value));
532 }
533
534 #[test]
535 fn test_replace_account_storage() {
536 let account = Address::with_last_byte(42);
537 let nonce = 42;
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 (key0, value0) = (StorageKey::from(123), StorageValue::from(456));
548 let (key1, value1) = (StorageKey::from(789), StorageValue::from(999));
549 init_state
550 .insert_account_storage(account, key0, value0)
551 .unwrap();
552
553 let mut new_state = CacheDB::new(init_state);
554 new_state
555 .replace_account_storage(account, HashMap::from_iter([(key1, value1)]))
556 .unwrap();
557
558 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
559 assert_eq!(new_state.storage(account, key0), Ok(StorageValue::ZERO));
560 assert_eq!(new_state.storage(account, key1), Ok(value1));
561 }
562
563 #[cfg(feature = "serde")]
564 #[test]
565 fn test_serialize_deserialize_cachedb() {
566 let account = Address::with_last_byte(69);
567 let nonce = 420;
568 let mut init_state = CacheDB::new(EmptyDB::default());
569 init_state.insert_account_info(
570 account,
571 AccountInfo {
572 nonce,
573 ..Default::default()
574 },
575 );
576
577 let serialized = serde_json::to_string(&init_state).unwrap();
578 let deserialized: CacheDB<EmptyDB> = serde_json::from_str(&serialized).unwrap();
579
580 assert!(deserialized.cache.accounts.contains_key(&account));
581 assert_eq!(
582 deserialized
583 .cache
584 .accounts
585 .get(&account)
586 .unwrap()
587 .info
588 .nonce,
589 nonce
590 );
591 }
592}