1use crate::{
4 eth::backend::db::{
5 BLOCKHASH_HISTORY, Db, MaybeForkedDatabase, MaybeFullDatabase, SerializableAccountRecord,
6 SerializableBlock, SerializableHistoricalStates, SerializableState,
7 SerializableTransaction, StateDb, cache_block_hash,
8 },
9 mem::state::{StateRootCache, state_root},
10};
11use alloy_primitives::{
12 Address, B256, U256,
13 map::{AddressMap, B256Map, HashSet},
14};
15use alloy_rpc_types::BlockId;
16use foundry_evm::backend::{BlockchainDb, DatabaseError, DatabaseResult, StateSnapshot};
17use imbl::HashMap as PersistentMap;
18use parking_lot::Mutex;
19use revm::{
20 Database, DatabaseCommit,
21 bytecode::Bytecode,
22 context::BlockEnv,
23 database::{AccountState, DatabaseRef, DbAccount},
24 state::{Account, AccountInfo},
25};
26use std::sync::OnceLock;
27
28pub use foundry_evm::backend::MemDb;
30use foundry_evm::backend::RevertStateSnapshotAction;
31
32#[derive(Debug, Default)]
34pub struct StateRootDb {
35 inner: MemDb,
36 state_root: Mutex<StateRootCache>,
37 history: Mutex<HistoricalStateCache>,
38 block_hash_head: Option<U256>,
40}
41
42impl StateRootDb {
43 pub fn new(track_history: bool) -> Self {
50 Self {
51 history: Mutex::new(HistoricalStateCache {
52 disabled: !track_history,
53 ..Default::default()
54 }),
55 ..Default::default()
56 }
57 }
58
59 fn normalize_block_hashes(&mut self) {
60 let block_hashes = &mut self.inner.inner.cache.block_hashes;
61 let Some(head) = block_hashes.keys().copied().max() else {
62 self.block_hash_head = None;
63 return;
64 };
65 let min_number = head.saturating_sub(U256::from(BLOCKHASH_HISTORY));
66 block_hashes.retain(|cached, _| *cached >= min_number && *cached <= head);
67 self.block_hash_head = Some(head);
68 }
69}
70
71#[derive(Debug, Default)]
73struct HistoricalStateCache {
74 state: Option<PersistentStateDb>,
75 dirty: AddressMap<DirtyHistoricalAccount>,
76 disabled: bool,
78}
79
80#[derive(Debug, Default)]
81struct DirtyHistoricalAccount {
82 storage: HashSet<U256>,
83 reset_storage: bool,
84}
85
86impl HistoricalStateCache {
87 fn record_changes(&mut self, changes: &AddressMap<Account>) {
88 if self.disabled {
89 return;
90 }
91 for (address, account) in changes {
92 if !account.is_touched() {
93 continue;
94 }
95
96 let dirty = self.dirty.entry(*address).or_default();
97 dirty.reset_storage |= account.is_created() || account.is_selfdestructed();
98 dirty.storage.extend(account.changed_storage_slots().map(|(slot, _)| *slot));
99 }
100 }
101
102 fn record_account(&mut self, address: Address) {
103 if self.disabled {
104 return;
105 }
106 self.dirty.entry(address).or_default();
107 }
108
109 fn record_storage(&mut self, address: Address, slot: U256) {
110 if self.disabled {
111 return;
112 }
113 self.dirty.entry(address).or_default().storage.insert(slot);
114 }
115
116 fn record_block_hash(&mut self, number: U256, hash: B256, is_next: bool) {
117 if self.disabled {
118 return;
119 }
120 let Some(state) = &mut self.state else { return };
121 if is_next {
122 let min_number = number.saturating_sub(U256::from(BLOCKHASH_HISTORY));
123 if min_number > U256::ZERO {
124 state.block_hashes.remove(&(min_number - U256::ONE));
125 }
126 state.block_hashes.insert(number, hash);
127 return;
128 }
129
130 let head = state.block_hashes.keys().copied().max().map_or(number, |head| head.max(number));
131 let min_number = head.saturating_sub(U256::from(BLOCKHASH_HISTORY));
132 state.block_hashes.retain(|cached, _| *cached >= min_number && *cached <= head);
133 if number >= min_number {
134 state.block_hashes.insert(number, hash);
135 }
136 }
137
138 fn invalidate(&mut self) {
139 self.state = None;
140 self.dirty.clear();
141 }
142
143 fn snapshot(&mut self, db: &MemDb) -> PersistentStateDb {
144 if self.disabled {
145 return PersistentStateDb::from_mem_db(db);
146 }
147 let Some(state) = &mut self.state else {
148 let state = PersistentStateDb::from_mem_db(db);
149 self.state = Some(state.clone());
150 self.dirty.clear();
151 return state;
152 };
153
154 for (address, dirty) in std::mem::take(&mut self.dirty) {
155 let Some(account) = db.inner.cache.accounts.get(&address) else {
156 state.accounts.remove(&address);
157 continue;
158 };
159
160 let mut storage = if dirty.reset_storage {
161 account.storage.iter().map(|(slot, value)| (*slot, *value)).collect()
162 } else {
163 state
164 .accounts
165 .get(&address)
166 .map(|account| account.storage.clone())
167 .unwrap_or_default()
168 };
169 if !dirty.reset_storage {
170 for slot in dirty.storage {
171 if let Some(value) = account.storage.get(&slot) {
172 storage.insert(slot, *value);
173 } else {
174 storage.remove(&slot);
175 }
176 }
177 }
178
179 let info = account_info_with_code(&account.info, &db.inner.cache.contracts);
180 if let Some(code) = &info.code {
181 state.contracts.insert(info.code_hash(), code.clone());
182 }
183 state.accounts.insert(
184 address,
185 PersistentAccount { info, account_state: account.account_state.clone(), storage },
186 );
187 }
188
189 state.full = OnceLock::new();
190 state.clone()
191 }
192}
193
194#[derive(Clone, Debug, Default)]
195struct PersistentAccount {
196 info: AccountInfo,
197 account_state: AccountState,
198 storage: PersistentMap<U256, U256>,
199}
200
201#[derive(Clone, Debug, Default)]
203struct PersistentStateDb {
204 accounts: PersistentMap<Address, PersistentAccount>,
205 contracts: PersistentMap<B256, Bytecode>,
206 block_hashes: PersistentMap<U256, B256>,
207 #[allow(clippy::type_complexity)]
208 full: OnceLock<AddressMap<DbAccount>>,
209}
210
211impl PersistentStateDb {
212 fn from_mem_db(db: &MemDb) -> Self {
213 let contracts = db
214 .inner
215 .cache
216 .contracts
217 .iter()
218 .map(|(hash, code)| (*hash, code.clone()))
219 .collect::<PersistentMap<_, _>>();
220 let accounts = db
221 .inner
222 .cache
223 .accounts
224 .iter()
225 .map(|(address, account)| {
226 (
227 *address,
228 PersistentAccount {
229 info: account_info_with_code(&account.info, &db.inner.cache.contracts),
230 account_state: account.account_state.clone(),
231 storage: account
232 .storage
233 .iter()
234 .map(|(slot, value)| (*slot, *value))
235 .collect(),
236 },
237 )
238 })
239 .collect();
240 let block_hashes =
241 db.inner.cache.block_hashes.iter().map(|(number, hash)| (*number, *hash)).collect();
242 Self { accounts, contracts, block_hashes, full: OnceLock::new() }
243 }
244
245 fn state_snapshot(&self) -> StateSnapshot {
246 StateSnapshot {
247 accounts: self
248 .accounts
249 .iter()
250 .filter(|(_, account)| account.account_state != AccountState::NotExisting)
251 .map(|(address, account)| (*address, account.info.clone()))
252 .collect(),
253 storage: self
254 .accounts
255 .iter()
256 .filter(|(_, account)| account.account_state != AccountState::NotExisting)
257 .map(|(address, account)| {
258 (
259 *address,
260 account.storage.iter().map(|(slot, value)| (*slot, *value)).collect(),
261 )
262 })
263 .collect(),
264 block_hashes: self.block_hashes.iter().map(|(number, hash)| (*number, *hash)).collect(),
265 ..Default::default()
266 }
267 }
268
269 fn full_db(&self) -> AddressMap<DbAccount> {
270 self.accounts
271 .iter()
272 .filter(|(_, account)| account.account_state != AccountState::NotExisting)
273 .map(|(address, account)| {
274 (
275 *address,
276 DbAccount {
277 info: account.info.clone(),
278 account_state: account.account_state.clone(),
279 storage: account
280 .storage
281 .iter()
282 .map(|(slot, value)| (*slot, *value))
283 .collect(),
284 },
285 )
286 })
287 .collect()
288 }
289}
290
291fn account_info_with_code(info: &AccountInfo, contracts: &B256Map<Bytecode>) -> AccountInfo {
292 let mut info = info.clone();
293 if info.code.is_none() {
294 info.code = contracts.get(&info.code_hash()).cloned();
295 }
296 info
297}
298
299impl DatabaseRef for PersistentStateDb {
300 type Error = DatabaseError;
301
302 fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {
303 Ok(match self.accounts.get(&address) {
304 Some(account) if account.account_state == AccountState::NotExisting => None,
305 Some(account) => Some(account.info.clone()),
306 None => Some(AccountInfo::default()),
307 })
308 }
309
310 fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {
311 Ok(self.contracts.get(&code_hash).cloned().unwrap_or_default())
312 }
313
314 fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
315 Ok(self
316 .accounts
317 .get(&address)
318 .and_then(|account| account.storage.get(&index).copied())
319 .unwrap_or_default())
320 }
321
322 fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {
323 Ok(self.block_hashes.get(&U256::from(number)).copied().unwrap_or_default())
324 }
325}
326
327impl MaybeFullDatabase for PersistentStateDb {
328 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
329 Some(self.full.get_or_init(|| self.full_db()))
330 }
331
332 fn is_persistent(&self) -> bool {
333 true
334 }
335
336 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
337 let snapshot = self.state_snapshot();
338 self.clear();
339 snapshot
340 }
341
342 fn read_as_state_snapshot(&self) -> StateSnapshot {
343 self.state_snapshot()
344 }
345
346 fn clear(&mut self) {
347 *self = Self::default();
348 }
349
350 fn init_from_state_snapshot(&mut self, snapshot: StateSnapshot) {
351 let StateSnapshot { accounts, mut storage, block_hashes, .. } = snapshot;
352 let mut contracts = PersistentMap::new();
353 let accounts = accounts
354 .into_iter()
355 .map(|(address, info)| {
356 if let Some(code) = &info.code {
357 contracts.insert(info.code_hash(), code.clone());
358 }
359 let storage = storage
360 .remove(&address)
361 .unwrap_or_default()
362 .into_iter()
363 .collect::<PersistentMap<_, _>>();
364 (address, PersistentAccount { info, account_state: AccountState::None, storage })
365 })
366 .collect();
367 let block_hashes = block_hashes.into_iter().collect();
368 *self = Self { accounts, contracts, block_hashes, full: OnceLock::new() };
369 }
370}
371
372impl DatabaseRef for StateRootDb {
373 type Error = DatabaseError;
374
375 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
376 self.inner.basic_ref(address)
377 }
378
379 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
380 self.inner.code_by_hash_ref(code_hash)
381 }
382
383 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
384 self.inner.storage_ref(address, index)
385 }
386
387 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
388 self.inner.block_hash_ref(number)
389 }
390}
391
392impl Database for StateRootDb {
393 type Error = DatabaseError;
394
395 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
396 self.state_root.get_mut().record_account(address);
397 self.history.get_mut().record_account(address);
398 self.inner.basic(address)
399 }
400
401 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
402 self.inner.code_by_hash(code_hash)
403 }
404
405 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
406 self.state_root.get_mut().record_storage(address, index);
407 self.history.get_mut().record_storage(address, index);
408 self.inner.storage(address, index)
409 }
410
411 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
412 self.inner.block_hash(number)
413 }
414}
415
416impl DatabaseCommit for StateRootDb {
417 fn commit(&mut self, changes: revm::state::EvmState) {
418 self.state_root.get_mut().record_changes(&changes);
419 self.history.get_mut().record_changes(&changes);
420 self.inner.commit(changes);
421 }
422}
423
424impl Db for StateRootDb {
425 fn insert_account(&mut self, address: Address, account: AccountInfo) {
426 self.state_root.get_mut().record_account(address);
427 self.history.get_mut().record_account(address);
428 Db::insert_account(&mut self.inner, address, account);
429 }
430
431 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
432 let storage_slot = slot.into();
433 self.state_root.get_mut().record_storage(address, storage_slot);
434 self.history.get_mut().record_storage(address, storage_slot);
435 Db::set_storage_at(&mut self.inner, address, slot, val)
436 }
437
438 fn insert_block_hash(&mut self, number: U256, hash: B256) {
439 let is_next =
440 self.block_hash_head.is_some_and(|head| number == head.saturating_add(U256::ONE));
441 if is_next {
442 let min_number = number.saturating_sub(U256::from(BLOCKHASH_HISTORY));
443 if min_number > U256::ZERO {
444 self.inner.inner.cache.block_hashes.remove(&(min_number - U256::ONE));
445 }
446 self.inner.inner.cache.block_hashes.insert(number, hash);
447 self.block_hash_head = Some(number);
448 } else {
449 self.block_hash_head =
450 Some(cache_block_hash(&mut self.inner.inner.cache.block_hashes, number, hash));
451 }
452 self.history.get_mut().record_block_hash(number, hash, is_next);
453 }
454
455 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>) {
456 Db::set_block_hashes(&mut self.inner, block_hashes);
457 self.normalize_block_hashes();
458 self.history.get_mut().invalidate();
459 }
460
461 fn dump_state(
462 &self,
463 at: BlockEnv,
464 best_number: u64,
465 blocks: Vec<SerializableBlock>,
466 transactions: Vec<SerializableTransaction>,
467 historical_states: Option<SerializableHistoricalStates>,
468 ) -> DatabaseResult<Option<SerializableState>> {
469 Db::dump_state(&self.inner, at, best_number, blocks, transactions, historical_states)
470 }
471
472 fn snapshot_state(&mut self) -> U256 {
473 Db::snapshot_state(&mut self.inner)
474 }
475
476 fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {
477 let reverted = Db::revert_state(&mut self.inner, id, action);
478 if reverted {
479 self.state_root.get_mut().invalidate();
480 self.history.get_mut().invalidate();
481 self.block_hash_head = self.inner.inner.cache.block_hashes.keys().copied().max();
482 }
483 reverted
484 }
485
486 fn delete_state_snapshot(&mut self, id: U256) -> bool {
487 Db::delete_state_snapshot(&mut self.inner, id)
488 }
489
490 fn maybe_state_root(&self) -> Option<B256> {
491 Some(self.state_root.lock().root(&self.inner.inner.cache.accounts))
492 }
493
494 fn current_state(&self) -> StateDb {
495 StateDb::new(self.history.lock().snapshot(&self.inner))
496 }
497}
498
499impl MaybeFullDatabase for StateRootDb {
500 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
501 MaybeFullDatabase::maybe_as_full_db(&self.inner)
502 }
503
504 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
505 MaybeFullDatabase::maybe_full_db(&self.inner)
506 }
507
508 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
509 self.state_root.get_mut().invalidate();
510 self.history.get_mut().invalidate();
511 self.block_hash_head = None;
512 MaybeFullDatabase::clear_into_state_snapshot(&mut self.inner)
513 }
514
515 fn read_as_state_snapshot(&self) -> StateSnapshot {
516 MaybeFullDatabase::read_as_state_snapshot(&self.inner)
517 }
518
519 fn clear(&mut self) {
520 self.state_root.get_mut().invalidate();
521 self.history.get_mut().invalidate();
522 self.block_hash_head = None;
523 MaybeFullDatabase::clear(&mut self.inner)
524 }
525
526 fn init_from_state_snapshot(&mut self, snapshot: StateSnapshot) {
527 MaybeFullDatabase::init_from_state_snapshot(&mut self.inner, snapshot);
528 self.state_root.get_mut().invalidate();
529 self.history.get_mut().invalidate();
530 self.normalize_block_hashes();
531 }
532}
533
534impl MaybeForkedDatabase for StateRootDb {
535 fn maybe_reset(&mut self, urls: Vec<String>, block_number: BlockId) -> Result<(), String> {
536 self.inner.maybe_reset(urls, block_number)
537 }
538
539 fn maybe_flush_cache(&self) -> Result<(), String> {
540 self.inner.maybe_flush_cache()
541 }
542
543 fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
544 self.inner.maybe_inner()
545 }
546}
547
548impl Db for MemDb {
549 fn insert_account(&mut self, address: Address, account: AccountInfo) {
550 self.inner.insert_account_info(address, account)
551 }
552
553 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
554 self.inner.insert_account_storage(address, slot.into(), val.into())
555 }
556
557 fn insert_block_hash(&mut self, number: U256, hash: B256) {
558 cache_block_hash(&mut self.inner.cache.block_hashes, number, hash);
559 }
560
561 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>) {
562 self.inner.cache.block_hashes = block_hashes.into_iter().collect();
563 }
564
565 fn dump_state(
566 &self,
567 at: BlockEnv,
568 best_number: u64,
569 blocks: Vec<SerializableBlock>,
570 transactions: Vec<SerializableTransaction>,
571 historical_states: Option<SerializableHistoricalStates>,
572 ) -> DatabaseResult<Option<SerializableState>> {
573 let accounts = self
574 .inner
575 .cache
576 .accounts
577 .clone()
578 .into_iter()
579 .map(|(k, v)| -> DatabaseResult<_> {
580 let code = if let Some(code) = v.info.code {
581 code
582 } else {
583 self.inner.code_by_hash_ref(v.info.code_hash())?
584 };
585 Ok((
586 k,
587 SerializableAccountRecord {
588 nonce: v.info.nonce,
589 balance: v.info.balance,
590 code: code.original_bytes(),
591 storage: v.storage.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),
592 },
593 ))
594 })
595 .collect::<Result<_, _>>()?;
596
597 Ok(Some(SerializableState {
598 block: Some(at),
599 accounts,
600 best_block_number: Some(best_number),
601 blocks,
602 transactions,
603 #[cfg(feature = "monad")]
604 monad_block_participants: Default::default(),
605 #[cfg(feature = "monad")]
606 monad_block_replay_profiles: Default::default(),
607 historical_states,
608 }))
609 }
610
611 fn snapshot_state(&mut self) -> U256 {
613 let id = self.state_snapshots.insert(self.inner.clone());
614 trace!(target: "backend::memdb", "Created new state snapshot {}", id);
615 id
616 }
617
618 fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {
619 if let Some(state_snapshot) = self.state_snapshots.remove(id) {
620 if action.is_keep() {
621 self.state_snapshots.insert_at(state_snapshot.clone(), id);
622 }
623 self.inner = state_snapshot;
624 trace!(target: "backend::memdb", "Reverted state snapshot {}", id);
625 true
626 } else {
627 warn!(target: "backend::memdb", "No state snapshot to revert for {}", id);
628 false
629 }
630 }
631
632 fn delete_state_snapshot(&mut self, id: U256) -> bool {
633 self.state_snapshots.remove_at(id).is_some()
634 }
635
636 fn maybe_state_root(&self) -> Option<B256> {
637 Some(state_root(&self.inner.cache.accounts))
638 }
639
640 fn current_state(&self) -> StateDb {
641 StateDb::new(Self { inner: self.inner.clone(), ..Default::default() })
642 }
643}
644
645impl MaybeFullDatabase for MemDb {
646 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
647 Some(&self.inner.cache.accounts)
648 }
649
650 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
652 StateSnapshot { account_states: None, ..self.inner.clear_into_state_snapshot() }
653 }
654
655 fn read_as_state_snapshot(&self) -> StateSnapshot {
656 StateSnapshot { account_states: None, ..self.inner.read_as_state_snapshot() }
657 }
658
659 fn clear(&mut self) {
660 self.inner.clear();
661 }
662
663 fn init_from_state_snapshot(&mut self, snapshot: StateSnapshot) {
664 self.inner.init_from_state_snapshot(snapshot)
665 }
666}
667
668impl MaybeForkedDatabase for MemDb {
669 fn maybe_reset(&mut self, _urls: Vec<String>, _block_number: BlockId) -> Result<(), String> {
670 Err("not supported".to_string())
671 }
672
673 fn maybe_flush_cache(&self) -> Result<(), String> {
674 Err("not supported".to_string())
675 }
676
677 fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
678 Err("not supported".to_string())
679 }
680}
681
682#[cfg(test)]
683mod tests {
684 use super::*;
685 use alloy_primitives::{Bytes, address};
686 use revm::primitives::KECCAK_EMPTY;
687 use std::collections::BTreeMap;
688
689 #[test]
692 fn test_dump_reload_cycle() {
693 let test_addr: Address = address!("0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266");
694
695 let mut dump_db = MemDb::default();
696
697 let contract_code = Bytecode::new_raw(Bytes::from("fake contract code"));
698 dump_db.insert_account(
699 test_addr,
700 AccountInfo {
701 balance: U256::from(123456),
702 code_hash: KECCAK_EMPTY,
703 code: Some(contract_code.clone()),
704 nonce: 1234,
705 account_id: None,
706 },
707 );
708 dump_db.set_storage_at(test_addr, U256::from(1234567).into(), U256::ONE.into()).unwrap();
709
710 let state = dump_db
712 .dump_state(Default::default(), 0, Vec::new(), Vec::new(), Default::default())
713 .unwrap()
714 .unwrap();
715
716 let mut load_db = MemDb::default();
717
718 load_db.load_state(state).unwrap();
719
720 let loaded_account = load_db.basic_ref(test_addr).unwrap().unwrap();
721
722 assert_eq!(loaded_account.balance, U256::from(123456));
723 assert_eq!(load_db.code_by_hash_ref(loaded_account.code_hash()).unwrap(), contract_code);
724 assert_eq!(loaded_account.nonce, 1234);
725 assert_eq!(load_db.storage_ref(test_addr, U256::from(1234567)).unwrap(), U256::ONE);
726 }
727
728 #[test]
731 fn test_load_state_merge() {
732 let test_addr: Address = address!("0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266");
733 let test_addr2: Address = address!("0x70997970c51812dc3a010c7d01b50e0d17dc79c8");
734
735 let contract_code = Bytecode::new_raw(Bytes::from("fake contract code"));
736
737 let mut db = MemDb::default();
738
739 db.insert_account(
740 test_addr,
741 AccountInfo {
742 balance: U256::from(123456),
743 code_hash: KECCAK_EMPTY,
744 code: Some(contract_code.clone()),
745 nonce: 1234,
746 account_id: None,
747 },
748 );
749
750 db.set_storage_at(test_addr, U256::from(1234567).into(), U256::ONE.into()).unwrap();
751 db.set_storage_at(test_addr, U256::from(1234568).into(), U256::from(2).into()).unwrap();
752
753 let mut new_state = SerializableState::default();
754
755 new_state.accounts.insert(
756 test_addr2,
757 SerializableAccountRecord {
758 balance: Default::default(),
759 code: Default::default(),
760 nonce: 1,
761 storage: Default::default(),
762 },
763 );
764
765 let mut new_storage = BTreeMap::default();
766 new_storage.insert(U256::from(1234568).into(), U256::from(5).into());
767
768 new_state.accounts.insert(
769 test_addr,
770 SerializableAccountRecord {
771 balance: U256::from(100100),
772 code: contract_code.original_bytes(),
773 nonce: 100,
774 storage: new_storage,
775 },
776 );
777
778 db.load_state(new_state).unwrap();
779
780 let loaded_account = db.basic_ref(test_addr).unwrap().unwrap();
781 let loaded_account2 = db.basic_ref(test_addr2).unwrap().unwrap();
782
783 assert_eq!(loaded_account2.nonce, 1);
784
785 assert_eq!(loaded_account.balance, U256::from(100100));
786 assert_eq!(db.code_by_hash_ref(loaded_account.code_hash()).unwrap(), contract_code);
787 assert_eq!(loaded_account.nonce, 1234);
788 assert_eq!(db.storage_ref(test_addr, U256::from(1234567)).unwrap(), U256::ONE);
789 assert_eq!(db.storage_ref(test_addr, U256::from(1234568)).unwrap(), U256::from(5));
790 }
791
792 #[test]
793 fn incremental_state_root_matches_full_rebuild() {
794 let address = address!("0000000000000000000000000000000000002935");
795 let deleted = Address::with_last_byte(1);
796 let mut db = StateRootDb::default();
797 db.insert_account(address, AccountInfo::default());
798 db.insert_account(deleted, AccountInfo::from_balance(U256::ONE));
799
800 assert_eq!(db.maybe_state_root(), Some(state_root(&db.inner.inner.cache.accounts)));
801
802 for slot in 0..1_024 {
804 db.set_storage_at(address, U256::from(slot).into(), B256::from(U256::from(slot + 1)))
805 .unwrap();
806 let _ = db.maybe_state_root().unwrap();
807 }
808
809 db.set_balance(address, U256::from(42)).unwrap();
810 db.set_storage_at(address, U256::from(7).into(), B256::ZERO).unwrap();
811 db.set_storage_at(address, U256::from(8).into(), B256::from(U256::from(2_048))).unwrap();
812 db.inner.inner.cache.accounts.get_mut(&deleted).unwrap().account_state =
813 AccountState::NotExisting;
814 db.state_root.get_mut().record_account(deleted);
815 assert_eq!(db.maybe_state_root(), Some(state_root(&db.inner.inner.cache.accounts)));
816
817 let snapshot = db.snapshot_state();
818 db.set_balance(address, U256::from(43)).unwrap();
819 assert!(db.revert_state(snapshot, RevertStateSnapshotAction::RevertRemove));
820 assert_eq!(db.maybe_state_root(), Some(state_root(&db.inner.inner.cache.accounts)));
821 }
822
823 #[test]
824 fn evm_block_hash_cache_is_bounded() {
825 let mut db = StateRootDb::default();
826 for number in 0..1_024 {
827 db.insert_block_hash(U256::from(number), B256::from(U256::from(number)));
828 }
829
830 let block_hashes = &db.inner.inner.cache.block_hashes;
831 assert_eq!(block_hashes.len(), BLOCKHASH_HISTORY as usize + 1);
832 assert!(!block_hashes.contains_key(&U256::from(766)));
833 assert!(block_hashes.contains_key(&U256::from(767)));
834 assert!(block_hashes.contains_key(&U256::from(768)));
835 assert!(block_hashes.contains_key(&U256::from(1_023)));
836
837 let snapshot = db.snapshot_state();
838 db.insert_block_hash(U256::from(1_024), B256::from(U256::from(1_024)));
839 assert!(db.revert_state(snapshot, RevertStateSnapshotAction::RevertRemove));
840 db.insert_block_hash(U256::from(1_024), B256::from(U256::from(1_024)));
841
842 let block_hashes = &db.inner.inner.cache.block_hashes;
843 assert_eq!(block_hashes.len(), BLOCKHASH_HISTORY as usize + 1);
844 assert!(!block_hashes.contains_key(&U256::from(767)));
845 assert!(block_hashes.contains_key(&U256::from(768)));
846 assert!(block_hashes.contains_key(&U256::from(1_024)));
847 }
848
849 #[test]
850 fn oversized_seeded_block_hash_caches_are_normalized() {
851 let block_hashes = (0..=1_000)
852 .map(|number| (U256::from(number), B256::from(U256::from(number))))
853 .collect::<Vec<_>>();
854
855 let mut db = StateRootDb::default();
856 db.set_block_hashes(block_hashes.clone());
857 assert_block_hash_window(&db, 744, 1_000);
858 db.insert_block_hash(U256::from(1_001), B256::from(U256::from(1_001)));
859 assert_block_hash_window(&db, 745, 1_001);
860
861 let mut snapshot_source = MemDb::default();
862 snapshot_source.set_block_hashes(block_hashes);
863 let snapshot = snapshot_source.read_as_state_snapshot();
864 let mut restored = StateRootDb::default();
865 restored.init_from_state_snapshot(snapshot);
866 assert_block_hash_window(&restored, 744, 1_000);
867 restored.insert_block_hash(U256::from(1_001), B256::from(U256::from(1_001)));
868 assert_block_hash_window(&restored, 745, 1_001);
869 }
870
871 fn assert_block_hash_window(db: &StateRootDb, min: u64, head: u64) {
872 let block_hashes = &db.inner.inner.cache.block_hashes;
873 assert_eq!(block_hashes.len(), BLOCKHASH_HISTORY as usize + 1);
874 assert!(
875 block_hashes
876 .keys()
877 .all(|number| *number >= U256::from(min) && *number <= U256::from(head))
878 );
879 assert!(block_hashes.contains_key(&U256::from(min)));
880 assert!(block_hashes.contains_key(&U256::from(head)));
881 }
882
883 #[test]
884 fn evm_block_hash_cache_is_bounded_across_block_number_jumps() {
885 let mut db = StateRootDb::default();
886 db.current_state();
888
889 for number in [0, 516, 400] {
890 db.insert_block_hash(U256::from(number), B256::from(U256::from(number)));
891 }
892
893 let block_hashes = &db.inner.inner.cache.block_hashes;
895 assert_eq!(block_hashes.len(), 2);
896 assert!(block_hashes.contains_key(&U256::from(400)));
897 assert!(block_hashes.contains_key(&U256::from(516)));
898
899 db.insert_block_hash(U256::from(774), B256::from(U256::from(774)));
900
901 let block_hashes = &db.inner.inner.cache.block_hashes;
902 assert_eq!(block_hashes.len(), 1);
903 assert!(block_hashes.contains_key(&U256::from(774)));
904
905 let historical = db.history.get_mut().state.as_ref().unwrap();
906 assert_eq!(historical.block_hashes.len(), 1);
907 assert!(historical.block_hashes.contains_key(&U256::from(774)));
908 }
909
910 #[test]
911 fn historical_states_are_persistent_and_isolated() {
912 let address = address!("0000000000000000000000000000000000002935");
913 let slot = U256::ONE;
914 let mut db = StateRootDb::default();
915 db.insert_account(address, AccountInfo::from_balance(U256::ONE));
916
917 let first = db.current_state();
918 assert!(first.is_persistent());
919
920 db.set_balance(address, U256::from(2)).unwrap();
921 db.set_storage_at(address, slot.into(), B256::with_last_byte(3)).unwrap();
922 let second = db.current_state();
923
924 assert_eq!(first.basic_ref(address).unwrap().unwrap().balance, U256::ONE);
925 assert_eq!(first.storage_ref(address, slot).unwrap(), U256::ZERO);
926 assert_eq!(second.basic_ref(address).unwrap().unwrap().balance, U256::from(2));
927 assert_eq!(second.storage_ref(address, slot).unwrap(), U256::from(3));
928 }
929
930 #[test]
931 fn historical_missing_accounts_match_live_state() {
932 let missing = Address::with_last_byte(1);
933 let deleted = Address::with_last_byte(2);
934 let mut db = StateRootDb::default();
935 let historical = db.current_state();
936
937 let live_account = db.basic_ref(missing).unwrap();
938 assert_eq!(live_account, Some(AccountInfo::default()));
939 assert_eq!(historical.basic_ref(missing).unwrap(), live_account);
940
941 db.insert_account(deleted, AccountInfo::from_balance(U256::ONE));
942 db.inner.inner.cache.accounts.get_mut(&deleted).unwrap().account_state =
943 AccountState::NotExisting;
944 db.history.get_mut().record_account(deleted);
945 let historical = db.current_state();
946 assert_eq!(historical.basic_ref(deleted).unwrap(), None);
947 assert!(!historical.maybe_as_full_db().unwrap().contains_key(&deleted));
948 assert!(!historical.read_as_state_snapshot().accounts.contains_key(&deleted));
949
950 let mut fresh = StateRootDb::default();
951 fresh.insert_account(deleted, AccountInfo::from_balance(U256::ONE));
952 fresh.inner.inner.cache.accounts.get_mut(&deleted).unwrap().account_state =
953 AccountState::NotExisting;
954 let historical = fresh.current_state();
955 assert_eq!(historical.basic_ref(deleted).unwrap(), None);
956 assert!(!historical.maybe_as_full_db().unwrap().contains_key(&deleted));
957 }
958
959 #[test]
960 fn disabled_history_tracking_records_nothing() {
961 let address = address!("0000000000000000000000000000000000002935");
962 let slot = U256::ONE;
963 let mut db = StateRootDb::new(false);
964
965 db.insert_account(address, AccountInfo::from_balance(U256::ONE));
966 db.set_storage_at(address, slot.into(), B256::with_last_byte(2)).unwrap();
967 db.basic(address).unwrap();
968 db.storage(address, slot).unwrap();
969 db.maybe_state_root().unwrap();
970
971 assert!(db.history.get_mut().dirty.is_empty());
972 assert!(db.history.get_mut().state.is_none());
973
974 let historical = db.current_state();
976 assert_eq!(historical.basic_ref(address).unwrap().unwrap().balance, U256::ONE);
977 assert_eq!(historical.storage_ref(address, slot).unwrap(), U256::from(2));
978 assert!(db.history.get_mut().state.is_none());
979 }
980}