Skip to main content

anvil/eth/backend/mem/
in_memory_db.rs

1//! The in memory DB
2
3use 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
28// reexport for convenience
29pub use foundry_evm::backend::MemDb;
30use foundry_evm::backend::RevertStateSnapshotAction;
31
32/// An in-memory database that incrementally maintains Anvil's mined-block state root.
33#[derive(Debug, Default)]
34pub struct StateRootDb {
35    inner: MemDb,
36    state_root: Mutex<StateRootCache>,
37    history: Mutex<HistoricalStateCache>,
38    /// Live cache head used to make sequential block-hash insertion constant-time.
39    block_hash_head: Option<U256>,
40}
41
42impl StateRootDb {
43    /// Creates a new database, optionally tracking the state used by block-history snapshots.
44    ///
45    /// Anvil disables history tracking when state history is pruned, since historical snapshots
46    /// are never taken in that mode and the recorded dirty sets would accumulate without ever
47    /// being drained. With tracking disabled, [`Db::current_state`] still returns a correct,
48    /// freshly built snapshot.
49    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/// Incrementally maintained, structurally shared state used by block-history snapshots.
72#[derive(Debug, Default)]
73struct HistoricalStateCache {
74    state: Option<PersistentStateDb>,
75    dirty: AddressMap<DirtyHistoricalAccount>,
76    /// Disables recording and snapshot caching; set when historical snapshots are never taken.
77    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/// A read-only historical state whose maps are cheap structural-sharing clones.
202#[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    /// Creates a new snapshot
612    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    // Nothing backs a `MemDb`, so its snapshots do not track account states.
651    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    // verifies that all substantial aspects of a loaded account remain the same after an account
690    // is dumped and reloaded
691    #[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        // blocks dumping/loading tested in storage.rs
711        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    // verifies that multiple accounts can be loaded at a time, and storage is merged within those
729    // accounts as well.
730    #[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        // Model the EIP-2935 history contract filling one new ring-buffer slot per block.
803        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        // Initialize the persistent historical-state cache as well as the live EVM cache.
887        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        // An out-of-order insertion within the active window must not discard the current head.
894        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        // `current_state` must still produce a correct snapshot without caching it.
975        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}