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: DatabaseRef<Error = DatabaseError> + Debug {
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
104impl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T
105where
106 &'a T: DatabaseRef<Error = DatabaseError>,
107{
108 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
109 T::maybe_as_full_db(self)
110 }
111
112 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
113 T::maybe_full_db(self)
114 }
115
116 fn is_persistent(&self) -> bool {
117 T::is_persistent(self)
118 }
119
120 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
121 unreachable!("never called for DatabaseRef")
122 }
123
124 fn read_as_state_snapshot(&self) -> StateSnapshot {
125 unreachable!("never called for DatabaseRef")
126 }
127
128 fn clear(&mut self) {}
129
130 fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
131}
132
133impl<T: MaybeFullDatabase + ?Sized> MaybeFullDatabase for Box<T>
134where
135 Self: DatabaseRef<Error = DatabaseError>,
136{
137 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
138 T::maybe_as_full_db(self)
139 }
140
141 fn maybe_as_full_db_mut(&mut self) -> Option<&mut AddressMap<DbAccount>> {
142 T::maybe_as_full_db_mut(self)
143 }
144
145 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
146 T::maybe_full_db(self)
147 }
148
149 fn is_persistent(&self) -> bool {
150 T::is_persistent(self)
151 }
152
153 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
154 T::clear_into_state_snapshot(self)
155 }
156
157 fn read_as_state_snapshot(&self) -> StateSnapshot {
158 T::read_as_state_snapshot(self)
159 }
160
161 fn clear(&mut self) {
162 T::clear(self)
163 }
164
165 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
166 T::init_from_state_snapshot(self, state_snapshot)
167 }
168}
169
170pub trait MaybeForkedDatabase {
172 fn maybe_reset(&mut self, _urls: Vec<String>, block_number: BlockId) -> Result<(), String>;
173
174 fn maybe_flush_cache(&self) -> Result<(), String>;
175
176 fn maybe_inner(&self) -> Result<&BlockchainDb, String>;
177}
178
179impl alloy_evm::Database for dyn Db {}
182
183#[derive(Debug)]
185pub struct AnvilCacheDB<T>(pub CacheDB<T>, BalState, SpecId);
186
187impl<T: DatabaseRef<Error = DatabaseError>> AnvilCacheDB<T> {
188 pub fn new(inner: T, spec: SpecId) -> Self {
189 Self(CacheDB::new(inner), BalState::new(), spec)
190 }
191
192 pub fn enable_bal_recording(&mut self) {
194 self.1 = BalState::new().with_bal_builder();
195 }
196
197 pub fn take_block_access_list(&mut self) -> Option<BlockAccessList> {
199 self.1.take_built_alloy_bal()
200 }
201}
202
203impl<T: DatabaseRef<Error = DatabaseError>> std::ops::Deref for AnvilCacheDB<T> {
204 type Target = CacheDB<T>;
205 fn deref(&self) -> &Self::Target {
206 &self.0
207 }
208}
209
210impl<T: DatabaseRef<Error = DatabaseError>> std::ops::DerefMut for AnvilCacheDB<T> {
211 fn deref_mut(&mut self) -> &mut Self::Target {
212 &mut self.0
213 }
214}
215
216impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> Database for AnvilCacheDB<T> {
217 type Error = DatabaseError;
218
219 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
220 Ok(existing_account(self.2, self.0.basic(address)?))
221 }
222
223 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
224 self.0.code_by_hash(code_hash)
225 }
226
227 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
228 self.0.storage(address, index)
229 }
230
231 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
232 self.0.block_hash(number)
233 }
234}
235
236impl<T: DatabaseRef<Error = DatabaseError>> DatabaseRef for AnvilCacheDB<T> {
237 type Error = DatabaseError;
238
239 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
240 self.0.basic_ref(address)
241 }
242
243 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
244 self.0.code_by_hash_ref(code_hash)
245 }
246
247 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
248 self.0.storage_ref(address, index)
249 }
250
251 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
252 self.0.block_hash_ref(number)
253 }
254}
255
256impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> DatabaseCommit for AnvilCacheDB<T> {
257 fn commit(&mut self, changes: revm::state::EvmState) {
258 self.1.commit(&changes);
259 self.0.commit(changes)
260 }
261}
262
263impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> BalIndexedDatabase for AnvilCacheDB<T> {
264 fn set_bal_index(&mut self, index: u64) {
265 self.1.bal_index = BlockAccessIndex::new(index);
266 }
267
268 fn bump_bal_index(&mut self) {
269 self.1.bump_bal_index();
270 }
271}
272
273impl<T: DatabaseRef<Error = DatabaseError> + fmt::Debug> BalIndexedDatabase
274 for &mut AnvilCacheDB<T>
275{
276 fn set_bal_index(&mut self, index: u64) {
277 (**self).set_bal_index(index);
278 }
279
280 fn bump_bal_index(&mut self) {
281 (**self).bump_bal_index();
282 }
283}
284
285#[derive(Debug)]
293pub(super) struct EmptyAsAbsentDb<T>(pub(super) T);
294
295impl<T: DatabaseRef> DatabaseRef for EmptyAsAbsentDb<T> {
296 type Error = T::Error;
297
298 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
299 Ok(self.0.basic_ref(address)?.filter(|info| !info.is_empty()))
300 }
301
302 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
303 self.0.code_by_hash_ref(code_hash)
304 }
305
306 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
307 self.0.storage_ref(address, index)
308 }
309
310 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
311 self.0.block_hash_ref(number)
312 }
313}
314
315pub trait Db:
317 DatabaseRef<Error = DatabaseError>
318 + Database<Error = DatabaseError>
319 + DatabaseCommit
320 + MaybeFullDatabase
321 + MaybeForkedDatabase
322 + fmt::Debug
323 + Send
324 + Sync
325{
326 fn insert_account(&mut self, address: Address, account: AccountInfo);
328
329 fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {
331 let mut info = self.basic(address)?.unwrap_or_default();
332 info.nonce = nonce;
333 self.insert_account(address, info);
334 Ok(())
335 }
336
337 fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {
339 let mut info = self.basic(address)?.unwrap_or_default();
340 info.balance = balance;
341 self.insert_account(address, info);
342 Ok(())
343 }
344
345 fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {
347 let mut info = self.basic(address)?.unwrap_or_default();
348 let code_hash = if code.as_ref().is_empty() {
349 KECCAK_EMPTY
350 } else {
351 B256::from_slice(&keccak256(code.as_ref())[..])
352 };
353 info.code_hash = code_hash;
354 info.code = Some(Bytecode::new_raw(code));
355 self.insert_account(address, info);
356 Ok(())
357 }
358
359 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;
361
362 fn insert_block_hash(&mut self, number: U256, hash: B256);
364
365 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>);
367
368 fn dump_state(
370 &self,
371 at: BlockEnv,
372 best_number: u64,
373 blocks: Vec<SerializableBlock>,
374 transactions: Vec<SerializableTransaction>,
375 historical_states: Option<SerializableHistoricalStates>,
376 ) -> DatabaseResult<Option<SerializableState>>;
377
378 fn load_state(&mut self, state: SerializableState) -> DatabaseResult<bool> {
380 for (addr, account) in state.accounts {
381 let old_account_nonce = DatabaseRef::basic_ref(self, addr)
382 .ok()
383 .and_then(|acc| acc.map(|acc| acc.nonce))
384 .unwrap_or_default();
385 let nonce = std::cmp::max(old_account_nonce, account.nonce);
388
389 self.insert_account(
390 addr,
391 AccountInfo {
392 balance: account.balance,
393 code_hash: KECCAK_EMPTY, code: if account.code.0.is_empty() {
395 None
396 } else {
397 Some(Bytecode::new_raw(account.code))
398 },
399 nonce,
400 account_id: None,
401 },
402 );
403
404 for (k, v) in account.storage {
405 self.set_storage_at(addr, k, v)?;
406 }
407 }
408 Ok(true)
409 }
410
411 fn snapshot_state(&mut self) -> U256;
413
414 fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;
418
419 fn delete_state_snapshot(&mut self, state_snapshot: U256) -> bool;
421
422 fn maybe_state_root(&self) -> Option<B256> {
424 None
425 }
426
427 fn current_state(&self) -> StateDb;
429}
430
431impl<T> Db for CacheDB<T>
436where
437 T: DatabaseRef<Error = DatabaseError> + MaybeFullDatabase + Send + Sync + Clone + fmt::Debug,
438{
439 fn insert_account(&mut self, address: Address, account: AccountInfo) {
440 self.insert_account_info(address, account)
441 }
442
443 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
444 self.insert_account_storage(address, slot.into(), val.into())
445 }
446
447 fn insert_block_hash(&mut self, number: U256, hash: B256) {
448 cache_block_hash(&mut self.cache.block_hashes, number, hash);
449 }
450
451 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>) {
452 self.cache.block_hashes = block_hashes.into_iter().collect();
453 }
454
455 fn dump_state(
456 &self,
457 _at: BlockEnv,
458 _best_number: u64,
459 _blocks: Vec<SerializableBlock>,
460 _transaction: Vec<SerializableTransaction>,
461 _historical_states: Option<SerializableHistoricalStates>,
462 ) -> DatabaseResult<Option<SerializableState>> {
463 Ok(None)
464 }
465
466 fn snapshot_state(&mut self) -> U256 {
467 U256::ZERO
468 }
469
470 fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {
471 false
472 }
473
474 fn delete_state_snapshot(&mut self, _state_snapshot: U256) -> bool {
475 false
476 }
477
478 fn maybe_state_root(&self) -> Option<B256> {
479 self.maybe_full_db().map(|accounts| crate::mem::state::state_root(&accounts))
480 }
481
482 fn current_state(&self) -> StateDb {
483 StateDb::new(MemDb::default())
484 }
485}
486
487impl<T: MaybeFullDatabase> MaybeFullDatabase for CacheDB<T> {
488 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
489 Some(&self.cache.accounts)
490 }
491
492 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
493 let mut accounts = self.db.maybe_full_db()?;
494 for (address, overlay) in &self.cache.accounts {
495 if overlay.account_state == AccountState::NotExisting {
496 accounts.remove(address);
497 continue;
498 }
499 if overlay.account_state.is_storage_cleared() {
500 accounts.insert(*address, overlay.clone());
501 continue;
502 }
503
504 let mut account = accounts.remove(address).unwrap_or_default();
505 account.info = overlay.info.clone();
506 account.account_state = overlay.account_state.clone();
507 account.storage.extend(overlay.storage.clone());
508 accounts.insert(*address, account);
509 }
510 Some(accounts)
511 }
512
513 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
514 let db_accounts = std::mem::take(&mut self.cache.accounts);
515 let mut accounts = HashMap::default();
516 let mut account_storage = HashMap::default();
517
518 for (addr, mut acc) in db_accounts {
519 account_storage.insert(addr, std::mem::take(&mut acc.storage));
520 let mut info = acc.info;
521 info.code = self.cache.contracts.remove(&info.code_hash());
522 accounts.insert(addr, info);
523 }
524 let block_hashes = std::mem::take(&mut self.cache.block_hashes);
525 StateSnapshot { accounts, storage: account_storage, block_hashes }
526 }
527
528 fn read_as_state_snapshot(&self) -> StateSnapshot {
529 let mut accounts = HashMap::default();
530 let mut account_storage = HashMap::default();
531
532 for (addr, acc) in &self.cache.accounts {
533 account_storage.insert(*addr, acc.storage.clone());
534 let mut info = acc.info.clone();
535 info.code = self.cache.contracts.get(&info.code_hash()).cloned();
536 accounts.insert(*addr, info);
537 }
538
539 let block_hashes = self.cache.block_hashes.clone();
540 StateSnapshot { accounts, storage: account_storage, block_hashes }
541 }
542
543 fn clear(&mut self) {
544 self.clear_into_state_snapshot();
545 }
546
547 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
548 let StateSnapshot { accounts, mut storage, block_hashes } = state_snapshot;
549
550 for (addr, mut acc) in accounts {
551 if let Some(code) = acc.code.take() {
552 self.cache.contracts.insert(acc.code_hash(), code);
553 }
554 self.cache.accounts.insert(
555 addr,
556 DbAccount {
557 info: acc,
558 storage: storage.remove(&addr).unwrap_or_default(),
559 ..Default::default()
560 },
561 );
562 }
563 self.cache.block_hashes = block_hashes;
564 }
565}
566
567impl MaybeFullDatabase for EmptyDBWrapper {
568 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
569 StateSnapshot::default()
570 }
571
572 fn read_as_state_snapshot(&self) -> StateSnapshot {
573 StateSnapshot::default()
574 }
575
576 fn clear(&mut self) {}
577
578 fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
579}
580
581impl<T: DatabaseRef<Error = DatabaseError>> MaybeForkedDatabase for CacheDB<T> {
582 fn maybe_reset(&mut self, _urls: Vec<String>, _block_number: BlockId) -> Result<(), String> {
583 Err("not supported".to_string())
584 }
585
586 fn maybe_flush_cache(&self) -> Result<(), String> {
587 Err("not supported".to_string())
588 }
589
590 fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
591 Err("not supported".to_string())
592 }
593}
594
595#[derive(Debug)]
597pub struct StateDb(pub(crate) Box<dyn MaybeFullDatabase + Send + Sync>);
598
599impl StateDb {
600 pub fn new(db: impl MaybeFullDatabase + Send + Sync + 'static) -> Self {
601 Self(Box::new(db))
602 }
603
604 pub fn serialize_state(&mut self) -> StateSnapshot {
605 self.read_as_state_snapshot()
608 }
609}
610
611impl DatabaseRef for StateDb {
612 type Error = DatabaseError;
613 fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {
614 self.0.basic_ref(address)
615 }
616
617 fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {
618 self.0.code_by_hash_ref(code_hash)
619 }
620
621 fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
622 self.0.storage_ref(address, index)
623 }
624
625 fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {
626 self.0.block_hash_ref(number)
627 }
628}
629
630impl MaybeFullDatabase for StateDb {
631 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
632 self.0.maybe_as_full_db()
633 }
634
635 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
636 self.0.maybe_full_db()
637 }
638
639 fn is_persistent(&self) -> bool {
640 self.0.is_persistent()
641 }
642
643 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
644 self.0.clear_into_state_snapshot()
645 }
646
647 fn read_as_state_snapshot(&self) -> StateSnapshot {
648 self.0.read_as_state_snapshot()
649 }
650
651 fn clear(&mut self) {
652 self.0.clear()
653 }
654
655 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
656 self.0.init_from_state_snapshot(state_snapshot)
657 }
658}
659
660#[derive(Debug, Deserialize)]
662#[serde(rename_all = "snake_case")]
663pub struct LegacyBlockEnv {
664 pub number: Option<StringOrU64>,
665 #[serde(alias = "coinbase")]
666 pub beneficiary: Option<Address>,
667 pub timestamp: Option<StringOrU64>,
668 pub gas_limit: Option<StringOrU64>,
669 pub basefee: Option<StringOrU64>,
670 pub difficulty: Option<StringOrU64>,
671 pub prevrandao: Option<B256>,
672 pub blob_excess_gas_and_price: Option<LegacyBlobExcessGasAndPrice>,
673}
674
675#[derive(Debug, Deserialize)]
677pub struct LegacyBlobExcessGasAndPrice {
678 pub excess_blob_gas: u64,
679 pub blob_gasprice: u128,
680}
681
682#[derive(Debug, Deserialize)]
684#[serde(untagged)]
685pub enum StringOrU64 {
686 Hex(String),
687 Dec(u64),
688}
689
690impl StringOrU64 {
691 pub fn to_u64(&self) -> Option<u64> {
692 match self {
693 Self::Dec(n) => Some(*n),
694 Self::Hex(s) => s.strip_prefix("0x").and_then(|s| u64::from_str_radix(s, 16).ok()),
695 }
696 }
697
698 pub fn to_u256(&self) -> Option<U256> {
699 match self {
700 Self::Dec(n) => Some(U256::from(*n)),
701 Self::Hex(s) => s.strip_prefix("0x").and_then(|s| U256::from_str_radix(s, 16).ok()),
702 }
703 }
704}
705
706impl TryFrom<LegacyBlockEnv> for BlockEnv {
708 type Error = &'static str;
709
710 fn try_from(legacy: LegacyBlockEnv) -> Result<Self, Self::Error> {
711 Ok(Self {
712 number: legacy.number.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),
713 beneficiary: legacy.beneficiary.unwrap_or(Address::ZERO),
714 timestamp: legacy.timestamp.and_then(|v| v.to_u256()).unwrap_or(U256::ONE),
715 gas_limit: legacy.gas_limit.and_then(|v| v.to_u64()).unwrap_or(u64::MAX),
716 basefee: legacy.basefee.and_then(|v| v.to_u64()).unwrap_or(0),
717 difficulty: legacy.difficulty.and_then(|v| v.to_u256()).unwrap_or(U256::ZERO),
718 prevrandao: legacy.prevrandao.or(Some(B256::ZERO)),
719 slot_num: 0,
720 blob_excess_gas_and_price: legacy
721 .blob_excess_gas_and_price
722 .map(|v| BlobExcessGasAndPrice {
723 excess_blob_gas: v.excess_blob_gas,
724 blob_gasprice: v.blob_gasprice,
725 })
726 .or_else(|| {
727 Some(BlobExcessGasAndPrice::new(0, BLOB_BASE_FEE_UPDATE_FRACTION_PRAGUE))
728 }),
729 })
730 }
731}
732
733fn deserialize_block_env_compat<'de, D>(deserializer: D) -> Result<Option<BlockEnv>, D::Error>
735where
736 D: Deserializer<'de>,
737{
738 let value: Option<Value> = Option::deserialize(deserializer)?;
739 let Some(value) = value else {
740 return Ok(None);
741 };
742
743 if let Ok(env) = BlockEnv::deserialize(&value) {
744 return Ok(Some(env));
745 }
746
747 let legacy: LegacyBlockEnv = serde_json::from_value(value).map_err(|e| {
748 D::Error::custom(format!("Legacy deserialization of `BlockEnv` failed: {e}"))
749 })?;
750
751 Ok(Some(BlockEnv::try_from(legacy).map_err(D::Error::custom)?))
752}
753
754fn deserialize_best_block_number_compat<'de, D>(deserializer: D) -> Result<Option<u64>, D::Error>
756where
757 D: Deserializer<'de>,
758{
759 let value: Option<Value> = Option::deserialize(deserializer)?;
760 let Some(value) = value else {
761 return Ok(None);
762 };
763
764 let number = match value {
765 Value::Number(n) => n.as_u64(),
766 Value::String(s) => {
767 if let Some(s) = s.strip_prefix("0x") {
768 u64::from_str_radix(s, 16).ok()
769 } else {
770 s.parse().ok()
771 }
772 }
773 _ => None,
774 };
775
776 Ok(number)
777}
778
779#[derive(Clone, Debug, Default, Serialize, Deserialize)]
780pub struct SerializableState {
781 #[serde(deserialize_with = "deserialize_block_env_compat")]
785 pub block: Option<BlockEnv>,
786 pub accounts: BTreeMap<Address, SerializableAccountRecord>,
787 #[serde(deserialize_with = "deserialize_best_block_number_compat")]
789 pub best_block_number: Option<u64>,
790 #[serde(default)]
791 pub blocks: Vec<SerializableBlock>,
792 #[serde(default)]
793 pub transactions: Vec<SerializableTransaction>,
794 #[cfg(feature = "monad")]
799 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
800 pub monad_block_participants: BTreeMap<B256, std::collections::BTreeSet<Address>>,
801 #[cfg(feature = "monad")]
803 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
804 pub monad_block_replay_profiles: BTreeMap<B256, MonadBlockReplayProfile>,
805 #[serde(default)]
809 pub historical_states: Option<SerializableHistoricalStates>,
810}
811
812impl SerializableState {
813 pub fn load(path: impl AsRef<Path>) -> Result<Self, FsPathError> {
815 let mut path = path.as_ref().to_path_buf();
816 if path.is_dir() {
817 path = path.join("state.json");
818 }
819
820 let file = File::open(&path).map_err(|err| FsPathError::read(err, &path))?;
821 serde_json::from_reader(BufReader::new(file)).map_err(|err| {
822 if err.is_io() {
823 FsPathError::read(err.into(), &path)
824 } else {
825 FsPathError::ReadJson { source: err, path }
826 }
827 })
828 }
829
830 #[cfg(feature = "cmd")]
832 pub(crate) fn parse(path: &str) -> Result<Self, String> {
833 Self::load(path).map_err(|err| err.to_string())
834 }
835}
836
837#[derive(Clone, Debug, Serialize, Deserialize)]
838pub struct SerializableAccountRecord {
839 pub nonce: u64,
840 pub balance: U256,
841 pub code: Bytes,
842
843 #[serde(deserialize_with = "deserialize_btree")]
844 pub storage: BTreeMap<B256, B256>,
845}
846
847fn deserialize_btree<'de, D>(deserializer: D) -> Result<BTreeMap<B256, B256>, D::Error>
848where
849 D: Deserializer<'de>,
850{
851 struct BTreeVisitor;
852
853 impl<'de> Visitor<'de> for BTreeVisitor {
854 type Value = BTreeMap<B256, B256>;
855
856 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
857 formatter.write_str("a mapping of hex encoded storage slots to hex encoded state data")
858 }
859
860 fn visit_map<M>(self, mut mapping: M) -> Result<BTreeMap<B256, B256>, M::Error>
861 where
862 M: MapAccess<'de>,
863 {
864 let mut btree = BTreeMap::new();
865 while let Some((key, value)) = mapping.next_entry::<U256, U256>()? {
866 btree.insert(B256::from(key), B256::from(value));
867 }
868
869 Ok(btree)
870 }
871 }
872
873 deserializer.deserialize_map(BTreeVisitor)
874}
875
876#[derive(Clone, Debug, Serialize, Deserialize)]
884#[serde(untagged)]
885pub enum SerializableTransactionType {
886 TypedTransaction(FoundryTxEnvelope),
887 MaybeImpersonatedTransaction(MaybeImpersonatedTransaction<FoundryTxEnvelope>),
888}
889
890#[derive(Clone, Debug, Serialize, Deserialize)]
891pub struct SerializableBlock {
892 pub header: FoundryHeader,
893 pub transactions: Vec<SerializableTransactionType>,
894 pub ommers: Vec<FoundryHeader>,
895 #[serde(default)]
896 pub withdrawals: Option<Withdrawals>,
897}
898
899impl From<Block> for SerializableBlock {
900 fn from(block: Block) -> Self {
901 Self {
902 header: block.header,
903 transactions: block.body.transactions.into_iter().map(Into::into).collect(),
904 ommers: block.body.ommers.into_iter().collect(),
905 withdrawals: block.body.withdrawals,
906 }
907 }
908}
909
910impl From<SerializableBlock> for Block {
911 fn from(block: SerializableBlock) -> Self {
912 let transactions = block.transactions.into_iter().map(Into::into).collect();
913 let ommers = block.ommers;
914 let body = BlockBody { transactions, ommers, withdrawals: block.withdrawals };
915 Self::new(block.header, body)
916 }
917}
918
919impl From<MaybeImpersonatedTransaction<FoundryTxEnvelope>> for SerializableTransactionType {
920 fn from(transaction: MaybeImpersonatedTransaction<FoundryTxEnvelope>) -> Self {
921 Self::MaybeImpersonatedTransaction(transaction)
922 }
923}
924
925impl From<SerializableTransactionType> for MaybeImpersonatedTransaction<FoundryTxEnvelope> {
926 fn from(transaction: SerializableTransactionType) -> Self {
927 match transaction {
928 SerializableTransactionType::TypedTransaction(tx) => Self::new(tx),
929 SerializableTransactionType::MaybeImpersonatedTransaction(tx) => tx,
930 }
931 }
932}
933
934#[derive(Clone, Debug, Serialize, Deserialize)]
935pub struct SerializableTransaction {
936 pub info: TransactionInfo,
937 pub receipt: FoundryReceiptEnvelope,
938 pub block_hash: B256,
939 pub block_number: u64,
940}
941
942impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> From<MinedTransaction<N>>
943 for SerializableTransaction
944{
945 fn from(transaction: MinedTransaction<N>) -> Self {
946 Self {
947 info: transaction.info,
948 receipt: transaction.receipt,
949 block_hash: transaction.block_hash,
950 block_number: transaction.block_number,
951 }
952 }
953}
954
955impl<N: Network<ReceiptEnvelope = FoundryReceiptEnvelope>> From<SerializableTransaction>
956 for MinedTransaction<N>
957{
958 fn from(transaction: SerializableTransaction) -> Self {
959 Self {
960 info: transaction.info,
961 receipt: transaction.receipt,
962 block_hash: transaction.block_hash,
963 block_number: transaction.block_number,
964 }
965 }
966}
967
968#[derive(Clone, Debug, Serialize, Deserialize, Default)]
969pub struct SerializableHistoricalStates(Vec<(B256, StateSnapshot)>);
970
971impl SerializableHistoricalStates {
972 pub const fn new(states: Vec<(B256, StateSnapshot)>) -> Self {
973 Self(states)
974 }
975}
976
977impl IntoIterator for SerializableHistoricalStates {
978 type Item = (B256, StateSnapshot);
979 type IntoIter = std::vec::IntoIter<Self::Item>;
980
981 fn into_iter(self) -> Self::IntoIter {
982 self.0.into_iter()
983 }
984}
985
986#[cfg(test)]
987mod test {
988 use super::*;
989 use alloy_consensus::Header;
990 use std::fs;
991
992 #[test]
993 fn loads_state_from_file_or_directory() {
994 let tmp = tempfile::tempdir().unwrap();
995 let state_path = tmp.path().join("state.json");
996 fs::write(&state_path, serde_json::to_vec(&SerializableState::default()).unwrap()).unwrap();
997
998 assert!(SerializableState::load(&state_path).unwrap().accounts.is_empty());
999 assert!(SerializableState::load(tmp.path()).unwrap().accounts.is_empty());
1000
1001 fs::write(&state_path, b"not json").unwrap();
1002 let Err(FsPathError::ReadJson { path, .. }) = SerializableState::load(tmp.path()) else {
1003 panic!("expected invalid JSON error")
1004 };
1005 assert_eq!(path, state_path);
1006
1007 let missing_path = tmp.path().join("missing.json");
1008 let Err(FsPathError::Read { path, .. }) = SerializableState::load(&missing_path) else {
1009 panic!("expected file read error")
1010 };
1011 assert_eq!(path, missing_path);
1012 }
1013
1014 #[test]
1015 fn cache_db_full_state_merges_base_and_overlay() {
1016 let preserved = Address::with_last_byte(1);
1017 let updated = Address::with_last_byte(2);
1018 let deleted = Address::with_last_byte(3);
1019 let cleared = Address::with_last_byte(4);
1020 let deleted_slot = U256::ONE;
1021 let updated_slot = U256::from(2);
1022
1023 let mut base = MemDb::default();
1024 base.insert_account(preserved, AccountInfo::from_balance(U256::ONE));
1025 base.insert_account(updated, AccountInfo::from_balance(U256::from(2)));
1026 base.set_storage_at(updated, deleted_slot.into(), B256::with_last_byte(10)).unwrap();
1027 base.set_storage_at(updated, updated_slot.into(), B256::with_last_byte(11)).unwrap();
1028 base.insert_account(deleted, AccountInfo::from_balance(U256::from(3)));
1029 base.insert_account(cleared, AccountInfo::from_balance(U256::from(4)));
1030 base.set_storage_at(cleared, deleted_slot.into(), B256::with_last_byte(11)).unwrap();
1031
1032 let mut cache = CacheDB::new(base);
1033 cache.insert_account_info(updated, AccountInfo::from_balance(U256::from(20)));
1034 cache.insert_account_storage(updated, deleted_slot, U256::ZERO).unwrap();
1035 cache.insert_account_storage(updated, updated_slot, U256::from(12)).unwrap();
1036 cache.cache.accounts.insert(deleted, DbAccount::new_not_existing());
1037 cache.cache.accounts.insert(
1038 cleared,
1039 DbAccount {
1040 info: AccountInfo::from_balance(U256::from(40)),
1041 account_state: AccountState::StorageCleared,
1042 ..Default::default()
1043 },
1044 );
1045
1046 let accounts = cache.maybe_full_db().unwrap();
1047 assert_eq!(accounts[&preserved].info.balance, U256::ONE);
1048 assert_eq!(accounts[&updated].info.balance, U256::from(20));
1049 assert_eq!(accounts[&updated].storage[&deleted_slot], U256::ZERO);
1050 assert_eq!(accounts[&updated].storage[&updated_slot], U256::from(12));
1051 assert!(!accounts.contains_key(&deleted));
1052 assert!(accounts[&cleared].storage.is_empty());
1053 let mut expected = accounts;
1054 expected.get_mut(&updated).unwrap().storage.remove(&deleted_slot);
1055 assert_eq!(
1056 cache.maybe_full_db().map(|accounts| crate::mem::state::state_root(&accounts)),
1057 Some(crate::mem::state::state_root(&expected))
1058 );
1059 }
1060
1061 #[test]
1062 fn test_deser_block() {
1063 let block = r#"{
1064 "header": {
1065 "parentHash": "0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929",
1066 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
1067 "miner": "0x0000000000000000000000000000000000000000",
1068 "stateRoot": "0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1",
1069 "transactionsRoot": "0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988",
1070 "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
1071 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
1072 "difficulty": "0x0",
1073 "number": "0x2",
1074 "gasLimit": "0x1c9c380",
1075 "gasUsed": "0x5208",
1076 "timestamp": "0x66cdc823",
1077 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
1078 "nonce": "0x0000000000000000",
1079 "baseFeePerGas": "0x342a1c58",
1080 "blobGasUsed": "0x0",
1081 "excessBlobGas": "0x0",
1082 "extraData": "0x"
1083 },
1084 "transactions": [
1085 {
1086 "type": "0x2",
1087 "chainId": "0x7a69",
1088 "nonce": "0x0",
1089 "gas": "0x5209",
1090 "maxFeePerGas": "0x77359401",
1091 "maxPriorityFeePerGas": "0x1",
1092 "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
1093 "value": "0x0",
1094 "accessList": [],
1095 "input": "0x",
1096 "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0",
1097 "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd",
1098 "yParity": "0x0",
1099 "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"
1100 }
1101 ],
1102 "ommers": []
1103 }
1104 "#;
1105
1106 let _block: SerializableBlock = serde_json::from_str(block).unwrap();
1107 }
1108
1109 #[test]
1110 fn test_block_withdrawals_preserved() {
1111 use alloy_eips::eip4895::Withdrawal;
1112
1113 let withdrawal = Withdrawal {
1115 index: 42,
1116 validator_index: 123,
1117 address: Address::repeat_byte(1),
1118 amount: 1000,
1119 };
1120
1121 let header = Header::default();
1122 let body = BlockBody {
1123 transactions: vec![],
1124 ommers: vec![],
1125 withdrawals: Some(vec![withdrawal].into()),
1126 };
1127 let block = Block::new(header.into(), body);
1128
1129 let serializable = SerializableBlock::from(block);
1131 let restored = Block::from(serializable);
1132
1133 assert!(restored.body.withdrawals.is_some());
1135 let withdrawals = restored.body.withdrawals.unwrap();
1136 assert_eq!(withdrawals.len(), 1);
1137 assert_eq!(withdrawals[0].index, 42);
1138 assert_eq!(withdrawals[0].validator_index, 123);
1139 }
1140}