Skip to main content

anvil/eth/backend/
db.rs

1//! Helper types for working with [revm]
2
3use std::{
4    collections::BTreeMap,
5    fmt::{self, Debug},
6    fs::File,
7    io::BufReader,
8    path::Path,
9};
10
11use alloy_consensus::BlockBody;
12#[cfg(test)]
13use alloy_consensus::Header;
14use alloy_eips::eip4895::Withdrawals;
15use alloy_network::Network;
16use alloy_primitives::{
17    Address, B256, Bytes, U256, keccak256,
18    map::{AddressMap, HashMap, U256Map},
19};
20use alloy_rpc_types::BlockId;
21use anvil_core::eth::{
22    block::Block,
23    transaction::{MaybeImpersonatedTransaction, TransactionInfo},
24};
25use foundry_common::errors::FsPathError;
26use foundry_evm::backend::{
27    BlockchainDb, DatabaseError, DatabaseResult, EmptyDBWrapper, MemDb, RevertStateSnapshotAction,
28    StateSnapshot,
29};
30use foundry_primitives::{FoundryHeader, FoundryReceiptEnvelope, FoundryTxEnvelope};
31use revm::{
32    Database, DatabaseCommit,
33    bytecode::Bytecode,
34    context::BlockEnv,
35    context_interface::block::BlobExcessGasAndPrice,
36    database::{AccountState, CacheDB, DatabaseRef, DbAccount},
37    primitives::{KECCAK_EMPTY, eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE},
38    state::AccountInfo,
39};
40use serde::{
41    Deserialize, Deserializer, Serialize,
42    de::{Error as DeError, MapAccess, Visitor},
43};
44use serde_json::Value;
45
46use crate::mem::storage::MinedTransaction;
47
48/// Number of preceding block hashes available to the EVM's `BLOCKHASH` opcode.
49pub(crate) const BLOCKHASH_HISTORY: u64 = 256;
50
51/// Execution inputs needed to replay a locally stored Monad block faithfully.
52#[cfg(feature = "monad")]
53#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
54pub struct MonadBlockReplayProfile {
55    /// Chain ID active when the block was executed.
56    pub execution_chain_id: u64,
57    /// Monad hardfork active when the block was executed.
58    pub hardfork: foundry_evm::hardfork::MonadHardfork,
59}
60
61/// Inserts a block hash, discards entries outside the EVM-visible cache, and returns its head.
62pub(crate) fn cache_block_hash(block_hashes: &mut U256Map<B256>, number: U256, hash: B256) -> U256 {
63    let head = block_hashes.keys().copied().max().map_or(number, |head| head.max(number));
64    let min_number = head.saturating_sub(U256::from(BLOCKHASH_HISTORY));
65    block_hashes.retain(|cached, _| *cached >= min_number && *cached <= head);
66    if number >= min_number {
67        block_hashes.insert(number, hash);
68    }
69    head
70}
71
72/// Helper trait get access to the full state data of the database
73pub trait MaybeFullDatabase: DatabaseRef<Error = DatabaseError> + Debug {
74    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
75        None
76    }
77
78    /// Returns an owned, recursively merged view of all available accounts.
79    fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
80        self.maybe_as_full_db().cloned()
81    }
82
83    /// Returns whether snapshots of this database use structural sharing.
84    fn is_persistent(&self) -> bool {
85        false
86    }
87
88    /// Clear the state and move it into a new `StateSnapshot`.
89    fn clear_into_state_snapshot(&mut self) -> StateSnapshot;
90
91    /// Read the state snapshot.
92    ///
93    /// This clones all the states and returns a new `StateSnapshot`.
94    fn read_as_state_snapshot(&self) -> StateSnapshot;
95
96    /// Clears the entire database
97    fn clear(&mut self);
98
99    /// Reverses `clear_into_snapshot` by initializing the db's state with the state snapshot.
100    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot);
101}
102
103impl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T
104where
105    &'a T: DatabaseRef<Error = DatabaseError>,
106{
107    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
108        T::maybe_as_full_db(self)
109    }
110
111    fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
112        T::maybe_full_db(self)
113    }
114
115    fn is_persistent(&self) -> bool {
116        T::is_persistent(self)
117    }
118
119    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
120        unreachable!("never called for DatabaseRef")
121    }
122
123    fn read_as_state_snapshot(&self) -> StateSnapshot {
124        unreachable!("never called for DatabaseRef")
125    }
126
127    fn clear(&mut self) {}
128
129    fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
130}
131
132impl<T: MaybeFullDatabase + ?Sized> MaybeFullDatabase for Box<T>
133where
134    Self: DatabaseRef<Error = DatabaseError>,
135{
136    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
137        T::maybe_as_full_db(self)
138    }
139
140    fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
141        T::maybe_full_db(self)
142    }
143
144    fn is_persistent(&self) -> bool {
145        T::is_persistent(self)
146    }
147
148    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
149        T::clear_into_state_snapshot(self)
150    }
151
152    fn read_as_state_snapshot(&self) -> StateSnapshot {
153        T::read_as_state_snapshot(self)
154    }
155
156    fn clear(&mut self) {
157        T::clear(self)
158    }
159
160    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
161        T::init_from_state_snapshot(self, state_snapshot)
162    }
163}
164
165/// Helper trait to reset the DB if it's forked
166pub trait MaybeForkedDatabase {
167    fn maybe_reset(&mut self, _urls: Vec<String>, block_number: BlockId) -> Result<(), String>;
168
169    fn maybe_flush_cache(&self) -> Result<(), String>;
170
171    fn maybe_inner(&self) -> Result<&BlockchainDb, String>;
172}
173
174/// `dyn Db` satisfies all `alloy_evm::Database` requirements via its supertraits, but the
175/// blanket impl has an implicit `Sized` bound. Provide an explicit impl.
176impl alloy_evm::Database for dyn Db {}
177
178/// A wrapper around [`CacheDB`].
179#[derive(Debug)]
180pub struct AnvilCacheDB<T>(pub CacheDB<T>);
181
182impl<T: DatabaseRef<Error = DatabaseError>> AnvilCacheDB<T> {
183    pub fn new(inner: T) -> Self {
184        Self(CacheDB::new(inner))
185    }
186}
187
188impl<T: DatabaseRef<Error = DatabaseError>> std::ops::Deref for AnvilCacheDB<T> {
189    type Target = CacheDB<T>;
190    fn deref(&self) -> &Self::Target {
191        &self.0
192    }
193}
194
195impl<T: DatabaseRef<Error = DatabaseError>> std::ops::DerefMut for AnvilCacheDB<T> {
196    fn deref_mut(&mut self) -> &mut Self::Target {
197        &mut self.0
198    }
199}
200
201impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> Database for AnvilCacheDB<T> {
202    type Error = DatabaseError;
203
204    fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
205        self.0.basic(address)
206    }
207
208    fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
209        self.0.code_by_hash(code_hash)
210    }
211
212    fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
213        self.0.storage(address, index)
214    }
215
216    fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
217        self.0.block_hash(number)
218    }
219}
220
221impl<T: DatabaseRef<Error = DatabaseError>> DatabaseRef for AnvilCacheDB<T> {
222    type Error = DatabaseError;
223
224    fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
225        self.0.basic_ref(address)
226    }
227
228    fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
229        self.0.code_by_hash_ref(code_hash)
230    }
231
232    fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
233        self.0.storage_ref(address, index)
234    }
235
236    fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
237        self.0.block_hash_ref(number)
238    }
239}
240
241impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> DatabaseCommit for AnvilCacheDB<T> {
242    fn commit(&mut self, changes: revm::state::EvmState) {
243        self.0.commit(changes)
244    }
245}
246
247/// This bundles all required revm traits
248pub trait Db:
249    DatabaseRef<Error = DatabaseError>
250    + Database<Error = DatabaseError>
251    + DatabaseCommit
252    + MaybeFullDatabase
253    + MaybeForkedDatabase
254    + fmt::Debug
255    + Send
256    + Sync
257{
258    /// Inserts an account
259    fn insert_account(&mut self, address: Address, account: AccountInfo);
260
261    /// Sets the nonce of the given address
262    fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {
263        let mut info = self.basic(address)?.unwrap_or_default();
264        info.nonce = nonce;
265        self.insert_account(address, info);
266        Ok(())
267    }
268
269    /// Sets the balance of the given address
270    fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {
271        let mut info = self.basic(address)?.unwrap_or_default();
272        info.balance = balance;
273        self.insert_account(address, info);
274        Ok(())
275    }
276
277    /// Sets the code of the given address
278    fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {
279        let mut info = self.basic(address)?.unwrap_or_default();
280        let code_hash = if code.as_ref().is_empty() {
281            KECCAK_EMPTY
282        } else {
283            B256::from_slice(&keccak256(code.as_ref())[..])
284        };
285        info.code_hash = code_hash;
286        info.code = Some(Bytecode::new_raw(code));
287        self.insert_account(address, info);
288        Ok(())
289    }
290
291    /// Sets the storage value at the given slot for the address
292    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;
293
294    /// inserts a blockhash for the given number
295    fn insert_block_hash(&mut self, number: U256, hash: B256);
296
297    /// Replaces all cached block hashes.
298    fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>);
299
300    /// Write all chain data to serialized bytes buffer
301    fn dump_state(
302        &self,
303        at: BlockEnv,
304        best_number: u64,
305        blocks: Vec<SerializableBlock>,
306        transactions: Vec<SerializableTransaction>,
307        historical_states: Option<SerializableHistoricalStates>,
308    ) -> DatabaseResult<Option<SerializableState>>;
309
310    /// Deserialize and add all accounts to the backend storage.
311    fn load_state(&mut self, state: SerializableState) -> DatabaseResult<bool> {
312        for (addr, account) in state.accounts {
313            let old_account_nonce = DatabaseRef::basic_ref(self, addr)
314                .ok()
315                .and_then(|acc| acc.map(|acc| acc.nonce))
316                .unwrap_or_default();
317            // use max nonce in case account is imported multiple times with difference
318            // nonces to prevent collisions
319            let nonce = std::cmp::max(old_account_nonce, account.nonce);
320
321            self.insert_account(
322                addr,
323                AccountInfo {
324                    balance: account.balance,
325                    code_hash: KECCAK_EMPTY, // will be set automatically
326                    code: if account.code.0.is_empty() {
327                        None
328                    } else {
329                        Some(Bytecode::new_raw(account.code))
330                    },
331                    nonce,
332                    account_id: None,
333                },
334            );
335
336            for (k, v) in account.storage {
337                self.set_storage_at(addr, k, v)?;
338            }
339        }
340        Ok(true)
341    }
342
343    /// Creates a new state snapshot.
344    fn snapshot_state(&mut self) -> U256;
345
346    /// Reverts a state snapshot.
347    ///
348    /// Returns `true` if the state snapshot was reverted.
349    fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;
350
351    /// Returns the state root if possible to compute
352    fn maybe_state_root(&self) -> Option<B256> {
353        None
354    }
355
356    /// Returns the current, standalone state of the Db
357    fn current_state(&self) -> StateDb;
358}
359
360/// Convenience impl only used to use any `Db` on the fly as the db layer for revm's CacheDB
361/// This is useful to create blocks without actually writing to the `Db`, but rather in the cache of
362/// the `CacheDB` see also
363/// [Backend::pending_block()](crate::eth::backend::mem::Backend::pending_block())
364impl<T> Db for CacheDB<T>
365where
366    T: DatabaseRef<Error = DatabaseError> + MaybeFullDatabase + Send + Sync + Clone + fmt::Debug,
367{
368    fn insert_account(&mut self, address: Address, account: AccountInfo) {
369        self.insert_account_info(address, account)
370    }
371
372    fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
373        self.insert_account_storage(address, slot.into(), val.into())
374    }
375
376    fn insert_block_hash(&mut self, number: U256, hash: B256) {
377        cache_block_hash(&mut self.cache.block_hashes, number, hash);
378    }
379
380    fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>) {
381        self.cache.block_hashes = block_hashes.into_iter().collect();
382    }
383
384    fn dump_state(
385        &self,
386        _at: BlockEnv,
387        _best_number: u64,
388        _blocks: Vec<SerializableBlock>,
389        _transaction: Vec<SerializableTransaction>,
390        _historical_states: Option<SerializableHistoricalStates>,
391    ) -> DatabaseResult<Option<SerializableState>> {
392        Ok(None)
393    }
394
395    fn snapshot_state(&mut self) -> U256 {
396        U256::ZERO
397    }
398
399    fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {
400        false
401    }
402
403    fn maybe_state_root(&self) -> Option<B256> {
404        self.maybe_full_db().map(|accounts| crate::mem::state::state_root(&accounts))
405    }
406
407    fn current_state(&self) -> StateDb {
408        StateDb::new(MemDb::default())
409    }
410}
411
412impl<T: MaybeFullDatabase> MaybeFullDatabase for CacheDB<T> {
413    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
414        Some(&self.cache.accounts)
415    }
416
417    fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
418        let mut accounts = self.db.maybe_full_db()?;
419        for (address, overlay) in &self.cache.accounts {
420            if overlay.account_state == AccountState::NotExisting {
421                accounts.remove(address);
422                continue;
423            }
424            if overlay.account_state == AccountState::StorageCleared {
425                accounts.insert(*address, overlay.clone());
426                continue;
427            }
428
429            let mut account = accounts.remove(address).unwrap_or_default();
430            account.info = overlay.info.clone();
431            account.account_state = overlay.account_state.clone();
432            account.storage.extend(overlay.storage.clone());
433            accounts.insert(*address, account);
434        }
435        Some(accounts)
436    }
437
438    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
439        let db_accounts = std::mem::take(&mut self.cache.accounts);
440        let mut accounts = HashMap::default();
441        let mut account_storage = HashMap::default();
442
443        for (addr, mut acc) in db_accounts {
444            account_storage.insert(addr, std::mem::take(&mut acc.storage));
445            let mut info = acc.info;
446            info.code = self.cache.contracts.remove(&info.code_hash);
447            accounts.insert(addr, info);
448        }
449        let block_hashes = std::mem::take(&mut self.cache.block_hashes);
450        StateSnapshot { accounts, storage: account_storage, block_hashes }
451    }
452
453    fn read_as_state_snapshot(&self) -> StateSnapshot {
454        let mut accounts = HashMap::default();
455        let mut account_storage = HashMap::default();
456
457        for (addr, acc) in &self.cache.accounts {
458            account_storage.insert(*addr, acc.storage.clone());
459            let mut info = acc.info.clone();
460            info.code = self.cache.contracts.get(&info.code_hash).cloned();
461            accounts.insert(*addr, info);
462        }
463
464        let block_hashes = self.cache.block_hashes.clone();
465        StateSnapshot { accounts, storage: account_storage, block_hashes }
466    }
467
468    fn clear(&mut self) {
469        self.clear_into_state_snapshot();
470    }
471
472    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
473        let StateSnapshot { accounts, mut storage, block_hashes } = state_snapshot;
474
475        for (addr, mut acc) in accounts {
476            if let Some(code) = acc.code.take() {
477                self.cache.contracts.insert(acc.code_hash, code);
478            }
479            self.cache.accounts.insert(
480                addr,
481                DbAccount {
482                    info: acc,
483                    storage: storage.remove(&addr).unwrap_or_default(),
484                    ..Default::default()
485                },
486            );
487        }
488        self.cache.block_hashes = block_hashes;
489    }
490}
491
492impl MaybeFullDatabase for EmptyDBWrapper {
493    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
494        StateSnapshot::default()
495    }
496
497    fn read_as_state_snapshot(&self) -> StateSnapshot {
498        StateSnapshot::default()
499    }
500
501    fn clear(&mut self) {}
502
503    fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
504}
505
506impl<T: DatabaseRef<Error = DatabaseError>> MaybeForkedDatabase for CacheDB<T> {
507    fn maybe_reset(&mut self, _urls: Vec<String>, _block_number: BlockId) -> Result<(), String> {
508        Err("not supported".to_string())
509    }
510
511    fn maybe_flush_cache(&self) -> Result<(), String> {
512        Err("not supported".to_string())
513    }
514
515    fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
516        Err("not supported".to_string())
517    }
518}
519
520/// Represents a state at certain point
521#[derive(Debug)]
522pub struct StateDb(pub(crate) Box<dyn MaybeFullDatabase + Send + Sync>);
523
524impl StateDb {
525    pub fn new(db: impl MaybeFullDatabase + Send + Sync + 'static) -> Self {
526        Self(Box::new(db))
527    }
528
529    pub fn serialize_state(&mut self) -> StateSnapshot {
530        // Using read_as_snapshot makes sures we don't clear the historical state from the current
531        // instance.
532        self.read_as_state_snapshot()
533    }
534}
535
536impl DatabaseRef for StateDb {
537    type Error = DatabaseError;
538    fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {
539        self.0.basic_ref(address)
540    }
541
542    fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {
543        self.0.code_by_hash_ref(code_hash)
544    }
545
546    fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
547        self.0.storage_ref(address, index)
548    }
549
550    fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {
551        self.0.block_hash_ref(number)
552    }
553}
554
555impl MaybeFullDatabase for StateDb {
556    fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
557        self.0.maybe_as_full_db()
558    }
559
560    fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
561        self.0.maybe_full_db()
562    }
563
564    fn is_persistent(&self) -> bool {
565        self.0.is_persistent()
566    }
567
568    fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
569        self.0.clear_into_state_snapshot()
570    }
571
572    fn read_as_state_snapshot(&self) -> StateSnapshot {
573        self.0.read_as_state_snapshot()
574    }
575
576    fn clear(&mut self) {
577        self.0.clear()
578    }
579
580    fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
581        self.0.init_from_state_snapshot(state_snapshot)
582    }
583}
584
585/// Legacy block environment from before v1.3.
586#[derive(Debug, Deserialize)]
587#[serde(rename_all = "snake_case")]
588pub struct LegacyBlockEnv {
589    pub number: Option<StringOrU64>,
590    #[serde(alias = "coinbase")]
591    pub beneficiary: Option<Address>,
592    pub timestamp: Option<StringOrU64>,
593    pub gas_limit: Option<StringOrU64>,
594    pub basefee: Option<StringOrU64>,
595    pub difficulty: Option<StringOrU64>,
596    pub prevrandao: Option<B256>,
597    pub blob_excess_gas_and_price: Option<LegacyBlobExcessGasAndPrice>,
598}
599
600/// Legacy blob excess gas and price structure from before v1.3.
601#[derive(Debug, Deserialize)]
602pub struct LegacyBlobExcessGasAndPrice {
603    pub excess_blob_gas: u64,
604    pub blob_gasprice: u128,
605}
606
607/// Legacy string or u64 type from before v1.3.
608#[derive(Debug, Deserialize)]
609#[serde(untagged)]
610pub enum StringOrU64 {
611    Hex(String),
612    Dec(u64),
613}
614
615impl StringOrU64 {
616    pub fn to_u64(&self) -> Option<u64> {
617        match self {
618            Self::Dec(n) => Some(*n),
619            Self::Hex(s) => s.strip_prefix("0x").and_then(|s| u64::from_str_radix(s, 16).ok()),
620        }
621    }
622
623    pub fn to_u256(&self) -> Option<U256> {
624        match self {
625            Self::Dec(n) => Some(U256::from(*n)),
626            Self::Hex(s) => s.strip_prefix("0x").and_then(|s| U256::from_str_radix(s, 16).ok()),
627        }
628    }
629}
630
631/// Converts a `LegacyBlockEnv` to a `BlockEnv`, handling the conversion of legacy fields.
632impl TryFrom<LegacyBlockEnv> for BlockEnv {
633    type Error = &'static str;
634
635    fn try_from(legacy: LegacyBlockEnv) -> Result<Self, Self::Error> {
636        Ok(Self {
637            number: legacy.number.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),
638            beneficiary: legacy.beneficiary.unwrap_or(Address::ZERO),
639            timestamp: legacy.timestamp.and_then(|v| v.to_u256()).unwrap_or(U256::ONE),
640            gas_limit: legacy.gas_limit.and_then(|v| v.to_u64()).unwrap_or(u64::MAX),
641            basefee: legacy.basefee.and_then(|v| v.to_u64()).unwrap_or(0),
642            difficulty: legacy.difficulty.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),
643            prevrandao: legacy.prevrandao.or(Some(B256::ZERO)),
644            slot_num: 0,
645            blob_excess_gas_and_price: legacy
646                .blob_excess_gas_and_price
647                .map(|v| BlobExcessGasAndPrice {
648                    excess_blob_gas: v.excess_blob_gas,
649                    blob_gasprice: v.blob_gasprice,
650                })
651                .or_else(|| {
652                    Some(BlobExcessGasAndPrice::new(0, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE))
653                }),
654        })
655    }
656}
657
658/// Custom deserializer for `BlockEnv` that handles both v1.2 and v1.3+ formats.
659fn deserialize_block_env_compat<'de, D>(deserializer: D) -> Result<Option<BlockEnv>, D::Error>
660where
661    D: Deserializer<'de>,
662{
663    let value: Option<Value> = Option::deserialize(deserializer)?;
664    let Some(value) = value else {
665        return Ok(None);
666    };
667
668    if let Ok(env) = BlockEnv::deserialize(&value) {
669        return Ok(Some(env));
670    }
671
672    let legacy: LegacyBlockEnv = serde_json::from_value(value).map_err(|e| {
673        D::Error::custom(format!("Legacy deserialization of `BlockEnv` failed: {e}"))
674    })?;
675
676    Ok(Some(BlockEnv::try_from(legacy).map_err(D::Error::custom)?))
677}
678
679/// Custom deserializer for `best_block_number` that handles both v1.2 and v1.3+ formats.
680fn deserialize_best_block_number_compat<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
681where
682    D: Deserializer<'de>,
683{
684    let value: Option<Value> = Option::deserialize(deserializer)?;
685    let Some(value) = value else {
686        return Ok(None);
687    };
688
689    let number = match value {
690        Value::Number(n) => n.as_u64(),
691        Value::String(s) => {
692            if let Some(s) = s.strip_prefix("0x") {
693                u64::from_str_radix(s, 16).ok()
694            } else {
695                s.parse().ok()
696            }
697        }
698        _ => None,
699    };
700
701    Ok(number)
702}
703
704#[derive(Clone, Debug, Default, Serialize, Deserialize)]
705pub struct SerializableState {
706    /// The block number of the state
707    ///
708    /// Note: This is an Option for backwards compatibility: <https://github.com/foundry-rs/foundry/issues/5460>
709    #[serde(deserialize_with = "deserialize_block_env_compat")]
710    pub block: Option<BlockEnv>,
711    pub accounts: BTreeMap<Address, SerializableAccountRecord>,
712    /// The best block number of the state, can be different from block number (Arbitrum chain).
713    #[serde(deserialize_with = "deserialize_best_block_number_compat")]
714    pub best_block_number: Option<u64>,
715    #[serde(default)]
716    pub blocks: Vec<SerializableBlock>,
717    #[serde(default)]
718    pub transactions: Vec<SerializableTransaction>,
719    /// Authoritative Monad senders and EIP-7702 authorities for locally stored blocks.
720    ///
721    /// This metadata can differ from transaction-body recovery when signature impersonation was
722    /// used, so it is preserved even while the corresponding transaction bodies are retained.
723    #[cfg(feature = "monad")]
724    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
725    pub monad_block_participants: BTreeMap<B256, std::collections::BTreeSet<Address>>,
726    /// Execution profile used for each locally stored Monad block.
727    #[cfg(feature = "monad")]
728    #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
729    pub monad_block_replay_profiles: BTreeMap<B256, MonadBlockReplayProfile>,
730    /// Historical states of accounts and storage at particular block hashes.
731    ///
732    /// Note: This is an Option for backwards compatibility.
733    #[serde(default)]
734    pub historical_states: Option<SerializableHistoricalStates>,
735}
736
737impl SerializableState {
738    /// Loads the `Genesis` object from the given json file path
739    pub fn load(path: impl AsRef<Path>) -> Result<Self, FsPathError> {
740        let mut path = path.as_ref().to_path_buf();
741        if path.is_dir() {
742            path = path.join("state.json");
743        }
744
745        let file = File::open(&path).map_err(|err| FsPathError::read(err, &path))?;
746        serde_json::from_reader(BufReader::new(file)).map_err(|err| {
747            if err.is_io() {
748                FsPathError::read(err.into(), &path)
749            } else {
750                FsPathError::ReadJson { source: err, path }
751            }
752        })
753    }
754
755    /// This is used as the clap `value_parser` implementation
756    #[cfg(feature = "cmd")]
757    pub(crate) fn parse(path: &str) -> Result<Self, String> {
758        Self::load(path).map_err(|err| err.to_string())
759    }
760}
761
762#[derive(Clone, Debug, Serialize, Deserialize)]
763pub struct SerializableAccountRecord {
764    pub nonce: u64,
765    pub balance: U256,
766    pub code: Bytes,
767
768    #[serde(deserialize_with = "deserialize_btree")]
769    pub storage: BTreeMap<B256, B256>,
770}
771
772fn deserialize_btree<'de, D>(deserializer: D) -> Result<BTreeMap<B256, B256>, D::Error>
773where
774    D: Deserializer<'de>,
775{
776    struct BTreeVisitor;
777
778    impl<'de> Visitor<'de> for BTreeVisitor {
779        type Value = BTreeMap<B256, B256>;
780
781        fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
782            formatter.write_str("a mapping of hex encoded storage slots to hex encoded state data")
783        }
784
785        fn visit_map<M>(self, mut mapping: M) -> Result<BTreeMap<B256, B256>, M::Error>
786        where
787            M: MapAccess<'de>,
788        {
789            let mut btree = BTreeMap::new();
790            while let Some((key, value)) = mapping.next_entry::<U256, U256>()? {
791                btree.insert(B256::from(key), B256::from(value));
792            }
793
794            Ok(btree)
795        }
796    }
797
798    deserializer.deserialize_map(BTreeVisitor)
799}
800
801/// Defines a backwards-compatible enum for transactions.
802/// This is essential for maintaining compatibility with state dumps
803/// created before the changes introduced in PR #8411.
804///
805/// The enum can represent either a `TypedTransaction` or a `MaybeImpersonatedTransaction`,
806/// depending on the data being deserialized. This flexibility ensures that older state
807/// dumps can still be loaded correctly, even after the changes in #8411.
808#[derive(Clone, Debug, Serialize, Deserialize)]
809#[serde(untagged)]
810pub enum SerializableTransactionType {
811    TypedTransaction(FoundryTxEnvelope),
812    MaybeImpersonatedTransaction(MaybeImpersonatedTransaction<FoundryTxEnvelope>),
813}
814
815#[derive(Clone, Debug, Serialize, Deserialize)]
816pub struct SerializableBlock {
817    pub header: FoundryHeader,
818    pub transactions: Vec<SerializableTransactionType>,
819    pub ommers: Vec<FoundryHeader>,
820    #[serde(default)]
821    pub withdrawals: Option<Withdrawals>,
822}
823
824impl From<Block> for SerializableBlock {
825    fn from(block: Block) -> Self {
826        Self {
827            header: block.header,
828            transactions: block.body.transactions.into_iter().map(Into::into).collect(),
829            ommers: block.body.ommers.into_iter().collect(),
830            withdrawals: block.body.withdrawals,
831        }
832    }
833}
834
835impl From<SerializableBlock> for Block {
836    fn from(block: SerializableBlock) -> Self {
837        let transactions = block.transactions.into_iter().map(Into::into).collect();
838        let ommers = block.ommers;
839        let body = BlockBody { transactions, ommers, withdrawals: block.withdrawals };
840        Self::new(block.header, body)
841    }
842}
843
844impl From<MaybeImpersonatedTransaction<FoundryTxEnvelope>> for SerializableTransactionType {
845    fn from(transaction: MaybeImpersonatedTransaction<FoundryTxEnvelope>) -> Self {
846        Self::MaybeImpersonatedTransaction(transaction)
847    }
848}
849
850impl From<SerializableTransactionType> for MaybeImpersonatedTransaction<FoundryTxEnvelope> {
851    fn from(transaction: SerializableTransactionType) -> Self {
852        match transaction {
853            SerializableTransactionType::TypedTransaction(tx) => Self::new(tx),
854            SerializableTransactionType::MaybeImpersonatedTransaction(tx) => tx,
855        }
856    }
857}
858
859#[derive(Clone, Debug, Serialize, Deserialize)]
860pub struct SerializableTransaction {
861    pub info: TransactionInfo,
862    pub receipt: FoundryReceiptEnvelope,
863    pub block_hash: B256,
864    pub block_number: u64,
865}
866
867impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> From<MinedTransaction<N>>
868    for SerializableTransaction
869{
870    fn from(transaction: MinedTransaction<N>) -> Self {
871        Self {
872            info: transaction.info,
873            receipt: transaction.receipt,
874            block_hash: transaction.block_hash,
875            block_number: transaction.block_number,
876        }
877    }
878}
879
880impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> From<SerializableTransaction>
881    for MinedTransaction<N>
882{
883    fn from(transaction: SerializableTransaction) -> Self {
884        Self {
885            info: transaction.info,
886            receipt: transaction.receipt,
887            block_hash: transaction.block_hash,
888            block_number: transaction.block_number,
889        }
890    }
891}
892
893#[derive(Clone, Debug, Serialize, Deserialize, Default)]
894pub struct SerializableHistoricalStates(Vec<(B256, StateSnapshot)>);
895
896impl SerializableHistoricalStates {
897    pub const fn new(states: Vec<(B256, StateSnapshot)>) -> Self {
898        Self(states)
899    }
900}
901
902impl IntoIterator for SerializableHistoricalStates {
903    type Item = (B256, StateSnapshot);
904    type IntoIter = std::vec::IntoIter<Self::Item>;
905
906    fn into_iter(self) -> Self::IntoIter {
907        self.0.into_iter()
908    }
909}
910
911#[cfg(test)]
912mod test {
913    use super::*;
914    use std::fs;
915
916    #[test]
917    fn loads_state_from_file_or_directory() {
918        let tmp = tempfile::tempdir().unwrap();
919        let state_path = tmp.path().join("state.json");
920        fs::write(&state_path, serde_json::to_vec(&SerializableState::default()).unwrap()).unwrap();
921
922        assert!(SerializableState::load(&state_path).unwrap().accounts.is_empty());
923        assert!(SerializableState::load(tmp.path()).unwrap().accounts.is_empty());
924
925        fs::write(&state_path, b"not json").unwrap();
926        let Err(FsPathError::ReadJson { path, .. }) = SerializableState::load(tmp.path()) else {
927            panic!("expected invalid JSON error")
928        };
929        assert_eq!(path, state_path);
930
931        let missing_path = tmp.path().join("missing.json");
932        let Err(FsPathError::Read { path, .. }) = SerializableState::load(&missing_path) else {
933            panic!("expected file read error")
934        };
935        assert_eq!(path, missing_path);
936    }
937
938    #[test]
939    fn cache_db_full_state_merges_base_and_overlay() {
940        let preserved = Address::with_last_byte(1);
941        let updated = Address::with_last_byte(2);
942        let deleted = Address::with_last_byte(3);
943        let cleared = Address::with_last_byte(4);
944        let deleted_slot = U256::from(1);
945        let updated_slot = U256::from(2);
946
947        let mut base = MemDb::default();
948        base.insert_account(preserved, AccountInfo::from_balance(U256::from(1)));
949        base.insert_account(updated, AccountInfo::from_balance(U256::from(2)));
950        base.set_storage_at(updated, deleted_slot.into(), B256::from(U256::from(10))).unwrap();
951        base.set_storage_at(updated, updated_slot.into(), B256::from(U256::from(11))).unwrap();
952        base.insert_account(deleted, AccountInfo::from_balance(U256::from(3)));
953        base.insert_account(cleared, AccountInfo::from_balance(U256::from(4)));
954        base.set_storage_at(cleared, deleted_slot.into(), B256::from(U256::from(11))).unwrap();
955
956        let mut cache = CacheDB::new(base);
957        cache.insert_account_info(updated, AccountInfo::from_balance(U256::from(20)));
958        cache.insert_account_storage(updated, deleted_slot, U256::ZERO).unwrap();
959        cache.insert_account_storage(updated, updated_slot, U256::from(12)).unwrap();
960        cache.cache.accounts.insert(
961            deleted,
962            DbAccount { account_state: AccountState::NotExisting, ..Default::default() },
963        );
964        cache.cache.accounts.insert(
965            cleared,
966            DbAccount {
967                info: AccountInfo::from_balance(U256::from(40)),
968                account_state: AccountState::StorageCleared,
969                ..Default::default()
970            },
971        );
972
973        let accounts = cache.maybe_full_db().unwrap();
974        assert_eq!(accounts[&preserved].info.balance, U256::from(1));
975        assert_eq!(accounts[&updated].info.balance, U256::from(20));
976        assert_eq!(accounts[&updated].storage[&deleted_slot], U256::ZERO);
977        assert_eq!(accounts[&updated].storage[&updated_slot], U256::from(12));
978        assert!(!accounts.contains_key(&deleted));
979        assert!(accounts[&cleared].storage.is_empty());
980        let mut expected = accounts;
981        expected.get_mut(&updated).unwrap().storage.remove(&deleted_slot);
982        assert_eq!(
983            cache.maybe_full_db().map(|accounts| crate::mem::state::state_root(&accounts)),
984            Some(crate::mem::state::state_root(&expected))
985        );
986    }
987
988    #[test]
989    fn test_deser_block() {
990        let block = r#"{
991            "header": {
992                "parentHash": "0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929",
993                "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
994                "miner": "0x0000000000000000000000000000000000000000",
995                "stateRoot": "0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1",
996                "transactionsRoot": "0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988",
997                "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
998                "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
999                "difficulty": "0x0",
1000                "number": "0x2",
1001                "gasLimit": "0x1c9c380",
1002                "gasUsed": "0x5208",
1003                "timestamp": "0x66cdc823",
1004                "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1005                "nonce": "0x0000000000000000",
1006                "baseFeePerGas": "0x342a1c58",
1007                "blobGasUsed": "0x0",
1008                "excessBlobGas": "0x0",
1009                "extraData": "0x"
1010            },
1011            "transactions": [
1012                {
1013                    "type": "0x2",
1014                    "chainId": "0x7a69",
1015                    "nonce": "0x0",
1016                    "gas": "0x5209",
1017                    "maxFeePerGas": "0x77359401",
1018                    "maxPriorityFeePerGas": "0x1",
1019                    "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
1020                    "value": "0x0",
1021                    "accessList": [],
1022                    "input": "0x",
1023                    "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0",
1024                    "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd",
1025                    "yParity": "0x0",
1026                    "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"
1027                }
1028            ],
1029            "ommers": []
1030        }
1031        "#;
1032
1033        let _block: SerializableBlock = serde_json::from_str(block).unwrap();
1034    }
1035
1036    #[test]
1037    fn test_block_withdrawals_preserved() {
1038        use alloy_eips::eip4895::Withdrawal;
1039
1040        // create a block with withdrawals (like post-Shanghai blocks)
1041        let withdrawal = Withdrawal {
1042            index: 42,
1043            validator_index: 123,
1044            address: Address::repeat_byte(1),
1045            amount: 1000,
1046        };
1047
1048        let header = Header::default();
1049        let body = BlockBody {
1050            transactions: vec![],
1051            ommers: vec![],
1052            withdrawals: Some(vec![withdrawal].into()),
1053        };
1054        let block = Block::new(header.into(), body);
1055
1056        // convert to SerializableBlock and back
1057        let serializable = SerializableBlock::from(block);
1058        let restored = Block::from(serializable);
1059
1060        // withdrawals should be preserved
1061        assert!(restored.body.withdrawals.is_some());
1062        let withdrawals = restored.body.withdrawals.unwrap();
1063        assert_eq!(withdrawals.len(), 1);
1064        assert_eq!(withdrawals[0].index, 42);
1065        assert_eq!(withdrawals[0].validator_index, 123);
1066    }
1067}