1use std::vec::Vec;
2
3use crate::fast_hasher::SimpleBuildHasher;
4use alloy::primitives::map::{Entry, HashMap};
5use alloy::primitives::BlockNumber;
6use alloy::{
7 consensus::constants::KECCAK_EMPTY,
8 primitives::{Address, Log, B256, U256},
9};
10use revm::database::AccountState;
11use revm::state::{Account, AccountInfo, Bytecode};
12use revm::{Database, DatabaseCommit, DatabaseRef};
13
14#[derive(Debug, Clone)]
22pub struct FastCacheDB<ExtDB> {
23 pub accounts: HashMap<Address, FastDbAccount>,
26 pub contracts: HashMap<B256, Bytecode, SimpleBuildHasher>,
28 pub logs: Vec<Log>,
30 pub block_hashes: HashMap<BlockNumber, B256>,
32 pub db: ExtDB,
36}
37
38impl<ExtDB: Default + DatabaseRef> Default for FastCacheDB<ExtDB> {
39 fn default() -> Self {
40 Self::new(ExtDB::default())
41 }
42}
43
44impl<ExtDB> FastCacheDB<ExtDB> {
45 pub fn new(db: ExtDB) -> Self
46 where
47 ExtDB: DatabaseRef,
48 {
49 let mut contracts = HashMap::with_hasher(SimpleBuildHasher::default());
50 contracts.insert(KECCAK_EMPTY, Bytecode::default());
51 contracts.insert(B256::ZERO, Bytecode::default());
52 Self { accounts: HashMap::default(), contracts, logs: Vec::default(), block_hashes: HashMap::default(), db }
53 }
54
55 pub fn insert_contract(&mut self, account: &mut AccountInfo) {
61 if let Some(code) = &account.code {
62 if !code.is_empty() {
63 if account.code_hash == KECCAK_EMPTY {
64 account.code_hash = code.hash_slow();
65 }
66 self.contracts.entry(account.code_hash).or_insert_with(|| code.clone());
67 }
68 }
69 if account.code_hash == B256::ZERO {
70 account.code_hash = KECCAK_EMPTY;
71 }
72 }
73
74 pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
76 self.insert_contract(&mut info);
77 self.accounts.entry(address).or_default().info = info;
78 }
79}
80
81impl<ExtDB: DatabaseRef> FastCacheDB<ExtDB> {
82 pub fn load_account(&mut self, address: Address) -> Result<&mut FastDbAccount, ExtDB::Error> {
86 let db = &self.db;
87 match self.accounts.entry(address) {
88 Entry::Occupied(entry) => Ok(entry.into_mut()),
89 Entry::Vacant(entry) => Ok(entry.insert(
90 db.basic_ref(address)?
91 .map(|info| FastDbAccount { info, ..Default::default() })
92 .unwrap_or_else(FastDbAccount::new_not_existing),
93 )),
94 }
95 }
96
97 pub fn insert_account_storage(&mut self, address: Address, slot: U256, value: U256) -> Result<(), ExtDB::Error> {
99 let account = self.load_account(address)?;
100 account.storage.insert(slot, value);
101 Ok(())
102 }
103
104 pub fn replace_account_storage(&mut self, address: Address, storage: HashMap<U256, U256>) -> Result<(), ExtDB::Error> {
106 let account = self.load_account(address)?;
107 account.account_state = AccountState::StorageCleared;
108 account.storage = storage.into_iter().collect();
109 Ok(())
110 }
111}
112
113impl<ExtDB> DatabaseCommit for FastCacheDB<ExtDB> {
114 fn commit(&mut self, changes: HashMap<Address, Account>) {
115 for (address, mut account) in changes {
116 if !account.is_touched() {
117 continue;
118 }
119 if account.is_selfdestructed() {
120 let db_account = self.accounts.entry(address).or_default();
121 db_account.storage.clear();
122 db_account.account_state = AccountState::NotExisting;
123 db_account.info = AccountInfo::default();
124 continue;
125 }
126 let is_newly_created = account.is_created();
127 self.insert_contract(&mut account.info);
128
129 let db_account = self.accounts.entry(address).or_default();
130 db_account.info = account.info;
131
132 db_account.account_state = if is_newly_created {
133 db_account.storage.clear();
134 AccountState::StorageCleared
135 } else if db_account.account_state.is_storage_cleared() {
136 AccountState::StorageCleared
138 } else {
139 AccountState::Touched
140 };
141 db_account.storage.extend(account.storage.into_iter().map(|(key, value)| (key, value.present_value())));
142 }
143 }
144}
145
146impl<ExtDB: DatabaseRef> Database for FastCacheDB<ExtDB> {
147 type Error = ExtDB::Error;
148
149 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
150 let basic = match self.accounts.entry(address) {
151 Entry::Occupied(entry) => entry.into_mut(),
152 Entry::Vacant(entry) => entry.insert(
153 self.db
154 .basic_ref(address)?
155 .map(|info| FastDbAccount { info, ..Default::default() })
156 .unwrap_or_else(FastDbAccount::new_not_existing),
157 ),
158 };
159 Ok(basic.info())
160 }
161
162 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
163 match self.contracts.entry(code_hash) {
164 Entry::Occupied(entry) => Ok(entry.get().clone()),
165 Entry::Vacant(entry) => {
166 Ok(entry.insert(self.db.code_by_hash_ref(code_hash)?).clone())
168 }
169 }
170 }
171
172 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
176 match self.accounts.entry(address) {
177 Entry::Occupied(mut acc_entry) => {
178 let acc_entry = acc_entry.get_mut();
179 match acc_entry.storage.entry(index) {
180 Entry::Occupied(entry) => Ok(*entry.get()),
181 Entry::Vacant(entry) => {
182 if matches!(acc_entry.account_state, AccountState::StorageCleared | AccountState::NotExisting) {
183 Ok(U256::ZERO)
184 } else {
185 let slot = self.db.storage_ref(address, index)?;
186 entry.insert(slot);
187 Ok(slot)
188 }
189 }
190 }
191 }
192 Entry::Vacant(acc_entry) => {
193 let info = self.db.basic_ref(address)?;
195 let (account, value) = if info.is_some() {
196 let value = self.db.storage_ref(address, index)?;
197 let mut account: FastDbAccount = info.into();
198 account.storage.insert(index, value);
199 (account, value)
200 } else {
201 (info.into(), U256::ZERO)
202 };
203 acc_entry.insert(account);
204 Ok(value)
205 }
206 }
207 }
208
209 fn block_hash(&mut self, number: BlockNumber) -> Result<B256, Self::Error> {
210 match self.block_hashes.entry(number) {
211 Entry::Occupied(entry) => Ok(*entry.get()),
212 Entry::Vacant(entry) => {
213 let hash = self.db.block_hash_ref(number)?;
214 entry.insert(hash);
215 Ok(hash)
216 }
217 }
218 }
219}
220
221impl<ExtDB: DatabaseRef> DatabaseRef for FastCacheDB<ExtDB> {
222 type Error = ExtDB::Error;
223
224 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
225 match self.accounts.get(&address) {
226 Some(acc) => Ok(acc.info()),
227 None => self.db.basic_ref(address),
228 }
229 }
230
231 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
232 match self.contracts.get(&code_hash) {
233 Some(entry) => Ok(entry.clone()),
234 None => self.db.code_by_hash_ref(code_hash),
235 }
236 }
237
238 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
239 match self.accounts.get(&address) {
240 Some(acc_entry) => match acc_entry.storage.get(&index) {
241 Some(entry) => Ok(*entry),
242 None => {
243 if matches!(acc_entry.account_state, AccountState::StorageCleared | AccountState::NotExisting) {
244 Ok(U256::ZERO)
245 } else {
246 self.db.storage_ref(address, index)
247 }
248 }
249 },
250 None => self.db.storage_ref(address, index),
251 }
252 }
253
254 fn block_hash_ref(&self, number: BlockNumber) -> Result<B256, Self::Error> {
255 match self.block_hashes.get(&number) {
256 Some(entry) => Ok(*entry),
257 None => self.db.block_hash_ref(number),
258 }
259 }
260}
261
262#[derive(Debug, Clone, Default)]
263pub struct FastDbAccount {
264 pub info: AccountInfo,
265 pub account_state: AccountState,
267 pub storage: HashMap<U256, U256, SimpleBuildHasher>,
269}
270
271impl FastDbAccount {
272 pub fn new_not_existing() -> Self {
273 Self { account_state: AccountState::NotExisting, ..Default::default() }
274 }
275
276 pub fn info(&self) -> Option<AccountInfo> {
277 if matches!(self.account_state, AccountState::NotExisting) {
278 None
279 } else {
280 Some(self.info.clone())
281 }
282 }
283}
284
285impl From<Option<AccountInfo>> for FastDbAccount {
286 fn from(from: Option<AccountInfo>) -> Self {
287 from.map(Self::from).unwrap_or_else(Self::new_not_existing)
288 }
289}
290
291impl From<AccountInfo> for FastDbAccount {
292 fn from(info: AccountInfo) -> Self {
293 Self { info, account_state: AccountState::None, ..Default::default() }
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use alloy::primitives::map::HashMap;
300 use std::collections::BTreeMap;
301 use std::sync::Arc;
302
303 use super::FastCacheDB;
304 use crate::in_memory_db::LoomInMemoryDB;
305 use alloy::primitives::{Bytes, B256};
306 use alloy::rpc::types::trace::geth::AccountState as GethAccountState;
307 use revm::database::EmptyDB;
308 use revm::primitives::{Address, I256, KECCAK_EMPTY, U256};
309 use revm::state::{AccountInfo, Bytecode};
310 use revm::{Database, DatabaseRef};
311
312 #[test]
313 fn test_insert_account_storage() {
314 let account = Address::with_last_byte(42);
315 let nonce = 42;
316 let mut init_state = FastCacheDB::new(EmptyDB::default());
317 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
318
319 let (key, value) = (U256::from(123), U256::from(456));
320 let mut new_state = FastCacheDB::new(init_state);
321 new_state.insert_account_storage(account, key, value).unwrap();
322
323 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
324 assert_eq!(new_state.storage(account, key), Ok(value));
325 }
326
327 #[test]
328 fn test_insert_account_storage_inherited() {
329 let account = Address::with_last_byte(42);
330 let nonce = 42;
331 let mut init_state = FastCacheDB::new(EmptyDB::default());
332 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
333
334 let (key, value) = (U256::from(123), U256::from(456));
335 let mut new_state = FastCacheDB::new(init_state);
336 new_state.insert_account_storage(account, key, value).unwrap();
337
338 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
339 assert_eq!(new_state.storage(account, key), Ok(value));
340 }
341
342 #[test]
343 fn test_replace_account_storage() {
344 let account = Address::with_last_byte(42);
345 let nonce = 42;
346 let mut init_state = FastCacheDB::new(EmptyDB::default());
347 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
348
349 let (key0, value0) = (U256::from(123), U256::from(456));
350 let (key1, value1) = (U256::from(789), U256::from(999));
351 init_state.insert_account_storage(account, key0, value0).unwrap();
352
353 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
354 assert_eq!(new_state.accounts.len(), 0);
355 let mut hm: HashMap<U256, U256> = Default::default();
356 hm.insert(key1, value1);
357
358 new_state.replace_account_storage(account, hm).unwrap();
359
360 let mut new_state = new_state.merge();
361
362 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
363 assert_eq!(new_state.storage(account, key0).unwrap(), value0);
364 assert_eq!(new_state.storage(account, key1).unwrap(), value1);
365 assert_eq!(new_state.accounts.len(), 1);
366 }
367
368 #[test]
369 fn test_apply_geth_update() {
370 let account = Address::with_last_byte(42);
371 let nonce = 42;
372 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
373 let mut init_state = FastCacheDB::new(EmptyDB::new());
374 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
375
376 let (key0, value0) = (U256::from(123), U256::from(456));
377 let (key1, value1) = (U256::from(789), U256::from(999));
378 init_state.insert_account_storage(account, key0, value0).unwrap();
379 init_state.insert_account_storage(account, key1, value1).unwrap();
380
381 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
382 assert_eq!(new_state.accounts.len(), 0);
383
384 let update_record = GethAccountState {
385 balance: None,
386 code: Some(Bytes::from(vec![1, 2, 3])),
387 nonce: Some(nonce + 1),
388 storage: [(B256::from(I256::try_from(123).unwrap()), B256::from(I256::try_from(333).unwrap()))].into(),
389 };
390
391 let update: BTreeMap<Address, GethAccountState> = [(account, update_record)].into();
392
393 new_state.apply_geth_update(update);
394
395 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(code.clone()));
396 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
397 assert_eq!(new_state.storage_ref(account, key0), Ok(U256::from(333)));
398 assert_eq!(new_state.storage_ref(account, key1), Ok(value1));
399 assert_eq!(new_state.accounts.len(), 1);
400
401 let mut new_state = new_state.merge();
402
403 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(code.clone()));
404 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
405 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
406 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
407 assert_eq!(new_state.accounts.len(), 1);
408 }
409
410 #[test]
411 fn test_merge() {
412 let account = Address::with_last_byte(42);
413 let nonce = 42;
414 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
415 let mut init_state = FastCacheDB::new(EmptyDB::default());
416 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
417
418 let (key0, value0) = (U256::from(123), U256::from(456));
419 let (key1, value1) = (U256::from(789), U256::from(999));
420 let (key2, value2) = (U256::from(999), U256::from(111));
421 init_state.insert_account_storage(account, key0, value0).unwrap();
422 init_state.insert_account_storage(account, key1, value1).unwrap();
423
424 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
425 assert_eq!(new_state.accounts.len(), 0);
426
427 new_state.insert_account_info(
428 account,
429 AccountInfo {
430 balance: U256::ZERO,
431 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
432 nonce: nonce + 1,
433 code_hash: KECCAK_EMPTY,
434 },
435 );
436
437 new_state.insert_account_storage(account, key0, U256::from(333)).unwrap();
438 new_state.insert_account_storage(account, key2, value2).unwrap();
439
440 let mut new_state = new_state.merge();
441
442 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))));
443 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
444 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
445 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
446 assert_eq!(new_state.storage_ref(account, key2).unwrap(), value2);
447 assert_eq!(new_state.accounts.len(), 1);
448 }
449
450 #[test]
451 fn test_update_cell() {
452 let account = Address::with_last_byte(42);
453 let account2 = Address::with_last_byte(43);
454 let nonce = 42;
455 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
456 let mut init_state = FastCacheDB::new(EmptyDB::default());
457 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
458
459 let (key0, value0) = (U256::from(123), U256::from(456));
460 let (key1, value1) = (U256::from(789), U256::from(999));
461 let (key2, value2) = (U256::from(999), U256::from(111));
462 init_state.insert_account_storage(account, key0, value0).unwrap();
463 init_state.insert_account_storage(account, key1, value1).unwrap();
464
465 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
466 assert_eq!(new_state.accounts.len(), 0);
467
468 new_state.insert_account_info(
469 account,
470 AccountInfo {
471 balance: U256::ZERO,
472 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
473 nonce: nonce + 1,
474 code_hash: KECCAK_EMPTY,
475 },
476 );
477
478 new_state.insert_account_info(
479 account2,
480 AccountInfo {
481 balance: U256::ZERO,
482 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
483 nonce: nonce + 1,
484 code_hash: KECCAK_EMPTY,
485 },
486 );
487
488 new_state.insert_account_storage(account, key0, U256::from(333)).unwrap();
489 new_state.insert_account_storage(account, key2, value2).unwrap();
490
491 let mut new_state = new_state.update_cells();
492
493 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))));
494 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
495 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
496 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
497 assert_eq!(new_state.storage_ref(account, key2).unwrap(), U256::ZERO);
498 assert_eq!(new_state.storage_ref(account2, key0).unwrap(), U256::ZERO);
499 assert_eq!(new_state.accounts.len(), 1);
500 assert_eq!(new_state.basic(account2).unwrap(), None);
501 assert_eq!(new_state.accounts.len(), 2);
502 assert_eq!(new_state.basic(account2).unwrap(), None);
503 assert_eq!(new_state.accounts.len(), 2);
504 }
505
506 }