1use crate::{mem::storage::MinedTransaction, revm::primitives::AccountInfo};
4use alloy_consensus::Header;
5use alloy_primitives::{keccak256, Address, Bytes, B256, U256, U64};
6use alloy_rpc_types::BlockId;
7use anvil_core::eth::{
8 block::Block,
9 transaction::{MaybeImpersonatedTransaction, TransactionInfo, TypedReceipt, TypedTransaction},
10};
11use foundry_common::errors::FsPathError;
12use foundry_evm::{
13 backend::{
14 BlockchainDb, DatabaseError, DatabaseResult, MemDb, RevertStateSnapshotAction,
15 StateSnapshot,
16 },
17 revm::{
18 db::{CacheDB, DatabaseRef, DbAccount},
19 primitives::{BlockEnv, Bytecode, HashMap, KECCAK_EMPTY},
20 Database, DatabaseCommit,
21 },
22};
23use serde::{
24 de::{MapAccess, Visitor},
25 Deserialize, Deserializer, Serialize,
26};
27use std::{collections::BTreeMap, fmt, path::Path};
28
29pub trait MaybeFullDatabase: DatabaseRef<Error = DatabaseError> {
31 fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError>;
34
35 fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
36 None
37 }
38
39 fn clear_into_state_snapshot(&mut self) -> StateSnapshot;
41
42 fn read_as_state_snapshot(&self) -> StateSnapshot;
46
47 fn clear(&mut self);
49
50 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot);
52}
53
54impl<'a, T: 'a + MaybeFullDatabase + ?Sized> MaybeFullDatabase for &'a T
55where
56 &'a T: DatabaseRef<Error = DatabaseError>,
57{
58 fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
59 T::as_dyn(self)
60 }
61
62 fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
63 T::maybe_as_full_db(self)
64 }
65
66 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
67 unreachable!("never called for DatabaseRef")
68 }
69
70 fn read_as_state_snapshot(&self) -> StateSnapshot {
71 unreachable!("never called for DatabaseRef")
72 }
73
74 fn clear(&mut self) {}
75
76 fn init_from_state_snapshot(&mut self, _state_snapshot: StateSnapshot) {}
77}
78
79pub trait MaybeForkedDatabase {
81 fn maybe_reset(&mut self, _url: Option<String>, block_number: BlockId) -> Result<(), String>;
82
83 fn maybe_flush_cache(&self) -> Result<(), String>;
84
85 fn maybe_inner(&self) -> Result<&BlockchainDb, String>;
86}
87
88pub trait Db:
90 DatabaseRef<Error = DatabaseError>
91 + Database<Error = DatabaseError>
92 + DatabaseCommit
93 + MaybeFullDatabase
94 + MaybeForkedDatabase
95 + fmt::Debug
96 + Send
97 + Sync
98{
99 fn insert_account(&mut self, address: Address, account: AccountInfo);
101
102 fn set_nonce(&mut self, address: Address, nonce: u64) -> DatabaseResult<()> {
104 let mut info = self.basic(address)?.unwrap_or_default();
105 info.nonce = nonce;
106 self.insert_account(address, info);
107 Ok(())
108 }
109
110 fn set_balance(&mut self, address: Address, balance: U256) -> DatabaseResult<()> {
112 let mut info = self.basic(address)?.unwrap_or_default();
113 info.balance = balance;
114 self.insert_account(address, info);
115 Ok(())
116 }
117
118 fn set_code(&mut self, address: Address, code: Bytes) -> DatabaseResult<()> {
120 let mut info = self.basic(address)?.unwrap_or_default();
121 let code_hash = if code.as_ref().is_empty() {
122 KECCAK_EMPTY
123 } else {
124 B256::from_slice(&keccak256(code.as_ref())[..])
125 };
126 info.code_hash = code_hash;
127 info.code = Some(Bytecode::new_raw(alloy_primitives::Bytes(code.0)));
128 self.insert_account(address, info);
129 Ok(())
130 }
131
132 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()>;
134
135 fn insert_block_hash(&mut self, number: U256, hash: B256);
137
138 fn dump_state(
140 &self,
141 at: BlockEnv,
142 best_number: U64,
143 blocks: Vec<SerializableBlock>,
144 transactions: Vec<SerializableTransaction>,
145 historical_states: Option<SerializableHistoricalStates>,
146 ) -> DatabaseResult<Option<SerializableState>>;
147
148 fn load_state(&mut self, state: SerializableState) -> DatabaseResult<bool> {
150 for (addr, account) in state.accounts.into_iter() {
151 let old_account_nonce = DatabaseRef::basic_ref(self, addr)
152 .ok()
153 .and_then(|acc| acc.map(|acc| acc.nonce))
154 .unwrap_or_default();
155 let nonce = std::cmp::max(old_account_nonce, account.nonce);
158
159 self.insert_account(
160 addr,
161 AccountInfo {
162 balance: account.balance,
163 code_hash: KECCAK_EMPTY, code: if account.code.0.is_empty() {
165 None
166 } else {
167 Some(Bytecode::new_raw(alloy_primitives::Bytes(account.code.0)))
168 },
169 nonce,
170 },
171 );
172
173 for (k, v) in account.storage.into_iter() {
174 self.set_storage_at(addr, k, v)?;
175 }
176 }
177 Ok(true)
178 }
179
180 fn snapshot_state(&mut self) -> U256;
182
183 fn revert_state(&mut self, state_snapshot: U256, action: RevertStateSnapshotAction) -> bool;
187
188 fn maybe_state_root(&self) -> Option<B256> {
190 None
191 }
192
193 fn current_state(&self) -> StateDb;
195}
196
197impl dyn Db {
198 pub fn as_dbref(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
200 self.as_dyn()
201 }
202}
203
204impl<T: DatabaseRef<Error = DatabaseError> + Send + Sync + Clone + fmt::Debug> Db for CacheDB<T> {
209 fn insert_account(&mut self, address: Address, account: AccountInfo) {
210 self.insert_account_info(address, account)
211 }
212
213 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
214 self.insert_account_storage(address, slot.into(), val.into())
215 }
216
217 fn insert_block_hash(&mut self, number: U256, hash: B256) {
218 self.block_hashes.insert(number, hash);
219 }
220
221 fn dump_state(
222 &self,
223 _at: BlockEnv,
224 _best_number: U64,
225 _blocks: Vec<SerializableBlock>,
226 _transaction: Vec<SerializableTransaction>,
227 _historical_states: Option<SerializableHistoricalStates>,
228 ) -> DatabaseResult<Option<SerializableState>> {
229 Ok(None)
230 }
231
232 fn snapshot_state(&mut self) -> U256 {
233 U256::ZERO
234 }
235
236 fn revert_state(&mut self, _state_snapshot: U256, _action: RevertStateSnapshotAction) -> bool {
237 false
238 }
239
240 fn current_state(&self) -> StateDb {
241 StateDb::new(MemDb::default())
242 }
243}
244
245impl<T: DatabaseRef<Error = DatabaseError>> MaybeFullDatabase for CacheDB<T> {
246 fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
247 self
248 }
249
250 fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
251 Some(&self.accounts)
252 }
253
254 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
255 let db_accounts = std::mem::take(&mut self.accounts);
256 let mut accounts = HashMap::default();
257 let mut account_storage = HashMap::default();
258
259 for (addr, mut acc) in db_accounts {
260 account_storage.insert(addr, std::mem::take(&mut acc.storage));
261 let mut info = acc.info;
262 info.code = self.contracts.remove(&info.code_hash);
263 accounts.insert(addr, info);
264 }
265 let block_hashes = std::mem::take(&mut self.block_hashes);
266 StateSnapshot { accounts, storage: account_storage, block_hashes }
267 }
268
269 fn read_as_state_snapshot(&self) -> StateSnapshot {
270 let db_accounts = self.accounts.clone();
271 let mut accounts = HashMap::default();
272 let mut account_storage = HashMap::default();
273
274 for (addr, acc) in db_accounts {
275 account_storage.insert(addr, acc.storage.clone());
276 let mut info = acc.info;
277 info.code = self.contracts.get(&info.code_hash).cloned();
278 accounts.insert(addr, info);
279 }
280
281 let block_hashes = self.block_hashes.clone();
282 StateSnapshot { accounts, storage: account_storage, block_hashes }
283 }
284
285 fn clear(&mut self) {
286 self.clear_into_state_snapshot();
287 }
288
289 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
290 let StateSnapshot { accounts, mut storage, block_hashes } = state_snapshot;
291
292 for (addr, mut acc) in accounts {
293 if let Some(code) = acc.code.take() {
294 self.contracts.insert(acc.code_hash, code);
295 }
296 self.accounts.insert(
297 addr,
298 DbAccount {
299 info: acc,
300 storage: storage.remove(&addr).unwrap_or_default(),
301 ..Default::default()
302 },
303 );
304 }
305 self.block_hashes = block_hashes;
306 }
307}
308
309impl<T: DatabaseRef<Error = DatabaseError>> MaybeForkedDatabase for CacheDB<T> {
310 fn maybe_reset(&mut self, _url: Option<String>, _block_number: BlockId) -> Result<(), String> {
311 Err("not supported".to_string())
312 }
313
314 fn maybe_flush_cache(&self) -> Result<(), String> {
315 Err("not supported".to_string())
316 }
317
318 fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
319 Err("not supported".to_string())
320 }
321}
322
323pub struct StateDb(pub(crate) Box<dyn MaybeFullDatabase + Send + Sync>);
325
326impl StateDb {
327 pub fn new(db: impl MaybeFullDatabase + Send + Sync + 'static) -> Self {
328 Self(Box::new(db))
329 }
330
331 pub fn serialize_state(&mut self) -> StateSnapshot {
332 self.read_as_state_snapshot()
335 }
336}
337
338impl DatabaseRef for StateDb {
339 type Error = DatabaseError;
340 fn basic_ref(&self, address: Address) -> DatabaseResult<Option<AccountInfo>> {
341 self.0.basic_ref(address)
342 }
343
344 fn code_by_hash_ref(&self, code_hash: B256) -> DatabaseResult<Bytecode> {
345 self.0.code_by_hash_ref(code_hash)
346 }
347
348 fn storage_ref(&self, address: Address, index: U256) -> DatabaseResult<U256> {
349 self.0.storage_ref(address, index)
350 }
351
352 fn block_hash_ref(&self, number: u64) -> DatabaseResult<B256> {
353 self.0.block_hash_ref(number)
354 }
355}
356
357impl MaybeFullDatabase for StateDb {
358 fn as_dyn(&self) -> &dyn DatabaseRef<Error = DatabaseError> {
359 self.0.as_dyn()
360 }
361
362 fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
363 self.0.maybe_as_full_db()
364 }
365
366 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
367 self.0.clear_into_state_snapshot()
368 }
369
370 fn read_as_state_snapshot(&self) -> StateSnapshot {
371 self.0.read_as_state_snapshot()
372 }
373
374 fn clear(&mut self) {
375 self.0.clear()
376 }
377
378 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
379 self.0.init_from_state_snapshot(state_snapshot)
380 }
381}
382
383#[derive(Clone, Debug, Default, Serialize, Deserialize)]
384pub struct SerializableState {
385 pub block: Option<BlockEnv>,
389 pub accounts: BTreeMap<Address, SerializableAccountRecord>,
390 pub best_block_number: Option<U64>,
392 #[serde(default)]
393 pub blocks: Vec<SerializableBlock>,
394 #[serde(default)]
395 pub transactions: Vec<SerializableTransaction>,
396 #[serde(default)]
400 pub historical_states: Option<SerializableHistoricalStates>,
401}
402
403impl SerializableState {
404 pub fn load(path: impl AsRef<Path>) -> Result<Self, FsPathError> {
406 let path = path.as_ref();
407 if path.is_dir() {
408 foundry_common::fs::read_json_file(&path.join("state.json"))
409 } else {
410 foundry_common::fs::read_json_file(path)
411 }
412 }
413
414 #[allow(dead_code)]
416 pub(crate) fn parse(path: &str) -> Result<Self, String> {
417 Self::load(path).map_err(|err| err.to_string())
418 }
419}
420
421#[derive(Clone, Debug, Serialize, Deserialize)]
422pub struct SerializableAccountRecord {
423 pub nonce: u64,
424 pub balance: U256,
425 pub code: Bytes,
426
427 #[serde(deserialize_with = "deserialize_btree")]
428 pub storage: BTreeMap<B256, B256>,
429}
430
431fn deserialize_btree<'de, D>(deserializer: D) -> Result<BTreeMap<B256, B256>, D::Error>
432where
433 D: Deserializer<'de>,
434{
435 struct BTreeVisitor;
436
437 impl<'de> Visitor<'de> for BTreeVisitor {
438 type Value = BTreeMap<B256, B256>;
439
440 fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
441 formatter.write_str("a mapping of hex encoded storage slots to hex encoded state data")
442 }
443
444 fn visit_map<M>(self, mut mapping: M) -> Result<BTreeMap<B256, B256>, M::Error>
445 where
446 M: MapAccess<'de>,
447 {
448 let mut btree = BTreeMap::new();
449 while let Some((key, value)) = mapping.next_entry::<U256, U256>()? {
450 btree.insert(B256::from(key), B256::from(value));
451 }
452
453 Ok(btree)
454 }
455 }
456
457 deserializer.deserialize_map(BTreeVisitor)
458}
459
460#[derive(Clone, Debug, Serialize, Deserialize)]
468#[serde(untagged)]
469pub enum SerializableTransactionType {
470 TypedTransaction(TypedTransaction),
471 MaybeImpersonatedTransaction(MaybeImpersonatedTransaction),
472}
473
474#[derive(Clone, Debug, Serialize, Deserialize)]
475pub struct SerializableBlock {
476 pub header: Header,
477 pub transactions: Vec<SerializableTransactionType>,
478 pub ommers: Vec<Header>,
479}
480
481impl From<Block> for SerializableBlock {
482 fn from(block: Block) -> Self {
483 Self {
484 header: block.header,
485 transactions: block.transactions.into_iter().map(Into::into).collect(),
486 ommers: block.ommers.into_iter().collect(),
487 }
488 }
489}
490
491impl From<SerializableBlock> for Block {
492 fn from(block: SerializableBlock) -> Self {
493 Self {
494 header: block.header,
495 transactions: block.transactions.into_iter().map(Into::into).collect(),
496 ommers: block.ommers.into_iter().collect(),
497 }
498 }
499}
500
501impl From<MaybeImpersonatedTransaction> for SerializableTransactionType {
502 fn from(transaction: MaybeImpersonatedTransaction) -> Self {
503 Self::MaybeImpersonatedTransaction(transaction)
504 }
505}
506
507impl From<SerializableTransactionType> for MaybeImpersonatedTransaction {
508 fn from(transaction: SerializableTransactionType) -> Self {
509 match transaction {
510 SerializableTransactionType::TypedTransaction(tx) => Self::new(tx),
511 SerializableTransactionType::MaybeImpersonatedTransaction(tx) => tx,
512 }
513 }
514}
515
516#[derive(Clone, Debug, Serialize, Deserialize)]
517pub struct SerializableTransaction {
518 pub info: TransactionInfo,
519 pub receipt: TypedReceipt,
520 pub block_hash: B256,
521 pub block_number: u64,
522}
523
524impl From<MinedTransaction> for SerializableTransaction {
525 fn from(transaction: MinedTransaction) -> Self {
526 Self {
527 info: transaction.info,
528 receipt: transaction.receipt,
529 block_hash: transaction.block_hash,
530 block_number: transaction.block_number,
531 }
532 }
533}
534
535impl From<SerializableTransaction> for MinedTransaction {
536 fn from(transaction: SerializableTransaction) -> Self {
537 Self {
538 info: transaction.info,
539 receipt: transaction.receipt,
540 block_hash: transaction.block_hash,
541 block_number: transaction.block_number,
542 }
543 }
544}
545
546#[derive(Clone, Debug, Serialize, Deserialize, Default)]
547pub struct SerializableHistoricalStates(Vec<(B256, StateSnapshot)>);
548
549impl SerializableHistoricalStates {
550 pub const fn new(states: Vec<(B256, StateSnapshot)>) -> Self {
551 Self(states)
552 }
553}
554
555impl IntoIterator for SerializableHistoricalStates {
556 type Item = (B256, StateSnapshot);
557 type IntoIter = std::vec::IntoIter<Self::Item>;
558
559 fn into_iter(self) -> Self::IntoIter {
560 self.0.into_iter()
561 }
562}
563
564#[cfg(test)]
565mod test {
566 use super::*;
567
568 #[test]
569 fn test_deser_block() {
570 let block = r#"{
571 "header": {
572 "parentHash": "0xceb0fe420d6f14a8eeec4319515b89acbb0bb4861cad9983d529ab4b1e4af929",
573 "sha3Uncles": "0x1dcc4de8dec75d7aab85b567b6ccd41ad312451b948a7413f0a142fd40d49347",
574 "miner": "0x0000000000000000000000000000000000000000",
575 "stateRoot": "0xe1423fd180478ab4fd05a7103277d64496b15eb914ecafe71eeec871b552efd1",
576 "transactionsRoot": "0x2b5598ef261e5f88e4303bb2b3986b3d5c0ebf4cd9977daebccae82a6469b988",
577 "receiptsRoot": "0xf78dfb743fbd92ade140711c8bbc542b5e307f0ab7984eff35d751969fe57efa",
578 "logsBloom": "0x00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
579 "difficulty": "0x0",
580 "number": "0x2",
581 "gasLimit": "0x1c9c380",
582 "gasUsed": "0x5208",
583 "timestamp": "0x66cdc823",
584 "mixHash": "0x0000000000000000000000000000000000000000000000000000000000000000",
585 "nonce": "0x0000000000000000",
586 "baseFeePerGas": "0x342a1c58",
587 "blobGasUsed": "0x0",
588 "excessBlobGas": "0x0",
589 "extraData": "0x"
590 },
591 "transactions": [
592 {
593 "EIP1559": {
594 "chainId": "0x7a69",
595 "nonce": "0x0",
596 "gas": "0x5209",
597 "maxFeePerGas": "0x77359401",
598 "maxPriorityFeePerGas": "0x1",
599 "to": "0xf39fd6e51aad88f6f4ce6ab8827279cfffb92266",
600 "value": "0x0",
601 "accessList": [],
602 "input": "0x",
603 "r": "0x85c2794a580da137e24ccc823b45ae5cea99371ae23ee13860fcc6935f8305b0",
604 "s": "0x41de7fa4121dab284af4453d30928241208bafa90cdb701fe9bc7054759fe3cd",
605 "yParity": "0x0",
606 "hash": "0x8c9b68e8947ace33028dba167354fde369ed7bbe34911b772d09b3c64b861515"
607 }
608 }
609 ],
610 "ommers": []
611 }
612 "#;
613
614 let _block: SerializableBlock = serde_json::from_str(block).unwrap();
615 }
616}