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