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