1use crate::mem::storage::MinedTransaction;
4use alloy_consensus::BlockBody;
5use alloy_eips::{eip4895::Withdrawals, eip7928::BlockAccessList};
6use alloy_evm::block::BalIndexedDatabase;
7use alloy_network::Network;
8use alloy_primitives::{
9 Address, B256, Bytes, U256, keccak256,
10 map::{AddressMap, HashMap, U256Map},
11};
12use alloy_rpc_types::BlockId;
13use anvil_core::eth::{
14 block::Block,
15 transaction::{MaybeImpersonatedTransaction, TransactionInfo},
16};
17use foundry_common::errors::FsPathError;
18use foundry_evm::backend::{
19 BlockchainDb, DatabaseError, DatabaseResult, EmptyDBWrapper, MemDb, RevertStateSnapshotAction,
20 StateSnapshot, existing_account,
21};
22use foundry_primitives::{FoundryHeader, FoundryReceiptEnvelope, FoundryTxEnvelope};
23use revm::{
24 Database, DatabaseCommit,
25 bytecode::Bytecode,
26 context::BlockEnv,
27 context_interface::block::BlobExcessGasAndPrice,
28 database::{AccountState, CacheDB, DatabaseRef, DbAccount, bal::BalState},
29 primitives::{KECCAK_EMPTY, eip4844::BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE, hardfork::SpecId},
30 state::{AccountInfo, bal::BlockAccessIndex},
31};
32use serde::{
33 Deserialize, Deserializer, Serialize,
34 de::{Error as DeError, MapAccess, Visitor},
35};
36use serde_json::Value;
37use std::{
38 collections::BTreeMap,
39 fmt::{self, Debug},
40 fs::File,
41 io::BufReader,
42 path::Path,
43};
44
45pub(crate) const BLOCKHASH_HISTORY: u64 = 256;
47
48#[cfg(feature = "monad")]
50#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
51pub struct MonadBlockReplayProfile {
52 pub execution_chain_id: u64,
54 pub hardfork: foundry_evm::hardfork::MonadHardfork,
56}
57
58pub(crate) fn cache_block_hash(block_hashes: &mut U256Map<B256>, number: U256, hash: B256) -> U256 {
60 let head = block_hashes.keys().copied().max().map_or(number, |head| head.max(number));
61 let min_number = head.saturating_sub(U256::from(BLOCKHASH_HISTORY));
62 block_hashes.retain(|cached, _| *cached >= min_number && *cached <= head);
63 if number >= min_number {
64 block_hashes.insert(number, hash);
65 }
66 head
67}
68
69pub trait MaybeFullDatabase: crate::mem::DatabaseRef + Send + Sync {
71 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
72 None
73 }
74
75 fn maybe_as_full_db_mut(&mut self) -> Option<&mut AddressMap<DbAccount>> {
76 None
77 }
78
79 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
81 self.maybe_as_full_db().cloned()
82 }
83
84 fn is_persistent(&self) -> bool {
86 false
87 }
88
89 fn clear_into_state_snapshot(&mut self) -> StateSnapshot;
91
92 fn read_as_state_snapshot(&self) -> StateSnapshot;
96
97 fn clear(&mut self);
99
100 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot);
102}
103
104pub type StateRef<'a> = &'a dyn MaybeFullDatabase;
106
107impl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T
108where
109 &'a T: DatabaseRef<Error = DatabaseError>,
110{
111 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
112 T::maybe_as_full_db(self)
113 }
114
115 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
116 T::maybe_full_db(self)
117 }
118
119 fn is_persistent(&self) -> bool {
120 T::is_persistent(self)
121 }
122
123 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
124 unreachable!("never called for DatabaseRef")
125 }
126
127 fn read_as_state_snapshot(&self) -> StateSnapshot {
128 unreachable!("never called for DatabaseRef")
129 }
130
131 fn clear(&mut self) {}
132
133 fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
134}
135
136impl<T: MaybeFullDatabase + ?Sized> MaybeFullDatabase for Box<T>
137where
138 Self: DatabaseRef<Error = DatabaseError>,
139{
140 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
141 T::maybe_as_full_db(self)
142 }
143
144 fn maybe_as_full_db_mut(&mut self) -> Option<&mut AddressMap<DbAccount>> {
145 T::maybe_as_full_db_mut(self)
146 }
147
148 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
149 T::maybe_full_db(self)
150 }
151
152 fn is_persistent(&self) -> bool {
153 T::is_persistent(self)
154 }
155
156 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
157 T::clear_into_state_snapshot(self)
158 }
159
160 fn read_as_state_snapshot(&self) -> StateSnapshot {
161 T::read_as_state_snapshot(self)
162 }
163
164 fn clear(&mut self) {
165 T::clear(self)
166 }
167
168 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
169 T::init_from_state_snapshot(self, state_snapshot)
170 }
171}
172
173pub trait MaybeForkedDatabase {
175 fn maybe_reset(&mut self, _urls: Vec<String>, block_number: BlockId) -> Result<(), String>;
176
177 fn maybe_flush_cache(&self) -> Result<(), String>;
178
179 fn maybe_inner(&self) -> Result<&BlockchainDb, String>;
180}
181
182impl alloy_evm::Database for dyn Db {}
185
186#[derive(Debug)]
188pub struct AnvilCacheDB<T>(pub CacheDB<T>, BalState, SpecId);
189
190impl<T: DatabaseRef<Error = DatabaseError>> AnvilCacheDB<T> {
191 pub fn new(inner: T, spec: SpecId) -> Self {
192 Self(CacheDB::new(inner), BalState::new(), spec)
193 }
194
195 pub fn enable_bal_recording(&mut self) {
197 self.1 = BalState::new().with_bal_builder();
198 }
199
200 pub fn take_block_access_list(&mut self) -> Option<BlockAccessList> {
202 self.1.take_built_alloy_bal()
203 }
204}
205
206impl<T: DatabaseRef<Error = DatabaseError>> std::ops::Deref for AnvilCacheDB<T> {
207 type Target = CacheDB<T>;
208 fn deref(&self) -> &Self::Target {
209 &self.0
210 }
211}
212
213impl<T: DatabaseRef<Error = DatabaseError>> std::ops::DerefMut for AnvilCacheDB<T> {
214 fn deref_mut(&mut self) -> &mut Self::Target {
215 &mut self.0
216 }
217}
218
219impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> Database for AnvilCacheDB<T> {
220 type Error = DatabaseError;
221
222 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
223 Ok(existing_account(self.2, self.0.basic(address)?))
224 }
225
226 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
227 self.0.code_by_hash(code_hash)
228 }
229
230 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
231 self.0.storage(address, index)
232 }
233
234 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
235 self.0.block_hash(number)
236 }
237}
238
239impl<T: DatabaseRef<Error = DatabaseError>> DatabaseRef for AnvilCacheDB<T> {
240 type Error = DatabaseError;
241
242 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
243 self.0.basic_ref(address)
244 }
245
246 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
247 self.0.code_by_hash_ref(code_hash)
248 }
249
250 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
251 self.0.storage_ref(address, index)
252 }
253
254 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
255 self.0.block_hash_ref(number)
256 }
257}
258
259impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> DatabaseCommit for AnvilCacheDB<T> {
260 fn commit(&mut self, changes: revm::state::EvmState) {
261 self.1.commit(&changes);
262 self.0.commit(changes)
263 }
264}
265
266impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> BalIndexedDatabase for AnvilCacheDB<T> {
267 fn set_bal_index(&mut self, index: u64) {
268 self.1.bal_index = BlockAccessIndex::new(index);
269 }
270
271 fn bump_bal_index(&mut self) {
272 self.1.bump_bal_index();
273 }
274}
275
276impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> BalIndexedDatabase
277 for &mut AnvilCacheDB<T>
278{
279 fn set_bal_index(&mut self, index: u64) {
280 (**self).set_bal_index(index);
281 }
282
283 fn bump_bal_index(&mut self) {
284 (**self).bump_bal_index();
285 }
286}
287
288#[derive(Debug)]
296pub(super) struct EmptyAsAbsentDb<T>(pub(super) T);
297
298impl<T: DatabaseRef> DatabaseRef for EmptyAsAbsentDb<T> {
299 type Error = T::Error;
300
301 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
302 Ok(self.0.basic_ref(address)?.filter(|info| !info.is_empty()))
303 }
304
305 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
306 self.0.code_by_hash_ref(code_hash)
307 }
308
309 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
310 self.0.storage_ref(address, index)
311 }
312
313 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
314 self.0.block_hash_ref(number)
315 }
316}
317
318pub trait Db:
320 Database<Error = DatabaseError>
321 + DatabaseCommit
322 + MaybeFullDatabase
323 + MaybeForkedDatabase
324 + Send
325 + Sync
326{
327 fn insert_account(&mut self, address: Address, account: AccountInfo);
329
330 fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {
332 let mut info = self.basic(address)?.unwrap_or_default();
333 info.nonce = nonce;
334 self.insert_account(address, info);
335 Ok(())
336 }
337
338 fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {
340 let mut info = self.basic(address)?.unwrap_or_default();
341 info.balance = balance;
342 self.insert_account(address, info);
343 Ok(())
344 }
345
346 fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {
348 let mut info = self.basic(address)?.unwrap_or_default();
349 let code_hash = if code.as_ref().is_empty() {
350 KECCAK_EMPTY
351 } else {
352 B256::from_slice(&keccak256(code.as_ref())[..])
353 };
354 info.code_hash = code_hash;
355 info.code = Some(Bytecode::new_raw(code));
356 self.insert_account(address, info);
357 Ok(())
358 }
359
360 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;
362
363 fn insert_block_hash(&mut self, number: U256, hash: B256);
365
366 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>);
368
369 fn dump_state(
371 &self,
372 at: BlockEnv,
373 best_number: u64,
374 blocks: Vec<SerializableBlock>,
375 transactions: Vec<SerializableTransaction>,
376 historical_states: Option<SerializableHistoricalStates>,
377 ) -> DatabaseResult<Option<SerializableState>>;
378
379 fn load_state(&mut self, state: SerializableState) -> DatabaseResult<bool> {
381 for (addr, account) in state.accounts {
382 let old_account_nonce =
383 DatabaseRef::basic_ref(self, addr)?.map(|acc| acc.nonce).unwrap_or_default();
384 let nonce = std::cmp::max(old_account_nonce, account.nonce);
387
388 self.insert_account(
389 addr,
390 AccountInfo {
391 balance: account.balance,
392 code_hash: KECCAK_EMPTY, code: if account.code.0.is_empty() {
394 None
395 } else {
396 Some(Bytecode::new_raw(account.code))
397 },
398 nonce,
399 account_id: None,
400 },
401 );
402
403 for (k, v) in account.storage {
404 self.set_storage_at(addr, k, v)?;
405 }
406 }
407 Ok(true)
408 }
409
410 fn snapshot_state(&mut self) -> U256;
412
413 fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;
417
418 fn delete_state_snapshot(&mut self, state_snapshot: U256) -> bool;
420
421 fn maybe_state_root(&self) -> Option<B256> {
423 None
424 }
425
426 fn current_state(&self) -> StateDb;
428
429 fn historical_state(&self, state_snapshot: StateSnapshot) -> StateDb {
431 let mut state = StateDb::new(MemDb::default());
432 state.init_from_state_snapshot(state_snapshot);
433 state
434 }
435}
436
437impl<T> Db for CacheDB<T>
442where
443 T: DatabaseRef<Error = DatabaseError> + MaybeFullDatabase + Send + Sync + Clone + fmt::Debug,
444{
445 fn insert_account(&mut self, address: Address, account: AccountInfo) {
446 self.insert_account_info(address, account)
447 }
448
449 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
450 self.insert_account_storage(address, slot.into(), val.into())
451 }
452
453 fn insert_block_hash(&mut self, number: U256, hash: B256) {
454 cache_block_hash(&mut self.cache.block_hashes, number, hash);
455 }
456
457 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>) {
458 self.cache.block_hashes = block_hashes.into_iter().collect();
459 }
460
461 fn dump_state(
462 &self,
463 _at: BlockEnv,
464 _best_number: u64,
465 _blocks: Vec<SerializableBlock>,
466 _transaction: Vec<SerializableTransaction>,
467 _historical_states: Option<SerializableHistoricalStates>,
468 ) -> DatabaseResult<Option<SerializableState>> {
469 Ok(None)
470 }
471
472 fn snapshot_state(&mut self) -> U256 {
473 U256::ZERO
474 }
475
476 fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {
477 false
478 }
479
480 fn delete_state_snapshot(&mut self, _state_snapshot: U256) -> bool {
481 false
482 }
483
484 fn maybe_state_root(&self) -> Option<B256> {
485 self.maybe_full_db().map(|accounts| crate::mem::state::state_root(&accounts))
486 }
487
488 fn current_state(&self) -> StateDb {
489 StateDb::new(MemDb::default())
490 }
491}
492
493impl<T: MaybeFullDatabase> MaybeFullDatabase for CacheDB<T> {
494 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
495 Some(&self.cache.accounts)
496 }
497
498 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
499 let mut accounts = self.db.maybe_full_db()?;
500 for (address, overlay) in &self.cache.accounts {
501 if overlay.account_state == AccountState::NotExisting {
502 accounts.remove(address);
503 continue;
504 }
505 if overlay.account_state.is_storage_cleared() {
506 accounts.insert(*address, overlay.clone());
507 continue;
508 }
509
510 let mut account = accounts.remove(address).unwrap_or_default();
511 account.info = overlay.info.clone();
512 account.account_state = overlay.account_state.clone();
513 account.storage.extend(overlay.storage.clone());
514 accounts.insert(*address, account);
515 }
516 Some(accounts)
517 }
518
519 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
520 let db_accounts = std::mem::take(&mut self.cache.accounts);
521 let mut accounts = HashMap::default();
522 let mut account_storage = HashMap::default();
523 let mut account_states = HashMap::default();
524
525 for (addr, mut acc) in db_accounts {
526 account_storage.insert(addr, std::mem::take(&mut acc.storage));
527 if matches!(acc.account_state, AccountState::NotExisting | AccountState::StorageCleared)
528 {
529 account_states.insert(addr, acc.account_state);
530 }
531 let mut info = acc.info;
532 info.code = self.cache.contracts.remove(&info.code_hash());
533 accounts.insert(addr, info);
534 }
535 let block_hashes = std::mem::take(&mut self.cache.block_hashes);
536 StateSnapshot {
537 accounts,
538 storage: account_storage,
539 block_hashes,
540 account_states: Some(account_states),
541 }
542 }
543
544 fn read_as_state_snapshot(&self) -> StateSnapshot {
545 let mut accounts = HashMap::default();
546 let mut account_storage = HashMap::default();
547 let mut account_states = HashMap::default();
548
549 for (addr, acc) in &self.cache.accounts {
550 account_storage.insert(*addr, acc.storage.clone());
551 if matches!(acc.account_state, AccountState::NotExisting | AccountState::StorageCleared)
552 {
553 account_states.insert(*addr, acc.account_state.clone());
554 }
555 let mut info = acc.info.clone();
556 info.code = self.cache.contracts.get(&info.code_hash()).cloned();
557 accounts.insert(*addr, info);
558 }
559
560 let block_hashes = self.cache.block_hashes.clone();
561 StateSnapshot {
562 accounts,
563 storage: account_storage,
564 block_hashes,
565 account_states: Some(account_states),
566 }
567 }
568
569 fn clear(&mut self) {
570 self.clear_into_state_snapshot();
571 }
572
573 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
574 let StateSnapshot { accounts, mut storage, block_hashes, account_states } = state_snapshot;
575 let mut account_states = account_states.unwrap_or_default();
576
577 for (addr, mut acc) in accounts {
578 if let Some(code) = acc.code.take() {
579 self.cache.contracts.insert(acc.code_hash(), code);
580 }
581 self.cache.accounts.insert(
582 addr,
583 DbAccount {
584 info: acc,
585 account_state: account_states.remove(&addr).unwrap_or_default(),
586 storage: storage.remove(&addr).unwrap_or_default(),
587 },
588 );
589 }
590 self.cache.block_hashes = block_hashes;
591 }
592}
593
594impl MaybeFullDatabase for EmptyDBWrapper {
595 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
596 StateSnapshot::default()
597 }
598
599 fn read_as_state_snapshot(&self) -> StateSnapshot {
600 StateSnapshot::default()
601 }
602
603 fn clear(&mut self) {}
604
605 fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
606}
607
608impl<T: DatabaseRef<Error = DatabaseError>> MaybeForkedDatabase for CacheDB<T> {
609 fn maybe_reset(&mut self, _urls: Vec<String>, _block_number: BlockId) -> Result<(), String> {
610 Err("not supported".to_string())
611 }
612
613 fn maybe_flush_cache(&self) -> Result<(), String> {
614 Err("not supported".to_string())
615 }
616
617 fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
618 Err("not supported".to_string())
619 }
620}
621
622#[derive(Debug)]
624pub struct StateDb(pub(crate) Box<dyn MaybeFullDatabase>);
625
626impl StateDb {
627 pub fn new(db: impl MaybeFullDatabase + 'static) -> Self {
628 Self(Box::new(db))
629 }
630
631 pub fn serialize_state(&mut self) -> StateSnapshot {
632 self.read_as_state_snapshot()
635 }
636}
637
638impl DatabaseRef for StateDb {
639 type Error = DatabaseError;
640 fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {
641 self.0.basic_ref(address)
642 }
643
644 fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {
645 self.0.code_by_hash_ref(code_hash)
646 }
647
648 fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
649 self.0.storage_ref(address, index)
650 }
651
652 fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {
653 self.0.block_hash_ref(number)
654 }
655}
656
657impl MaybeFullDatabase for StateDb {
658 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
659 self.0.maybe_as_full_db()
660 }
661
662 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
663 self.0.maybe_full_db()
664 }
665
666 fn is_persistent(&self) -> bool {
667 self.0.is_persistent()
668 }
669
670 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
671 self.0.clear_into_state_snapshot()
672 }
673
674 fn read_as_state_snapshot(&self) -> StateSnapshot {
675 self.0.read_as_state_snapshot()
676 }
677
678 fn clear(&mut self) {
679 self.0.clear()
680 }
681
682 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
683 self.0.init_from_state_snapshot(state_snapshot)
684 }
685}
686
687#[derive(Debug, Deserialize)]
689#[serde(rename_all = "snake_case")]
690pub struct LegacyBlockEnv {
691 pub number: Option<StringOrU64>,
692 #[serde(alias = "coinbase")]
693 pub beneficiary: Option<Address>,
694 pub timestamp: Option<StringOrU64>,
695 pub gas_limit: Option<StringOrU64>,
696 pub basefee: Option<StringOrU64>,
697 pub difficulty: Option<StringOrU64>,
698 pub prevrandao: Option<B256>,
699 pub blob_excess_gas_and_price: Option<LegacyBlobExcessGasAndPrice>,
700}
701
702#[derive(Debug, Deserialize)]
704pub struct LegacyBlobExcessGasAndPrice {
705 pub excess_blob_gas: u64,
706 pub blob_gasprice: u128,
707}
708
709#[derive(Debug, Deserialize)]
711#[serde(untagged)]
712pub enum StringOrU64 {
713 Hex(String),
714 Dec(u64),
715}
716
717impl StringOrU64 {
718 pub fn to_u64(&self) -> Option<u64> {
719 match self {
720 Self::Dec(n) => Some(*n),
721 Self::Hex(s) => s.strip_prefix("0x").and_then(|s| u64::from_str_radix(s, 16).ok()),
722 }
723 }
724
725 pub fn to_u256(&self) -> Option<U256> {
726 match self {
727 Self::Dec(n) => Some(U256::from(*n)),
728 Self::Hex(s) => s.strip_prefix("0x").and_then(|s| U256::from_str_radix(s, 16).ok()),
729 }
730 }
731}
732
733impl TryFrom<LegacyBlockEnv> for BlockEnv {
735 type Error = &'static str;
736
737 fn try_from(legacy: LegacyBlockEnv) -> Result<Self, Self::Error> {
738 Ok(Self {
739 number: legacy.number.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),
740 beneficiary: legacy.beneficiary.unwrap_or(Address::ZERO),
741 timestamp: legacy.timestamp.and_then(|v| v.to_u256()).unwrap_or(U256::ONE),
742 gas_limit: legacy.gas_limit.and_then(|v| v.to_u64()).unwrap_or(u64::MAX),
743 basefee: legacy.basefee.and_then(|v| v.to_u64()).unwrap_or(0),
744 difficulty: legacy.difficulty.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),
745 prevrandao: legacy.prevrandao.or(Some(B256::ZERO)),
746 slot_num: 0,
747 blob_excess_gas_and_price: legacy
748 .blob_excess_gas_and_price
749 .map(|v| BlobExcessGasAndPrice {
750 excess_blob_gas: v.excess_blob_gas,
751 blob_gasprice: v.blob_gasprice,
752 })
753 .or_else(|| {
754 Some(BlobExcessGasAndPrice::new(0, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE))
755 }),
756 })
757 }
758}
759
760fn deserialize_block_env_compat<'de, D>(deserializer: D) -> Result<Option<BlockEnv>, D::Error>
762where
763 D: Deserializer<'de>,
764{
765 let value: Option<Value> = Option::deserialize(deserializer)?;
766 let Some(value) = value else {
767 return Ok(None);
768 };
769
770 if let Ok(env) = BlockEnv::deserialize(&value) {
771 return Ok(Some(env));
772 }
773
774 let legacy: LegacyBlockEnv = serde_json::from_value(value).map_err(|e| {
775 D::Error::custom(format!("Legacy deserialization of `BlockEnv` failed: {e}"))
776 })?;
777
778 Ok(Some(BlockEnv::try_from(legacy).map_err(D::Error::custom)?))
779}
780
781fn deserialize_best_block_number_compat<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
783where
784 D: Deserializer<'de>,
785{
786 let value: Option<Value> = Option::deserialize(deserializer)?;
787 let Some(value) = value else {
788 return Ok(None);
789 };
790
791 let number = match value {
792 Value::Number(n) => n.as_u64(),
793 Value::String(s) => {
794 if let Some(s) = s.strip_prefix("0x") {
795 u64::from_str_radix(s, 16).ok()
796 } else {
797 s.parse().ok()
798 }
799 }
800 _ => None,
801 };
802
803 Ok(number)
804}
805
806#[derive(Clone, Debug, Default, Serialize, Deserialize)]
807pub struct SerializableState {
808 #[serde(deserialize_with = "deserialize_block_env_compat")]
812 pub block: Option<BlockEnv>,
813 pub accounts: BTreeMap<Address, SerializableAccountRecord>,
814 #[serde(deserialize_with = "deserialize_best_block_number_compat")]
816 pub best_block_number: Option<u64>,
817 #[serde(default)]
818 pub blocks: Vec<SerializableBlock>,
819 #[serde(default)]
820 pub transactions: Vec<SerializableTransaction>,
821 #[cfg(feature = "monad")]
826 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
827 pub monad_block_participants: BTreeMap<B256, std::collections::BTreeSet<Address>>,
828 #[cfg(feature = "monad")]
830 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
831 pub monad_block_replay_profiles: BTreeMap<B256, MonadBlockReplayProfile>,
832 #[serde(default)]
836 pub historical_states: Option<SerializableHistoricalStates>,
837}
838
839impl SerializableState {
840 pub fn load(path: impl AsRef<Path>) -> Result<Self, FsPathError> {
842 let mut path = path.as_ref().to_path_buf();
843 if path.is_dir() {
844 path = path.join("state.json");
845 }
846
847 let file = File::open(&path).map_err(|err| FsPathError::read(err, &path))?;
848 serde_json::from_reader(BufReader::new(file)).map_err(|err| {
849 if err.is_io() {
850 FsPathError::read(err.into(), &path)
851 } else {
852 FsPathError::ReadJson { source: err, path }
853 }
854 })
855 }
856
857 #[cfg(feature = "cmd")]
859 pub(crate) fn parse(path: &str) -> Result<Self, String> {
860 Self::load(path).map_err(|err| err.to_string())
861 }
862}
863
864#[derive(Clone, Debug, Serialize, Deserialize)]
865pub struct SerializableAccountRecord {
866 pub nonce: u64,
867 pub balance: U256,
868 pub code: Bytes,
869
870 #[serde(deserialize_with = "deserialize_btree")]
871 pub storage: BTreeMap<B256, B256>,
872}
873
874fn deserialize_btree<'de, D>(deserializer: D) -> Result<BTreeMap<B256, B256>, D::Error>
875where
876 D: Deserializer<'de>,
877{
878 struct BTreeVisitor;
879
880 impl<'de> Visitor<'de> for BTreeVisitor {
881 type Value = BTreeMap<B256, B256>;
882
883 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
884 formatter.write_str("a mapping of hex encoded storage slots to hex encoded state data")
885 }
886
887 fn visit_map<M>(self, mut mapping: M) -> Result<BTreeMap<B256, B256>, M::Error>
888 where
889 M: MapAccess<'de>,
890 {
891 let mut btree = BTreeMap::new();
892 while let Some((key, value)) = mapping.next_entry::<U256, U256>()? {
893 btree.insert(B256::from(key), B256::from(value));
894 }
895
896 Ok(btree)
897 }
898 }
899
900 deserializer.deserialize_map(BTreeVisitor)
901}
902
903#[derive(Clone, Debug, Serialize, Deserialize)]
911#[serde(untagged)]
912pub enum SerializableTransactionType {
913 TypedTransaction(FoundryTxEnvelope),
914 MaybeImpersonatedTransaction(MaybeImpersonatedTransaction<FoundryTxEnvelope>),
915}
916
917#[derive(Clone, Debug, Serialize, Deserialize)]
918pub struct SerializableBlock {
919 pub header: FoundryHeader,
920 pub transactions: Vec<SerializableTransactionType>,
921 pub ommers: Vec<FoundryHeader>,
922 #[serde(default)]
923 pub withdrawals: Option<Withdrawals>,
924}
925
926impl From<Block> for SerializableBlock {
927 fn from(block: Block) -> Self {
928 Self {
929 header: block.header,
930 transactions: block.body.transactions.into_iter().map(Into::into).collect(),
931 ommers: block.body.ommers.into_iter().collect(),
932 withdrawals: block.body.withdrawals,
933 }
934 }
935}
936
937impl From<SerializableBlock> for Block {
938 fn from(block: SerializableBlock) -> Self {
939 let transactions = block.transactions.into_iter().map(Into::into).collect();
940 let ommers = block.ommers;
941 let body = BlockBody { transactions, ommers, withdrawals: block.withdrawals };
942 Self::new(block.header, body)
943 }
944}
945
946impl From<MaybeImpersonatedTransaction<FoundryTxEnvelope>> for SerializableTransactionType {
947 fn from(transaction: MaybeImpersonatedTransaction<FoundryTxEnvelope>) -> Self {
948 Self::MaybeImpersonatedTransaction(transaction)
949 }
950}
951
952impl From<SerializableTransactionType> for MaybeImpersonatedTransaction<FoundryTxEnvelope> {
953 fn from(transaction: SerializableTransactionType) -> Self {
954 match transaction {
955 SerializableTransactionType::TypedTransaction(tx) => Self::new(tx),
956 SerializableTransactionType::MaybeImpersonatedTransaction(tx) => tx,
957 }
958 }
959}
960
961#[derive(Clone, Debug, Serialize, Deserialize)]
962pub struct SerializableTransaction {
963 pub info: TransactionInfo,
964 pub receipt: FoundryReceiptEnvelope,
965 pub block_hash: B256,
966 pub block_number: u64,
967}
968
969impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> From<MinedTransaction<N>>
970 for SerializableTransaction
971{
972 fn from(transaction: MinedTransaction<N>) -> Self {
973 Self {
974 info: transaction.info,
975 receipt: transaction.receipt,
976 block_hash: transaction.block_hash,
977 block_number: transaction.block_number,
978 }
979 }
980}
981
982impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> From<SerializableTransaction>
983 for MinedTransaction<N>
984{
985 fn from(transaction: SerializableTransaction) -> Self {
986 Self {
987 info: transaction.info,
988 receipt: transaction.receipt,
989 block_hash: transaction.block_hash,
990 block_number: transaction.block_number,
991 }
992 }
993}
994
995#[derive(Clone, Debug, Serialize, Deserialize, Default)]
996pub struct SerializableHistoricalStates(Vec<(B256, StateSnapshot)>);
997
998impl SerializableHistoricalStates {
999 pub const fn new(states: Vec<(B256, StateSnapshot)>) -> Self {
1000 Self(states)
1001 }
1002}
1003
1004impl IntoIterator for SerializableHistoricalStates {
1005 type Item = (B256, StateSnapshot);
1006 type IntoIter = std::vec::IntoIter<Self::Item>;
1007
1008 fn into_iter(self) -> Self::IntoIter {
1009 self.0.into_iter()
1010 }
1011}
1012
1013#[cfg(test)]
1014mod test {
1015 use super::*;
1016 use crate::eth::backend::mem::fork_db::ForkedDatabase;
1017 use alloy_consensus::Header;
1018 use alloy_network::AnyNetwork;
1019 use alloy_provider::ProviderBuilder;
1020 use alloy_transport::mock::Asserter;
1021 use foundry_evm::backend::{BlockchainDbMeta, SharedBackend};
1022 use std::fs;
1023
1024 #[test]
1025 fn loads_state_from_file_or_directory() {
1026 let tmp = tempfile::tempdir().unwrap();
1027 let state_path = tmp.path().join("state.json");
1028 fs::write(&state_path, serde_json::to_vec(&SerializableState::default()).unwrap()).unwrap();
1029
1030 assert!(SerializableState::load(&state_path).unwrap().accounts.is_empty());
1031 assert!(SerializableState::load(tmp.path()).unwrap().accounts.is_empty());
1032
1033 fs::write(&state_path, b"not json").unwrap();
1034 let Err(FsPathError::ReadJson { path, .. }) = SerializableState::load(tmp.path()) else {
1035 panic!("expected invalid JSON error")
1036 };
1037 assert_eq!(path, state_path);
1038
1039 let missing_path = tmp.path().join("missing.json");
1040 let Err(FsPathError::Read { path, .. }) = SerializableState::load(&missing_path) else {
1041 panic!("expected file read error")
1042 };
1043 assert_eq!(path, missing_path);
1044 }
1045
1046 #[test]
1047 fn cache_db_full_state_merges_base_and_overlay() {
1048 let preserved = Address::with_last_byte(1);
1049 let updated = Address::with_last_byte(2);
1050 let deleted = Address::with_last_byte(3);
1051 let cleared = Address::with_last_byte(4);
1052 let deleted_slot = U256::ONE;
1053 let updated_slot = U256::from(2);
1054
1055 let mut base = MemDb::default();
1056 base.insert_account(preserved, AccountInfo::from_balance(U256::ONE));
1057 base.insert_account(updated, AccountInfo::from_balance(U256::from(2)));
1058 base.set_storage_at(updated, deleted_slot.into(), B256::with_last_byte(10)).unwrap();
1059 base.set_storage_at(updated, updated_slot.into(), B256::with_last_byte(11)).unwrap();
1060 base.insert_account(deleted, AccountInfo::from_balance(U256::from(3)));
1061 base.insert_account(cleared, AccountInfo::from_balance(U256::from(4)));
1062 base.set_storage_at(cleared, deleted_slot.into(), B256::with_last_byte(11)).unwrap();
1063
1064 let mut cache = CacheDB::new(base);
1065 cache.insert_account_info(updated, AccountInfo::from_balance(U256::from(20)));
1066 cache.insert_account_storage(updated, deleted_slot, U256::ZERO).unwrap();
1067 cache.insert_account_storage(updated, updated_slot, U256::from(12)).unwrap();
1068 cache.cache.accounts.insert(deleted, DbAccount::new_not_existing());
1069 cache.cache.accounts.insert(
1070 cleared,
1071 DbAccount {
1072 info: AccountInfo::from_balance(U256::from(40)),
1073 account_state: AccountState::StorageCleared,
1074 ..Default::default()
1075 },
1076 );
1077
1078 let accounts = cache.maybe_full_db().unwrap();
1079 assert_eq!(accounts[&preserved].info.balance, U256::ONE);
1080 assert_eq!(accounts[&updated].info.balance, U256::from(20));
1081 assert_eq!(accounts[&updated].storage[&deleted_slot], U256::ZERO);
1082 assert_eq!(accounts[&updated].storage[&updated_slot], U256::from(12));
1083 assert!(!accounts.contains_key(&deleted));
1084 assert!(accounts[&cleared].storage.is_empty());
1085 let mut expected = accounts;
1086 expected.get_mut(&updated).unwrap().storage.remove(&deleted_slot);
1087 assert_eq!(
1088 cache.maybe_full_db().map(|accounts| crate::mem::state::state_root(&accounts)),
1089 Some(crate::mem::state::state_root(&expected))
1090 );
1091 }
1092
1093 #[test]
1094 fn cache_db_state_snapshot_preserves_account_states() {
1095 let touched = Address::with_last_byte(1);
1096 let deleted = Address::with_last_byte(2);
1097 let cleared = Address::with_last_byte(3);
1098 let (kept_slot, missing_slot) = (U256::ONE, U256::from(2));
1099 let base = || {
1101 let mut base = MemDb::default();
1102 for address in [touched, deleted, cleared] {
1103 base.insert_account(address, AccountInfo::from_balance(U256::ONE));
1104 base.set_storage_at(address, missing_slot.into(), B256::with_last_byte(9)).unwrap();
1105 }
1106 base
1107 };
1108
1109 let mut cache = CacheDB::new(base());
1110 cache.insert_account_storage(touched, kept_slot, U256::from(5)).unwrap();
1111 cache.cache.accounts.insert(deleted, DbAccount::new_not_existing());
1112 let mut cleared_account = DbAccount {
1113 info: AccountInfo::from_balance(U256::from(40)),
1114 account_state: AccountState::StorageCleared,
1115 ..Default::default()
1116 };
1117 cleared_account.storage.insert(kept_slot, U256::from(6));
1118 cache.cache.accounts.insert(cleared, cleared_account);
1119
1120 let snapshot = cache.read_as_state_snapshot();
1121 let mut restored = CacheDB::new(base());
1122 restored.init_from_state_snapshot(
1123 serde_json::from_str(&serde_json::to_string(&snapshot).unwrap()).unwrap(),
1124 );
1125
1126 assert_eq!(restored.storage_ref(touched, kept_slot).unwrap(), U256::from(5));
1127 assert_eq!(restored.storage_ref(touched, missing_slot).unwrap(), U256::from(9));
1128 assert_eq!(restored.basic_ref(deleted).unwrap(), None);
1129 assert_eq!(restored.storage_ref(deleted, missing_slot).unwrap(), U256::ZERO);
1130 assert_eq!(restored.basic_ref(cleared).unwrap().unwrap().balance, U256::from(40));
1131 assert_eq!(restored.storage_ref(cleared, kept_slot).unwrap(), U256::from(6));
1132 assert_eq!(restored.storage_ref(cleared, missing_slot).unwrap(), U256::ZERO);
1133 assert_eq!(restored.clear_into_state_snapshot().account_states, snapshot.account_states);
1134 }
1135
1136 #[test]
1137 fn test_deser_block() {
1138 let block = r#"{
1139 "header": {
1140 "parentHash": "0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929",
1141 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
1142 "miner": "0x0000000000000000000000000000000000000000",
1143 "stateRoot": "0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1",
1144 "transactionsRoot": "0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988",
1145 "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
1146 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1147 "difficulty": "0x0",
1148 "number": "0x2",
1149 "gasLimit": "0x1c9c380",
1150 "gasUsed": "0x5208",
1151 "timestamp": "0x66cdc823",
1152 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1153 "nonce": "0x0000000000000000",
1154 "baseFeePerGas": "0x342a1c58",
1155 "blobGasUsed": "0x0",
1156 "excessBlobGas": "0x0",
1157 "extraData": "0x"
1158 },
1159 "transactions": [
1160 {
1161 "type": "0x2",
1162 "chainId": "0x7a69",
1163 "nonce": "0x0",
1164 "gas": "0x5209",
1165 "maxFeePerGas": "0x77359401",
1166 "maxPriorityFeePerGas": "0x1",
1167 "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
1168 "value": "0x0",
1169 "accessList": [],
1170 "input": "0x",
1171 "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0",
1172 "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd",
1173 "yParity": "0x0",
1174 "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"
1175 }
1176 ],
1177 "ommers": []
1178 }
1179 "#;
1180
1181 let _block: SerializableBlock = serde_json::from_str(block).unwrap();
1182 }
1183
1184 #[test]
1185 fn test_block_withdrawals_preserved() {
1186 use alloy_eips::eip4895::Withdrawal;
1187
1188 let withdrawal = Withdrawal {
1190 index: 42,
1191 validator_index: 123,
1192 address: Address::repeat_byte(1),
1193 amount: 1000,
1194 };
1195
1196 let header = Header::default();
1197 let body = BlockBody {
1198 transactions: vec![],
1199 ommers: vec![],
1200 withdrawals: Some(vec![withdrawal].into()),
1201 };
1202 let block = Block::new(header.into(), body);
1203
1204 let serializable = SerializableBlock::from(block);
1206 let restored = Block::from(serializable);
1207
1208 assert!(restored.body.withdrawals.is_some());
1210 let withdrawals = restored.body.withdrawals.unwrap();
1211 assert_eq!(withdrawals.len(), 1);
1212 assert_eq!(withdrawals[0].index, 42);
1213 assert_eq!(withdrawals[0].validator_index, 123);
1214 }
1215
1216 #[test]
1217 fn load_state_fork_read_error_allows_snapshot_rollback() {
1218 let provider =
1219 ProviderBuilder::<_, _, AnyNetwork>::default().connect_mocked_client(Asserter::new());
1220 let remote = BlockchainDb::new(
1221 BlockchainDbMeta::new(BlockEnv::default(), "http://localhost".to_string()),
1222 None,
1223 );
1224 let (backend, handler) = SharedBackend::new(provider, remote.clone(), None);
1225 drop(handler);
1226 let mut db = ForkedDatabase::new(backend, remote);
1227 let cached = Address::with_last_byte(1);
1228 let uncached = Address::with_last_byte(2);
1229 let original = AccountInfo { nonce: 7, balance: U256::ONE, ..Default::default() };
1230 db.insert_account(cached, original.clone());
1231 let snapshot = db.snapshot_state();
1232 let mut state = SerializableState::default();
1233 for address in [cached, uncached] {
1234 state.accounts.insert(
1235 address,
1236 SerializableAccountRecord {
1237 nonce: 3,
1238 balance: U256::from(10),
1239 code: Bytes::new(),
1240 storage: Default::default(),
1241 },
1242 );
1243 }
1244
1245 assert!(matches!(db.load_state(state), Err(DatabaseError::Send(_))));
1247 let imported = db.basic_ref(cached).unwrap().unwrap();
1248 assert_eq!(imported.nonce, original.nonce);
1249 assert_eq!(imported.balance, U256::from(10));
1250 assert!(!db.database().cache.accounts.contains_key(&uncached));
1251
1252 assert!(db.revert_state(snapshot, RevertStateSnapshotAction::RevertRemove));
1254 assert_eq!(db.basic_ref(cached).unwrap().unwrap(), original);
1255 assert!(!db.database().cache.accounts.contains_key(&uncached));
1256 }
1257}