Skip to main content

revm_database/
in_memory_db.rs

1use core::convert::Infallible;
2use database_interface::{
3    Database, DatabaseCommit, DatabaseRef, EmptyDB, BENCH_CALLER, BENCH_CALLER_BALANCE,
4    BENCH_TARGET, BENCH_TARGET_BALANCE,
5};
6use primitives::{
7    hash_map::Entry, Address, AddressMap, B256Map, HashMap, Log, StorageKey, StorageKeyMap,
8    StorageValue, U256Map, B256, KECCAK_EMPTY, U256,
9};
10use state::{Account, AccountInfo, Bytecode};
11use std::vec::Vec;
12
13/// A [Database] implementation that stores all state changes in memory.
14pub type InMemoryDB = CacheDB<EmptyDB>;
15
16/// A cache used in [CacheDB]. Its kept separate so it can be used independently.
17///
18/// Accounts and code are stored in two separate maps, the `accounts` map maps addresses to [DbAccount],
19/// whereas contracts are identified by their code hash, and are stored in the `contracts` map.
20/// The [DbAccount] holds the code hash of the contract, which is used to look up the contract in the `contracts` map.
21#[derive(Debug, Clone)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Cache {
24    /// Account info where None means it is not existing. Not existing state is needed for Pre TANGERINE forks.
25    /// `code` is always `None`, and bytecode can be found in `contracts`.
26    pub accounts: AddressMap<DbAccount>,
27    /// Tracks all contracts by their code hash.
28    pub contracts: B256Map<Bytecode>,
29    /// All logs that were committed via [DatabaseCommit::commit].
30    pub logs: Vec<Log>,
31    /// All cached block hashes from the [DatabaseRef].
32    pub block_hashes: U256Map<B256>,
33}
34
35impl Default for Cache {
36    fn default() -> Self {
37        let mut contracts = HashMap::default();
38        contracts.insert(KECCAK_EMPTY, Bytecode::default());
39        contracts.insert(B256::ZERO, Bytecode::default());
40
41        Cache {
42            accounts: HashMap::default(),
43            contracts,
44            logs: Vec::default(),
45            block_hashes: HashMap::default(),
46        }
47    }
48}
49
50/// A [Database] implementation that stores all state changes in memory.
51///
52/// This implementation wraps a [DatabaseRef] that is used to load data ([AccountInfo]).
53#[derive(Debug, Clone)]
54#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
55pub struct CacheDB<ExtDB> {
56    /// The cache that stores all state changes.
57    pub cache: Cache,
58    /// The underlying database ([DatabaseRef]) that is used to load data.
59    ///
60    /// Note: This is read-only, data is never written to this database.
61    pub db: ExtDB,
62}
63
64impl<ExtDB: Default> Default for CacheDB<ExtDB> {
65    fn default() -> Self {
66        Self::new(ExtDB::default())
67    }
68}
69
70impl<ExtDb> CacheDB<CacheDB<ExtDb>> {
71    /// Flattens a nested cache by applying the outer cache to the inner cache.
72    ///
73    /// The behavior is as follows:
74    /// - Accounts are overridden with outer accounts
75    /// - Contracts are overridden with outer contracts
76    /// - Logs are appended
77    /// - Block hashes are overridden with outer block hashes
78    pub fn flatten(self) -> CacheDB<ExtDb> {
79        let CacheDB {
80            cache:
81                Cache {
82                    accounts,
83                    contracts,
84                    logs,
85                    block_hashes,
86                },
87            db: mut inner,
88            ..
89        } = self;
90
91        inner.cache.accounts.extend(accounts);
92        inner.cache.contracts.extend(contracts);
93        inner.cache.logs.extend(logs);
94        inner.cache.block_hashes.extend(block_hashes);
95        inner
96    }
97
98    /// Discards the outer cache and return the inner cache.
99    pub fn discard_outer(self) -> CacheDB<ExtDb> {
100        self.db
101    }
102}
103
104impl<ExtDB> CacheDB<ExtDB> {
105    /// Creates a new cache with the given external database.
106    pub fn new(db: ExtDB) -> Self {
107        Self {
108            cache: Cache::default(),
109            db,
110        }
111    }
112
113    /// Inserts the account's code into the cache.
114    ///
115    /// Accounts objects and code are stored separately in the cache, this will take the code from the account and instead map it to the code hash.
116    ///
117    /// Note: This will not insert into the underlying external database.
118    pub fn insert_contract(&mut self, account: &mut AccountInfo) {
119        if let Some(code) = &account.code {
120            if !code.is_empty() {
121                if account.code_hash == KECCAK_EMPTY {
122                    account.code_hash = code.hash_slow();
123                }
124                self.cache
125                    .contracts
126                    .entry(account.code_hash)
127                    .or_insert_with(|| code.clone());
128            }
129        }
130        if account.code_hash.is_zero() {
131            account.code_hash = KECCAK_EMPTY;
132        }
133    }
134
135    /// Inserts account info but not override storage
136    pub fn insert_account_info(&mut self, address: Address, mut info: AccountInfo) {
137        self.insert_contract(&mut info);
138        let account_entry = self.cache.accounts.entry(address).or_default();
139        account_entry.update_info(info);
140        if account_entry.account_state == AccountState::NotExisting {
141            account_entry.update_account_state(AccountState::None);
142        }
143    }
144
145    fn commit_account(&mut self, address: Address, mut account: Account) {
146        if !account.is_touched() {
147            return;
148        }
149        if account.is_selfdestructed() {
150            let db_account = self.cache.accounts.entry(address).or_default();
151            db_account.storage.clear();
152            db_account.account_state = AccountState::NotExisting;
153            db_account.info = AccountInfo::default();
154            return;
155        }
156        let is_newly_created = account.is_created();
157        self.insert_contract(&mut account.info);
158
159        let db_account = self.cache.accounts.entry(address).or_default();
160        db_account.info = account.info;
161
162        db_account.account_state = if is_newly_created {
163            db_account.storage.clear();
164            AccountState::StorageCleared
165        } else if db_account.account_state.is_storage_cleared() {
166            // Preserve old account state if it already exists
167            AccountState::StorageCleared
168        } else {
169            AccountState::Touched
170        };
171        db_account.storage.extend(
172            account
173                .storage
174                .into_iter()
175                .map(|(key, value)| (key, value.present_value())),
176        );
177    }
178
179    /// Wraps the cache in a [CacheDB], creating a nested cache.
180    pub fn nest(self) -> CacheDB<Self> {
181        CacheDB::new(self)
182    }
183}
184
185impl<ExtDB: DatabaseRef> CacheDB<ExtDB> {
186    /// Returns the account for the given address.
187    ///
188    /// If the account was not found in the cache, it will be loaded from the underlying database.
189    pub fn load_account(&mut self, address: Address) -> Result<&mut DbAccount, ExtDB::Error> {
190        let db = &self.db;
191        match self.cache.accounts.entry(address) {
192            Entry::Occupied(entry) => Ok(entry.into_mut()),
193            Entry::Vacant(entry) => Ok(entry.insert(
194                db.basic_ref(address)?
195                    .map(|info| DbAccount {
196                        info,
197                        ..Default::default()
198                    })
199                    .unwrap_or_else(DbAccount::new_not_existing),
200            )),
201        }
202    }
203
204    /// Inserts account storage without overriding account info
205    pub fn insert_account_storage(
206        &mut self,
207        address: Address,
208        slot: StorageKey,
209        value: StorageValue,
210    ) -> Result<(), ExtDB::Error> {
211        let account = self.load_account(address)?;
212        account.storage.insert(slot, value);
213        Ok(())
214    }
215
216    /// Replaces account storage without overriding account info
217    pub fn replace_account_storage(
218        &mut self,
219        address: Address,
220        storage: StorageKeyMap<StorageValue>,
221    ) -> Result<(), ExtDB::Error> {
222        let account = self.load_account(address)?;
223        account.account_state = AccountState::StorageCleared;
224        account.storage = storage.into_iter().collect();
225        Ok(())
226    }
227
228    /// Pretty print the cache DB for debugging purposes.
229    #[cfg(feature = "std")]
230    pub fn pretty_print(&self) -> String {
231        let mut output = String::new();
232        output.push_str("CacheDB:\n");
233        output.push_str(&format!(
234            "  accounts: {} total\n",
235            self.cache.accounts.len()
236        ));
237
238        // Sort accounts by address for deterministic output
239        let mut accounts: Vec<_> = self.cache.accounts.iter().collect();
240        accounts.sort_by_key(|(addr, _)| *addr);
241
242        for (address, db_account) in accounts {
243            output.push_str(&format!("  [{address}]:\n"));
244            output.push_str(&format!("    state: {:?}\n", db_account.account_state));
245
246            if let Some(info) = db_account.info() {
247                output.push_str(&format!("    balance: {}\n", info.balance));
248                output.push_str(&format!("    nonce: {}\n", info.nonce));
249                output.push_str(&format!("    code_hash: {}\n", info.code_hash));
250
251                if let Some(code) = info.code {
252                    if !code.is_empty() {
253                        output.push_str(&format!("    code: {} bytes\n", code.len()));
254                    }
255                }
256            } else {
257                output.push_str("    account: None (not existing)\n");
258            }
259
260            if !db_account.storage.is_empty() {
261                output.push_str(&format!(
262                    "    storage: {} slots\n",
263                    db_account.storage.len()
264                ));
265                let mut storage: Vec<_> = db_account.storage.iter().collect();
266                storage.sort_by_key(|(k, _)| *k);
267                for (key, value) in storage {
268                    output.push_str(&format!("      [{key:#x}]: {value:#x}\n"));
269                }
270            }
271        }
272
273        if !self.cache.contracts.is_empty() {
274            output.push_str(&format!(
275                "  contracts: {} total\n",
276                self.cache.contracts.len()
277            ));
278            let mut contracts: Vec<_> = self.cache.contracts.iter().collect();
279            contracts.sort_by_key(|(h, _)| *h);
280            for (hash, bytecode) in contracts {
281                output.push_str(&format!("    [{hash}]: {} bytes\n", bytecode.len()));
282            }
283        }
284
285        // Print logs in detail: index, address and number of topics.
286        if !self.cache.logs.is_empty() {
287            output.push_str(&format!("  logs: {} total\n", self.cache.logs.len()));
288            for (i, log) in self.cache.logs.iter().enumerate() {
289                // Print address and topics count. We avoid printing raw data to keep output compact.
290                output.push_str(&format!(
291                    "    [{i}]: address: {:?}, topics: {}\n",
292                    log.address,
293                    log.data.topics().len()
294                ));
295            }
296        }
297
298        // Print block_hashes entries (sorted by block number) with their hash.
299        if !self.cache.block_hashes.is_empty() {
300            output.push_str(&format!(
301                "  block_hashes: {} total\n",
302                self.cache.block_hashes.len()
303            ));
304            let mut block_hashes: Vec<_> = self.cache.block_hashes.iter().collect();
305            block_hashes.sort_by_key(|(num, _)| *num);
306            for (num, hash) in block_hashes {
307                output.push_str(&format!("    [{num}]: {hash}\n"));
308            }
309        }
310
311        output.push_str("}\n");
312        output
313    }
314}
315
316impl<ExtDB> DatabaseCommit for CacheDB<ExtDB> {
317    fn commit(&mut self, changes: AddressMap<Account>) {
318        for (address, account) in changes {
319            self.commit_account(address, account);
320        }
321    }
322
323    fn commit_iter(&mut self, changes: &mut dyn Iterator<Item = (Address, Account)>) {
324        for (address, account) in changes {
325            self.commit_account(address, account);
326        }
327    }
328}
329
330impl<ExtDB: DatabaseRef> Database for CacheDB<ExtDB> {
331    type Error = ExtDB::Error;
332
333    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
334        Ok(self.load_account(address)?.info())
335    }
336
337    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
338        match self.cache.contracts.entry(code_hash) {
339            Entry::Occupied(entry) => Ok(entry.get().clone()),
340            Entry::Vacant(entry) => {
341                // If you return code bytes when basic fn is called this function is not needed.
342                Ok(entry.insert(self.db.code_by_hash_ref(code_hash)?).clone())
343            }
344        }
345    }
346
347    /// Get the value in an account's storage slot.
348    ///
349    /// It is assumed that account is already loaded.
350    fn storage(
351        &mut self,
352        address: Address,
353        index: StorageKey,
354    ) -> Result<StorageValue, Self::Error> {
355        match self.cache.accounts.entry(address) {
356            Entry::Occupied(mut acc_entry) => {
357                let acc_entry = acc_entry.get_mut();
358                match acc_entry.storage.entry(index) {
359                    Entry::Occupied(entry) => Ok(*entry.get()),
360                    Entry::Vacant(entry) => {
361                        if matches!(
362                            acc_entry.account_state,
363                            AccountState::StorageCleared | AccountState::NotExisting
364                        ) {
365                            Ok(StorageValue::ZERO)
366                        } else {
367                            let slot = self.db.storage_ref(address, index)?;
368                            entry.insert(slot);
369                            Ok(slot)
370                        }
371                    }
372                }
373            }
374            Entry::Vacant(acc_entry) => {
375                // Acc needs to be loaded for us to access slots.
376                let info = self.db.basic_ref(address)?;
377                let (account, value) = if info.is_some() {
378                    let value = self.db.storage_ref(address, index)?;
379                    let mut account: DbAccount = info.into();
380                    account.storage.insert(index, value);
381                    (account, value)
382                } else {
383                    (info.into(), StorageValue::ZERO)
384                };
385                acc_entry.insert(account);
386                Ok(value)
387            }
388        }
389    }
390
391    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
392        match self.cache.block_hashes.entry(U256::from(number)) {
393            Entry::Occupied(entry) => Ok(*entry.get()),
394            Entry::Vacant(entry) => {
395                let hash = self.db.block_hash_ref(number)?;
396                entry.insert(hash);
397                Ok(hash)
398            }
399        }
400    }
401}
402
403impl<ExtDB: DatabaseRef> DatabaseRef for CacheDB<ExtDB> {
404    type Error = ExtDB::Error;
405
406    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
407        match self.cache.accounts.get(&address) {
408            Some(acc) => Ok(acc.info()),
409            None => self.db.basic_ref(address),
410        }
411    }
412
413    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
414        match self.cache.contracts.get(&code_hash) {
415            Some(entry) => Ok(entry.clone()),
416            None => self.db.code_by_hash_ref(code_hash),
417        }
418    }
419
420    fn storage_ref(
421        &self,
422        address: Address,
423        index: StorageKey,
424    ) -> Result<StorageValue, Self::Error> {
425        match self.cache.accounts.get(&address) {
426            Some(acc_entry) => match acc_entry.storage.get(&index) {
427                Some(entry) => Ok(*entry),
428                None => {
429                    if matches!(
430                        acc_entry.account_state,
431                        AccountState::StorageCleared | AccountState::NotExisting
432                    ) {
433                        Ok(StorageValue::ZERO)
434                    } else {
435                        self.db.storage_ref(address, index)
436                    }
437                }
438            },
439            None => self.db.storage_ref(address, index),
440        }
441    }
442
443    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
444        match self.cache.block_hashes.get(&U256::from(number)) {
445            Some(entry) => Ok(*entry),
446            None => self.db.block_hash_ref(number),
447        }
448    }
449}
450
451/// Database account representation.
452#[derive(Debug, Clone, Default)]
453#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
454pub struct DbAccount {
455    /// Basic account information.
456    pub info: AccountInfo,
457    /// If account is selfdestructed or newly created, storage will be cleared.
458    pub account_state: AccountState,
459    /// Storage slots
460    pub storage: StorageKeyMap<StorageValue>,
461}
462
463impl DbAccount {
464    /// Creates a new non-existing account.
465    pub fn new_not_existing() -> Self {
466        Self {
467            account_state: AccountState::NotExisting,
468            ..Default::default()
469        }
470    }
471
472    /// Returns account info if the account exists.
473    pub fn info(&self) -> Option<AccountInfo> {
474        if matches!(self.account_state, AccountState::NotExisting) {
475            None
476        } else {
477            Some(self.info.clone())
478        }
479    }
480
481    /// Updates the account information.
482    #[inline(always)]
483    pub fn update_info(&mut self, info: AccountInfo) {
484        self.info = info;
485    }
486
487    /// Updates the account state.
488    #[inline(always)]
489    pub const fn update_account_state(&mut self, account_state: AccountState) {
490        self.account_state = account_state;
491    }
492}
493
494impl From<Option<AccountInfo>> for DbAccount {
495    fn from(from: Option<AccountInfo>) -> Self {
496        from.map(Self::from).unwrap_or_else(Self::new_not_existing)
497    }
498}
499
500impl From<AccountInfo> for DbAccount {
501    fn from(info: AccountInfo) -> Self {
502        Self {
503            info,
504            account_state: AccountState::None,
505            ..Default::default()
506        }
507    }
508}
509
510/// State of an account in the database.
511#[derive(Debug, Clone, Default, PartialEq, Eq, Hash)]
512#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
513pub enum AccountState {
514    /// Before Spurious Dragon hardfork there was a difference between empty and not existing.
515    /// And we are flagging it here.
516    NotExisting,
517    /// EVM touched this account. For newer hardfork this means it can be cleared/removed from state.
518    Touched,
519    /// EVM cleared storage of this account, mostly by selfdestruct, we don't ask database for storage slots
520    /// and assume they are StorageValue::ZERO
521    StorageCleared,
522    /// EVM didn't interacted with this account
523    #[default]
524    None,
525}
526
527impl AccountState {
528    /// Returns `true` if EVM cleared storage of this account
529    pub const fn is_storage_cleared(&self) -> bool {
530        matches!(self, AccountState::StorageCleared)
531    }
532}
533
534/// Custom benchmarking DB that only has account info for the zero address.
535///
536/// Any other address will return an empty account.
537#[derive(Debug, Default, Clone)]
538pub struct BenchmarkDB(pub Bytecode, B256);
539
540impl BenchmarkDB {
541    /// Creates a new benchmark database with the given bytecode.
542    pub fn new_bytecode(bytecode: Bytecode) -> Self {
543        let hash = bytecode.hash_slow();
544        Self(bytecode, hash)
545    }
546}
547
548impl Database for BenchmarkDB {
549    type Error = Infallible;
550    /// Get basic account information.
551    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
552        if address == BENCH_TARGET {
553            return Ok(Some(AccountInfo {
554                nonce: 1,
555                balance: BENCH_TARGET_BALANCE,
556                code: Some(self.0.clone()),
557                code_hash: self.1,
558                ..Default::default()
559            }));
560        }
561        if address == BENCH_CALLER {
562            return Ok(Some(AccountInfo {
563                nonce: 0,
564                balance: BENCH_CALLER_BALANCE,
565                code: None,
566                code_hash: KECCAK_EMPTY,
567                ..Default::default()
568            }));
569        }
570        Ok(None)
571    }
572
573    /// Get account code by its hash
574    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
575        if code_hash == self.1 {
576            Ok(self.0.clone())
577        } else {
578            Ok(Bytecode::default())
579        }
580    }
581
582    /// Get storage value of address at index.
583    fn storage(
584        &mut self,
585        _address: Address,
586        _index: StorageKey,
587    ) -> Result<StorageValue, Self::Error> {
588        Ok(StorageValue::default())
589    }
590
591    // History related
592    fn block_hash(&mut self, _number: u64) -> Result<B256, Self::Error> {
593        Ok(B256::default())
594    }
595}
596
597#[cfg(test)]
598mod tests {
599    use super::{CacheDB, EmptyDB};
600    use database_interface::{Database, DatabaseCommit};
601    use primitives::{Address, HashMap, StorageKey, StorageValue};
602    use state::{Account, AccountInfo, EvmStorageSlot, TransactionId};
603
604    #[test]
605    fn test_insert_account_storage() {
606        let account = Address::with_last_byte(42);
607        let nonce = 42;
608        let mut init_state = CacheDB::new(EmptyDB::default());
609        init_state.insert_account_info(
610            account,
611            AccountInfo {
612                nonce,
613                ..Default::default()
614            },
615        );
616
617        let (key, value) = (StorageKey::from(123), StorageValue::from(456));
618        let mut new_state = CacheDB::new(init_state);
619        new_state
620            .insert_account_storage(account, key, value)
621            .unwrap();
622
623        assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
624        assert_eq!(new_state.storage(account, key), Ok(value));
625    }
626
627    #[test]
628    fn test_replace_account_storage() {
629        let account = Address::with_last_byte(42);
630        let nonce = 42;
631        let mut init_state = CacheDB::new(EmptyDB::default());
632        init_state.insert_account_info(
633            account,
634            AccountInfo {
635                nonce,
636                ..Default::default()
637            },
638        );
639
640        let (key0, value0) = (StorageKey::from(123), StorageValue::from(456));
641        let (key1, value1) = (StorageKey::from(789), StorageValue::from(999));
642        init_state
643            .insert_account_storage(account, key0, value0)
644            .unwrap();
645
646        let mut new_state = CacheDB::new(init_state);
647        new_state
648            .replace_account_storage(account, HashMap::from_iter([(key1, value1)]))
649            .unwrap();
650
651        assert_eq!(new_state.basic(account).unwrap().unwrap().nonce, nonce);
652        assert_eq!(new_state.storage(account, key0), Ok(StorageValue::ZERO));
653        assert_eq!(new_state.storage(account, key1), Ok(value1));
654    }
655
656    #[test]
657    fn commit_iter_applies_repeated_account_updates_in_order() {
658        let address = Address::with_last_byte(42);
659        let key = StorageKey::from(123);
660        let value = StorageValue::from(456);
661        let mut db = CacheDB::new(EmptyDB::default());
662
663        let first = Account::from(AccountInfo {
664            nonce: 1,
665            ..Default::default()
666        })
667        .with_touched_mark()
668        .with_storage(
669            [(
670                key,
671                EvmStorageSlot::new_changed(StorageValue::ZERO, value, TransactionId::ZERO),
672            )]
673            .into_iter(),
674        );
675        let second = Account::from(AccountInfo {
676            nonce: 2,
677            ..Default::default()
678        })
679        .with_touched_mark();
680
681        db.commit_iter(&mut [(address, first), (address, second)].into_iter());
682
683        assert_eq!(db.basic(address).unwrap().unwrap().nonce, 2);
684        assert_eq!(db.storage(address, key), Ok(value));
685    }
686
687    #[cfg(feature = "std")]
688    #[test]
689    fn test_pretty_print_cachedb() {
690        use primitives::{Bytes, Log, LogData, B256, U256};
691
692        let account = Address::with_last_byte(55);
693        let mut cachedb = CacheDB::new(EmptyDB::default());
694        cachedb.insert_account_info(
695            account,
696            AccountInfo {
697                nonce: 7,
698                ..Default::default()
699            },
700        );
701        let key = StorageKey::from(1);
702        let value = StorageValue::from(2);
703        cachedb.insert_account_storage(account, key, value).unwrap();
704
705        // Add a log entry
706        let log = Log {
707            address: account,
708            data: LogData::new(Vec::new(), Bytes::from(vec![0x01u8]))
709                .expect("LogData should have <=4 topics"),
710        };
711        cachedb.cache.logs.push(log);
712
713        // Add a block hash entry
714        cachedb
715            .cache
716            .block_hashes
717            .insert(U256::from(123u64), B256::from([1u8; 32]));
718
719        let s = cachedb.pretty_print();
720        assert!(s.contains("CacheDB:"));
721        assert!(s.contains("accounts: 1 total"));
722        // storage line is expected to be present for the account
723        assert!(s.contains("storage: 1 slots"));
724
725        // logs and block_hashes should be reported with counts
726        assert!(s.contains("logs: 1 total"));
727        assert!(s.contains("block_hashes: 1 total"));
728    }
729
730    #[cfg(feature = "serde")]
731    #[test]
732    fn test_serialize_deserialize_cachedb() {
733        let account = Address::with_last_byte(69);
734        let nonce = 420;
735        let mut init_state = CacheDB::new(EmptyDB::default());
736        init_state.insert_account_info(
737            account,
738            AccountInfo {
739                nonce,
740                ..Default::default()
741            },
742        );
743
744        let serialized = serde_json::to_string(&init_state).unwrap();
745        let deserialized: CacheDB<EmptyDB> = serde_json::from_str(&serialized).unwrap();
746
747        assert!(deserialized.cache.accounts.contains_key(&account));
748        assert_eq!(
749            deserialized
750                .cache
751                .accounts
752                .get(&account)
753                .unwrap()
754                .info
755                .nonce,
756            nonce
757        );
758    }
759}