1use 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
48pub(crate) const BLOCKHASH_HISTORY: u64 = 256;
50
51#[cfg(feature = "monad")]
53#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
54pub struct MonadBlockReplayProfile {
55 pub execution_chain_id: u64,
57 pub hardfork: foundry_evm::hardfork::MonadHardfork,
59}
60
61pub(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
72pub trait MaybeFullDatabase: DatabaseRef<Error = DatabaseError> + Debug {
74 fn maybe_as_full_db(&self) -> Option<&AddressMap<DbAccount>> {
75 None
76 }
77
78 fn maybe_full_db(&self) -> Option<AddressMap<DbAccount>> {
80 self.maybe_as_full_db().cloned()
81 }
82
83 fn is_persistent(&self) -> bool {
85 false
86 }
87
88 fn clear_into_state_snapshot(&mut self) -> StateSnapshot;
90
91 fn read_as_state_snapshot(&self) -> StateSnapshot;
95
96 fn clear(&mut self);
98
99 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
165pub 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
174impl alloy_evm::Database for dyn Db {}
177
178#[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
247pub 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 fn insert_account(&mut self, address: Address, account: AccountInfo);
260
261 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 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 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 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;
293
294 fn insert_block_hash(&mut self, number: U256, hash: B256);
296
297 fn set_block_hashes(&mut self, block_hashes: Vec<(U256, B256)>);
299
300 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 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 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, 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 fn snapshot_state(&mut self) -> U256;
345
346 fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;
350
351 fn maybe_state_root(&self) -> Option<B256> {
353 None
354 }
355
356 fn current_state(&self) -> StateDb;
358}
359
360impl<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#[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 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#[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#[derive(Debug, Deserialize)]
602pub struct LegacyBlobExcessGasAndPrice {
603 pub excess_blob_gas: u64,
604 pub blob_gasprice: u128,
605}
606
607#[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
631impl 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
658fn 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
679fn 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 #[serde(deserialize_with = "deserialize_block_env_compat")]
710 pub block: Option<BlockEnv>,
711 pub accounts: BTreeMap<Address, SerializableAccountRecord>,
712 #[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 #[cfg(feature = "monad")]
724 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
725 pub monad_block_participants: BTreeMap<B256, std::collections::BTreeSet<Address>>,
726 #[cfg(feature = "monad")]
728 #[serde(default, skip_serializing_if = "BTreeMap::is_empty")]
729 pub monad_block_replay_profiles: BTreeMap<B256, MonadBlockReplayProfile>,
730 #[serde(default)]
734 pub historical_states: Option<SerializableHistoricalStates>,
735}
736
737impl SerializableState {
738 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 #[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#[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 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 let serializable = SerializableBlock::from(block);
1058 let restored = Block::from(serializable);
1059
1060 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}