1use std::vec::Vec;
2
3use crate::fast_hasher::SimpleBuildHasher;
4use alloy::primitives::BlockNumber;
5use alloy::primitives::map::{Entry, HashMap};
6use alloy::{
7 consensus::constants::KECCAK_EMPTY,
8 primitives::{Address, B256, Log, 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 && !code.is_empty()
63 {
64 if account.code_hash == KECCAK_EMPTY {
65 account.code_hash = code.hash_slow();
66 }
67 self.contracts.entry(account.code_hash).or_insert_with(|| code.clone());
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) { None } else { Some(self.info.clone()) }
278 }
279}
280
281impl From<Option<AccountInfo>> for FastDbAccount {
282 fn from(from: Option<AccountInfo>) -> Self {
283 from.map(Self::from).unwrap_or_else(Self::new_not_existing)
284 }
285}
286
287impl From<AccountInfo> for FastDbAccount {
288 fn from(info: AccountInfo) -> Self {
289 Self { info, account_state: AccountState::None, ..Default::default() }
290 }
291}
292
293#[cfg(test)]
294mod tests {
295 use alloy::primitives::map::HashMap;
296 use std::collections::BTreeMap;
297 use std::sync::Arc;
298
299 use super::FastCacheDB;
300 use crate::in_memory_db::LoomInMemoryDB;
301 use alloy::primitives::{B256, Bytes};
302 use alloy::rpc::types::trace::geth::AccountState as GethAccountState;
303 use revm::database::EmptyDB;
304 use revm::primitives::{Address, I256, KECCAK_EMPTY, U256};
305 use revm::state::{AccountInfo, Bytecode};
306 use revm::{Database, DatabaseRef};
307
308 #[test]
309 fn test_insert_account_storage() {
310 let account = Address::with_last_byte(42);
311 let nonce = 42;
312 let mut init_state = FastCacheDB::new(EmptyDB::default());
313 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
314
315 let (key, value) = (U256::from(123), U256::from(456));
316 let mut new_state = FastCacheDB::new(init_state);
317 new_state.insert_account_storage(account, key, value).unwrap();
318
319 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
320 assert_eq!(new_state.storage(account, key), Ok(value));
321 }
322
323 #[test]
324 fn test_insert_account_storage_inherited() {
325 let account = Address::with_last_byte(42);
326 let nonce = 42;
327 let mut init_state = FastCacheDB::new(EmptyDB::default());
328 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
329
330 let (key, value) = (U256::from(123), U256::from(456));
331 let mut new_state = FastCacheDB::new(init_state);
332 new_state.insert_account_storage(account, key, value).unwrap();
333
334 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
335 assert_eq!(new_state.storage(account, key), Ok(value));
336 }
337
338 #[test]
339 fn test_replace_account_storage() {
340 let account = Address::with_last_byte(42);
341 let nonce = 42;
342 let mut init_state = FastCacheDB::new(EmptyDB::default());
343 init_state.insert_account_info(account, AccountInfo { nonce, ..Default::default() });
344
345 let (key0, value0) = (U256::from(123), U256::from(456));
346 let (key1, value1) = (U256::from(789), U256::from(999));
347 init_state.insert_account_storage(account, key0, value0).unwrap();
348
349 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
350 assert_eq!(new_state.accounts.len(), 0);
351 let mut hm: HashMap<U256, U256> = Default::default();
352 hm.insert(key1, value1);
353
354 new_state.replace_account_storage(account, hm).unwrap();
355
356 let mut new_state = new_state.merge();
357
358 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
359 assert_eq!(new_state.storage(account, key0).unwrap(), value0);
360 assert_eq!(new_state.storage(account, key1).unwrap(), value1);
361 assert_eq!(new_state.accounts.len(), 1);
362 }
363
364 #[test]
365 fn test_apply_geth_update() {
366 let account = Address::with_last_byte(42);
367 let nonce = 42;
368 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
369 let mut init_state = FastCacheDB::new(EmptyDB::new());
370 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
371
372 let (key0, value0) = (U256::from(123), U256::from(456));
373 let (key1, value1) = (U256::from(789), U256::from(999));
374 init_state.insert_account_storage(account, key0, value0).unwrap();
375 init_state.insert_account_storage(account, key1, value1).unwrap();
376
377 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
378 assert_eq!(new_state.accounts.len(), 0);
379
380 let update_record = GethAccountState {
381 balance: None,
382 code: Some(Bytes::from(vec![1, 2, 3])),
383 nonce: Some(nonce + 1),
384 storage: [(B256::from(I256::try_from(123).unwrap()), B256::from(I256::try_from(333).unwrap()))].into(),
385 };
386
387 let update: BTreeMap<Address, GethAccountState> = [(account, update_record)].into();
388
389 new_state.apply_geth_update(update);
390
391 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(code.clone()));
392 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
393 assert_eq!(new_state.storage_ref(account, key0), Ok(U256::from(333)));
394 assert_eq!(new_state.storage_ref(account, key1), Ok(value1));
395 assert_eq!(new_state.accounts.len(), 1);
396
397 let mut new_state = new_state.merge();
398
399 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(code.clone()));
400 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
401 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
402 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
403 assert_eq!(new_state.accounts.len(), 1);
404 }
405
406 #[test]
407 fn test_merge() {
408 let account = Address::with_last_byte(42);
409 let nonce = 42;
410 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
411 let mut init_state = FastCacheDB::new(EmptyDB::default());
412 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
413
414 let (key0, value0) = (U256::from(123), U256::from(456));
415 let (key1, value1) = (U256::from(789), U256::from(999));
416 let (key2, value2) = (U256::from(999), U256::from(111));
417 init_state.insert_account_storage(account, key0, value0).unwrap();
418 init_state.insert_account_storage(account, key1, value1).unwrap();
419
420 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
421 assert_eq!(new_state.accounts.len(), 0);
422
423 new_state.insert_account_info(
424 account,
425 AccountInfo {
426 balance: U256::ZERO,
427 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
428 nonce: nonce + 1,
429 code_hash: KECCAK_EMPTY,
430 },
431 );
432
433 new_state.insert_account_storage(account, key0, U256::from(333)).unwrap();
434 new_state.insert_account_storage(account, key2, value2).unwrap();
435
436 let mut new_state = new_state.merge();
437
438 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))));
439 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
440 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
441 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
442 assert_eq!(new_state.storage_ref(account, key2).unwrap(), value2);
443 assert_eq!(new_state.accounts.len(), 1);
444 }
445
446 #[test]
447 fn test_update_cell() {
448 let account = Address::with_last_byte(42);
449 let account2 = Address::with_last_byte(43);
450 let nonce = 42;
451 let code = Bytecode::new_raw(Bytes::from(vec![1, 2, 3]));
452 let mut init_state = FastCacheDB::new(EmptyDB::default());
453 init_state.insert_account_info(account, AccountInfo { nonce, code: Some(code.clone()), ..Default::default() });
454
455 let (key0, value0) = (U256::from(123), U256::from(456));
456 let (key1, value1) = (U256::from(789), U256::from(999));
457 let (key2, value2) = (U256::from(999), U256::from(111));
458 init_state.insert_account_storage(account, key0, value0).unwrap();
459 init_state.insert_account_storage(account, key1, value1).unwrap();
460
461 let mut new_state = LoomInMemoryDB::new(Arc::new(init_state));
462 assert_eq!(new_state.accounts.len(), 0);
463
464 new_state.insert_account_info(
465 account,
466 AccountInfo {
467 balance: U256::ZERO,
468 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
469 nonce: nonce + 1,
470 code_hash: KECCAK_EMPTY,
471 },
472 );
473
474 new_state.insert_account_info(
475 account2,
476 AccountInfo {
477 balance: U256::ZERO,
478 code: Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))),
479 nonce: nonce + 1,
480 code_hash: KECCAK_EMPTY,
481 },
482 );
483
484 new_state.insert_account_storage(account, key0, U256::from(333)).unwrap();
485 new_state.insert_account_storage(account, key2, value2).unwrap();
486
487 let mut new_state = new_state.update_cells();
488
489 assert_eq!(new_state.basic(account).unwrap().unwrap().code, Some(Bytecode::new_raw(Bytes::from(vec![1, 2, 2]))));
490 assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce + 1);
491 assert_eq!(new_state.storage_ref(account, key0).unwrap(), U256::from(333));
492 assert_eq!(new_state.storage_ref(account, key1).unwrap(), value1);
493 assert_eq!(new_state.storage_ref(account, key2).unwrap(), U256::ZERO);
494 assert_eq!(new_state.storage_ref(account2, key0).unwrap(), U256::ZERO);
495 assert_eq!(new_state.accounts.len(), 1);
496 assert_eq!(new_state.basic(account2).unwrap(), None);
497 assert_eq!(new_state.accounts.len(), 2);
498 assert_eq!(new_state.basic(account2).unwrap(), None);
499 assert_eq!(new_state.accounts.len(), 2);
500 }
501
502 }