anvil/eth/backend/
db.rs

1//! Helper types for working with [revm](foundry_evm::revm)
2
3use crate::mem::storage::MinedTransaction;
4use alloy_consensus::Header;
5use alloy_primitives::{Address, B256, Bytes, U256, keccak256, map::HashMap};
6use alloy_rpc_types::BlockId;
7use anvil_core::eth::{
8    block::Block,
9    transaction::{MaybeImpersonatedTransaction, TransactionInfo, TypedReceipt, TypedTransaction},
10};
11use foundry_common::errors::FsPathError;
12use foundry_evm::backend::{
13    BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertStateSnapshotAction, StateSnapshot,
14};
15use revm::{
16    Database, DatabaseCommit,
17    bytecode::Bytecode,
18    context::BlockEnv,
19    database::{CacheDB, DatabaseRef, DbAccount},
20    primitives::KECCAK_EMPTY,
21    state::AccountInfo,
22};
23use serde::{
24    Deserialize, Deserializer, Serialize,
25    de::{MapAccess, Visitor},
26};
27use std::{
28    collections::BTreeMap,
29    fmt::{self, Debug},
30    path::Path,
31};
32
33/// Helper trait get access to the full state data of the database
34pub trait MaybeFullDatabase: DatabaseRef<Error = DatabaseError> + Debug {
35    /// Returns a reference to the database as a `dyn DatabaseRef`.
36    // TODO: Required until trait upcasting is stabilized: <https://github.com/rust-lang/rust/issues/65991>
37    fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError>;
38
39    fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
40        None
41    }
42
43    /// Clear the state and move it into a new `StateSnapshot`.
44    fn clear_into_state_snapshot(&mut self) -> StateSnapshot;
45
46    /// Read the state snapshot.
47    ///
48    /// This clones all the states and returns a new `StateSnapshot`.
49    fn read_as_state_snapshot(&self) -> StateSnapshot;
50
51    /// Clears the entire database
52    fn clear(&mut self);
53
54    /// Reverses `clear_into_snapshot` by initializing the db's state with the state snapshot.
55    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot);
56}
57
58impl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T
59where
60    &'a T: DatabaseRef<Error = DatabaseError>,
61{
62    fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
63        T::as_dyn(self)
64    }
65
66    fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
67        T::maybe_as_full_db(self)
68    }
69
70    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
71        unreachable!("never called for DatabaseRef")
72    }
73
74    fn read_as_state_snapshot(&self) -> StateSnapshot {
75        unreachable!("never called for DatabaseRef")
76    }
77
78    fn clear(&mut self) {}
79
80    fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
81}
82
83/// Helper trait to reset the DB if it's forked
84pub trait MaybeForkedDatabase {
85    fn maybe_reset(&mut self, _url: Option<String>, block_number: BlockId) -> Result<(), String>;
86
87    fn maybe_flush_cache(&self) -> Result<(), String>;
88
89    fn maybe_inner(&self) -> Result<&BlockchainDb, String>;
90}
91
92/// This bundles all required revm traits
93pub trait Db:
94    DatabaseRef<Error = DatabaseError>
95    + Database<Error = DatabaseError>
96    + DatabaseCommit
97    + MaybeFullDatabase
98    + MaybeForkedDatabase
99    + fmt::Debug
100    + Send
101    + Sync
102{
103    /// Inserts an account
104    fn insert_account(&mut self, address: Address, account: AccountInfo);
105
106    /// Sets the nonce of the given address
107    fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {
108        let mut info = self.basic(address)?.unwrap_or_default();
109        info.nonce = nonce;
110        self.insert_account(address, info);
111        Ok(())
112    }
113
114    /// Sets the balance of the given address
115    fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {
116        let mut info = self.basic(address)?.unwrap_or_default();
117        info.balance = balance;
118        self.insert_account(address, info);
119        Ok(())
120    }
121
122    /// Sets the code of the given address
123    fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {
124        let mut info = self.basic(address)?.unwrap_or_default();
125        let code_hash = if code.as_ref().is_empty() {
126            KECCAK_EMPTY
127        } else {
128            B256::from_slice(&keccak256(code.as_ref())[..])
129        };
130        info.code_hash = code_hash;
131        info.code = Some(Bytecode::new_raw(alloy_primitives::Bytes(code.0)));
132        self.insert_account(address, info);
133        Ok(())
134    }
135
136    /// Sets the storage value at the given slot for the address
137    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;
138
139    /// inserts a blockhash for the given number
140    fn insert_block_hash(&mut self, number: U256, hash: B256);
141
142    /// Write all chain data to serialized bytes buffer
143    fn dump_state(
144        &self,
145        at: BlockEnv,
146        best_number: u64,
147        blocks: Vec<SerializableBlock>,
148        transactions: Vec<SerializableTransaction>,
149        historical_states: Option<SerializableHistoricalStates>,
150    ) -> DatabaseResult<Option<SerializableState>>;
151
152    /// Deserialize and add all chain data to the backend storage
153    fn load_state(&mut self, state: SerializableState) -> DatabaseResult<bool> {
154        for (addr, account) in state.accounts.into_iter() {
155            let old_account_nonce = DatabaseRef::basic_ref(self, addr)
156                .ok()
157                .and_then(|acc| acc.map(|acc| acc.nonce))
158                .unwrap_or_default();
159            // use max nonce in case account is imported multiple times with difference
160            // nonces to prevent collisions
161            let nonce = std::cmp::max(old_account_nonce, account.nonce);
162
163            self.insert_account(
164                addr,
165                AccountInfo {
166                    balance: account.balance,
167                    code_hash: KECCAK_EMPTY, // will be set automatically
168                    code: if account.code.0.is_empty() {
169                        None
170                    } else {
171                        Some(Bytecode::new_raw(alloy_primitives::Bytes(account.code.0)))
172                    },
173                    nonce,
174                },
175            );
176
177            for (k, v) in account.storage.into_iter() {
178                self.set_storage_at(addr, k, v)?;
179            }
180        }
181        Ok(true)
182    }
183
184    /// Creates a new state snapshot.
185    fn snapshot_state(&mut self) -> U256;
186
187    /// Reverts a state snapshot.
188    ///
189    /// Returns `true` if the state snapshot was reverted.
190    fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;
191
192    /// Returns the state root if possible to compute
193    fn maybe_state_root(&self) -> Option<B256> {
194        None
195    }
196
197    /// Returns the current, standalone state of the Db
198    fn current_state(&self) -> StateDb;
199}
200
201impl dyn Db {
202    // TODO: Required until trait upcasting is stabilized: <https://github.com/rust-lang/rust/issues/65991>
203    pub fn as_dbref(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
204        self.as_dyn()
205    }
206}
207
208/// Convenience impl only used to use any `Db` on the fly as the db layer for revm's CacheDB
209/// This is useful to create blocks without actually writing to the `Db`, but rather in the cache of
210/// the `CacheDB` see also
211/// [Backend::pending_block()](crate::eth::backend::mem::Backend::pending_block())
212impl<T: DatabaseRef<Error = DatabaseError> + Send + Sync + Clone + fmt::Debug> Db for CacheDB<T> {
213    fn insert_account(&mut self, address: Address, account: AccountInfo) {
214        self.insert_account_info(address, account)
215    }
216
217    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
218        self.insert_account_storage(address, slot.into(), val.into())
219    }
220
221    fn insert_block_hash(&mut self, number: U256, hash: B256) {
222        self.cache.block_hashes.insert(number, hash);
223    }
224
225    fn dump_state(
226        &self,
227        _at: BlockEnv,
228        _best_number: u64,
229        _blocks: Vec<SerializableBlock>,
230        _transaction: Vec<SerializableTransaction>,
231        _historical_states: Option<SerializableHistoricalStates>,
232    ) -> DatabaseResult<Option<SerializableState>> {
233        Ok(None)
234    }
235
236    fn snapshot_state(&mut self) -> U256 {
237        U256::ZERO
238    }
239
240    fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {
241        false
242    }
243
244    fn current_state(&self) -> StateDb {
245        StateDb::new(MemDb::default())
246    }
247}
248
249impl<T: DatabaseRef<Error = DatabaseError> + Debug> MaybeFullDatabase for CacheDB<T> {
250    fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
251        self
252    }
253
254    fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
255        Some(&self.cache.accounts)
256    }
257
258    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
259        let db_accounts = std::mem::take(&mut self.cache.accounts);
260        let mut accounts = HashMap::default();
261        let mut account_storage = HashMap::default();
262
263        for (addr, mut acc) in db_accounts {
264            account_storage.insert(addr, std::mem::take(&mut acc.storage));
265            let mut info = acc.info;
266            info.code = self.cache.contracts.remove(&info.code_hash);
267            accounts.insert(addr, info);
268        }
269        let block_hashes = std::mem::take(&mut self.cache.block_hashes);
270        StateSnapshot { accounts, storage: account_storage, block_hashes }
271    }
272
273    fn read_as_state_snapshot(&self) -> StateSnapshot {
274        let db_accounts = self.cache.accounts.clone();
275        let mut accounts = HashMap::default();
276        let mut account_storage = HashMap::default();
277
278        for (addr, acc) in db_accounts {
279            account_storage.insert(addr, acc.storage.clone());
280            let mut info = acc.info;
281            info.code = self.cache.contracts.get(&info.code_hash).cloned();
282            accounts.insert(addr, info);
283        }
284
285        let block_hashes = self.cache.block_hashes.clone();
286        StateSnapshot { accounts, storage: account_storage, block_hashes }
287    }
288
289    fn clear(&mut self) {
290        self.clear_into_state_snapshot();
291    }
292
293    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
294        let StateSnapshot { accounts, mut storage, block_hashes } = state_snapshot;
295
296        for (addr, mut acc) in accounts {
297            if let Some(code) = acc.code.take() {
298                self.cache.contracts.insert(acc.code_hash, code);
299            }
300            self.cache.accounts.insert(
301                addr,
302                DbAccount {
303                    info: acc,
304                    storage: storage.remove(&addr).unwrap_or_default(),
305                    ..Default::default()
306                },
307            );
308        }
309        self.cache.block_hashes = block_hashes;
310    }
311}
312
313impl<T: DatabaseRef<Error = DatabaseError>> MaybeForkedDatabase for CacheDB<T> {
314    fn maybe_reset(&mut self, _url: Option<String>, _block_number: BlockId) -> Result<(), String> {
315        Err("not supported".to_string())
316    }
317
318    fn maybe_flush_cache(&self) -> Result<(), String> {
319        Err("not supported".to_string())
320    }
321
322    fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
323        Err("not supported".to_string())
324    }
325}
326
327/// Represents a state at certain point
328#[derive(Debug)]
329pub struct StateDb(pub(crate) Box<dyn MaybeFullDatabase + Send + Sync>);
330
331impl StateDb {
332    pub fn new(db: impl MaybeFullDatabase + Send + Sync + 'static) -> Self {
333        Self(Box::new(db))
334    }
335
336    pub fn serialize_state(&mut self) -> StateSnapshot {
337        // Using read_as_snapshot makes sures we don't clear the historical state from the current
338        // instance.
339        self.read_as_state_snapshot()
340    }
341}
342
343impl DatabaseRef for StateDb {
344    type Error = DatabaseError;
345    fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {
346        self.0.basic_ref(address)
347    }
348
349    fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {
350        self.0.code_by_hash_ref(code_hash)
351    }
352
353    fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
354        self.0.storage_ref(address, index)
355    }
356
357    fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {
358        self.0.block_hash_ref(number)
359    }
360}
361
362impl MaybeFullDatabase for StateDb {
363    fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
364        self.0.as_dyn()
365    }
366
367    fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
368        self.0.maybe_as_full_db()
369    }
370
371    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
372        self.0.clear_into_state_snapshot()
373    }
374
375    fn read_as_state_snapshot(&self) -> StateSnapshot {
376        self.0.read_as_state_snapshot()
377    }
378
379    fn clear(&mut self) {
380        self.0.clear()
381    }
382
383    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
384        self.0.init_from_state_snapshot(state_snapshot)
385    }
386}
387
388#[derive(Clone, Debug, Default, Serialize, Deserialize)]
389pub struct SerializableState {
390    /// The block number of the state
391    ///
392    /// Note: This is an Option for backwards compatibility: <https://github.com/foundry-rs/foundry/issues/5460>
393    pub block: Option<BlockEnv>,
394    pub accounts: BTreeMap<Address, SerializableAccountRecord>,
395    /// The best block number of the state, can be different from block number (Arbitrum chain).
396    pub best_block_number: Option<u64>,
397    #[serde(default)]
398    pub blocks: Vec<SerializableBlock>,
399    #[serde(default)]
400    pub transactions: Vec<SerializableTransaction>,
401    /// Historical states of accounts and storage at particular block hashes.
402    ///
403    /// Note: This is an Option for backwards compatibility.
404    #[serde(default)]
405    pub historical_states: Option<SerializableHistoricalStates>,
406}
407
408impl SerializableState {
409    /// Loads the `Genesis` object from the given json file path
410    pub fn load(path: impl AsRef<Path>) -> Result<Self, FsPathError> {
411        let path = path.as_ref();
412        if path.is_dir() {
413            foundry_common::fs::read_json_file(&path.join("state.json"))
414        } else {
415            foundry_common::fs::read_json_file(path)
416        }
417    }
418
419    /// This is used as the clap `value_parser` implementation
420    #[allow(dead_code)]
421    pub(crate) fn parse(path: &str) -> Result<Self, String> {
422        Self::load(path).map_err(|err| err.to_string())
423    }
424}
425
426#[derive(Clone, Debug, Serialize, Deserialize)]
427pub struct SerializableAccountRecord {
428    pub nonce: u64,
429    pub balance: U256,
430    pub code: Bytes,
431
432    #[serde(deserialize_with = "deserialize_btree")]
433    pub storage: BTreeMap<B256, B256>,
434}
435
436fn deserialize_btree<'de, D>(deserializer: D) -> Result<BTreeMap<B256, B256>, D::Error>
437where
438    D: Deserializer<'de>,
439{
440    struct BTreeVisitor;
441
442    impl<'de> Visitor<'de> for BTreeVisitor {
443        type Value = BTreeMap<B256, B256>;
444
445        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
446            formatter.write_str("a mapping of hex encoded storage slots to hex encoded state data")
447        }
448
449        fn visit_map<M>(self, mut mapping: M) -> Result<BTreeMap<B256, B256>, M::Error>
450        where
451            M: MapAccess<'de>,
452        {
453            let mut btree = BTreeMap::new();
454            while let Some((key, value)) = mapping.next_entry::<U256, U256>()? {
455                btree.insert(B256::from(key), B256::from(value));
456            }
457
458            Ok(btree)
459        }
460    }
461
462    deserializer.deserialize_map(BTreeVisitor)
463}
464
465/// Defines a backwards-compatible enum for transactions.
466/// This is essential for maintaining compatibility with state dumps
467/// created before the changes introduced in PR #8411.
468///
469/// The enum can represent either a `TypedTransaction` or a `MaybeImpersonatedTransaction`,
470/// depending on the data being deserialized. This flexibility ensures that older state
471/// dumps can still be loaded correctly, even after the changes in #8411.
472#[derive(Clone, Debug, Serialize, Deserialize)]
473#[serde(untagged)]
474pub enum SerializableTransactionType {
475    TypedTransaction(TypedTransaction),
476    MaybeImpersonatedTransaction(MaybeImpersonatedTransaction),
477}
478
479#[derive(Clone, Debug, Serialize, Deserialize)]
480pub struct SerializableBlock {
481    pub header: Header,
482    pub transactions: Vec<SerializableTransactionType>,
483    pub ommers: Vec<Header>,
484}
485
486impl From<Block> for SerializableBlock {
487    fn from(block: Block) -> Self {
488        Self {
489            header: block.header,
490            transactions: block.transactions.into_iter().map(Into::into).collect(),
491            ommers: block.ommers.into_iter().collect(),
492        }
493    }
494}
495
496impl From<SerializableBlock> for Block {
497    fn from(block: SerializableBlock) -> Self {
498        Self {
499            header: block.header,
500            transactions: block.transactions.into_iter().map(Into::into).collect(),
501            ommers: block.ommers.into_iter().collect(),
502        }
503    }
504}
505
506impl From<MaybeImpersonatedTransaction> for SerializableTransactionType {
507    fn from(transaction: MaybeImpersonatedTransaction) -> Self {
508        Self::MaybeImpersonatedTransaction(transaction)
509    }
510}
511
512impl From<SerializableTransactionType> for MaybeImpersonatedTransaction {
513    fn from(transaction: SerializableTransactionType) -> Self {
514        match transaction {
515            SerializableTransactionType::TypedTransaction(tx) => Self::new(tx),
516            SerializableTransactionType::MaybeImpersonatedTransaction(tx) => tx,
517        }
518    }
519}
520
521#[derive(Clone, Debug, Serialize, Deserialize)]
522pub struct SerializableTransaction {
523    pub info: TransactionInfo,
524    pub receipt: TypedReceipt,
525    pub block_hash: B256,
526    pub block_number: u64,
527}
528
529impl From<MinedTransaction> for SerializableTransaction {
530    fn from(transaction: MinedTransaction) -> Self {
531        Self {
532            info: transaction.info,
533            receipt: transaction.receipt,
534            block_hash: transaction.block_hash,
535            block_number: transaction.block_number,
536        }
537    }
538}
539
540impl From<SerializableTransaction> for MinedTransaction {
541    fn from(transaction: SerializableTransaction) -> Self {
542        Self {
543            info: transaction.info,
544            receipt: transaction.receipt,
545            block_hash: transaction.block_hash,
546            block_number: transaction.block_number,
547        }
548    }
549}
550
551#[derive(Clone, Debug, Serialize, Deserialize, Default)]
552pub struct SerializableHistoricalStates(Vec<(B256, StateSnapshot)>);
553
554impl SerializableHistoricalStates {
555    pub const fn new(states: Vec<(B256, StateSnapshot)>) -> Self {
556        Self(states)
557    }
558}
559
560impl IntoIterator for SerializableHistoricalStates {
561    type Item = (B256, StateSnapshot);
562    type IntoIter = std::vec::IntoIter<Self::Item>;
563
564    fn into_iter(self) -> Self::IntoIter {
565        self.0.into_iter()
566    }
567}
568
569#[cfg(test)]
570mod test {
571    use super::*;
572
573    #[test]
574    fn test_deser_block() {
575        let block = r#"{
576            "header": {
577                "parentHash": "0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929",
578                "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
579                "miner": "0x0000000000000000000000000000000000000000",
580                "stateRoot": "0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1",
581                "transactionsRoot": "0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988",
582                "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
583                "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
584                "difficulty": "0x0",
585                "number": "0x2",
586                "gasLimit": "0x1c9c380",
587                "gasUsed": "0x5208",
588                "timestamp": "0x66cdc823",
589                "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
590                "nonce": "0x0000000000000000",
591                "baseFeePerGas": "0x342a1c58",
592                "blobGasUsed": "0x0",
593                "excessBlobGas": "0x0",
594                "extraData": "0x"
595            },
596            "transactions": [
597                {
598                    "EIP1559": {
599                        "chainId": "0x7a69",
600                        "nonce": "0x0",
601                        "gas": "0x5209",
602                        "maxFeePerGas": "0x77359401",
603                        "maxPriorityFeePerGas": "0x1",
604                        "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
605                        "value": "0x0",
606                        "accessList": [],
607                        "input": "0x",
608                        "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0",
609                        "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd",
610                        "yParity": "0x0",
611                        "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"
612                    }
613                }
614            ],
615            "ommers": []
616        }
617        "#;
618
619        let _block: SerializableBlock = serde_json::from_str(block).unwrap();
620    }
621}