anvil/eth/backend/mem/
fork_db.rs1use crate::eth::backend::db::{
2 Db, MaybeForkedDatabase, MaybeFullDatabase, SerializableAccountRecord, SerializableBlock,
3 SerializableHistoricalStates, SerializableState, SerializableTransaction, StateDb,
4};
5use alloy_primitives::{Address, B256, U256, map::HashMap};
6use alloy_rpc_types::BlockId;
7use foundry_evm::{
8 backend::{BlockchainDb, DatabaseResult, RevertStateSnapshotAction, StateSnapshot},
9 fork::database::ForkDbStateSnapshot,
10};
11use revm::{
12 context::BlockEnv,
13 database::{Database, DbAccount},
14 state::AccountInfo,
15};
16
17pub use foundry_evm::fork::database::ForkedDatabase;
18
19impl Db for ForkedDatabase {
20 fn insert_account(&mut self, address: Address, account: AccountInfo) {
21 self.database_mut().insert_account(address, account)
22 }
23
24 fn set_storage_at(&mut self, address: Address, slot: B256, val: B256) -> DatabaseResult<()> {
25 let _ = Database::basic(self, address)?;
27 self.database_mut().set_storage_at(address, slot, val)
28 }
29
30 fn insert_block_hash(&mut self, number: U256, hash: B256) {
31 self.inner().block_hashes().write().insert(number, hash);
32 }
33
34 fn dump_state(
35 &self,
36 at: BlockEnv,
37 best_number: u64,
38 blocks: Vec<SerializableBlock>,
39 transactions: Vec<SerializableTransaction>,
40 historical_states: Option<SerializableHistoricalStates>,
41 ) -> DatabaseResult<Option<SerializableState>> {
42 let mut db = self.database().clone();
43 let accounts = self
44 .database()
45 .cache
46 .accounts
47 .clone()
48 .into_iter()
49 .map(|(k, v)| -> DatabaseResult<_> {
50 let code = if let Some(code) = v.info.code {
51 code
52 } else {
53 db.code_by_hash(v.info.code_hash)?
54 };
55 Ok((
56 k,
57 SerializableAccountRecord {
58 nonce: v.info.nonce,
59 balance: v.info.balance,
60 code: code.original_bytes(),
61 storage: v.storage.into_iter().map(|(k, v)| (k.into(), v.into())).collect(),
62 },
63 ))
64 })
65 .collect::<Result<_, _>>()?;
66 Ok(Some(SerializableState {
67 block: Some(at),
68 accounts,
69 best_block_number: Some(best_number),
70 blocks,
71 transactions,
72 historical_states,
73 }))
74 }
75
76 fn snapshot_state(&mut self) -> U256 {
77 self.insert_state_snapshot()
78 }
79
80 fn revert_state(&mut self, id: U256, action: RevertStateSnapshotAction) -> bool {
81 self.revert_state_snapshot(id, action)
82 }
83
84 fn current_state(&self) -> StateDb {
85 StateDb::new(self.create_state_snapshot())
86 }
87}
88
89impl MaybeFullDatabase for ForkedDatabase {
90 fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
91 Some(&self.database().cache.accounts)
92 }
93
94 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
95 let db = self.inner().db();
96 let accounts = std::mem::take(&mut *db.accounts.write());
97 let storage = std::mem::take(&mut *db.storage.write());
98 let block_hashes = std::mem::take(&mut *db.block_hashes.write());
99 StateSnapshot { accounts, storage, block_hashes }
100 }
101
102 fn read_as_state_snapshot(&self) -> StateSnapshot {
103 let db = self.inner().db();
104 let accounts = db.accounts.read().clone();
105 let storage = db.storage.read().clone();
106 let block_hashes = db.block_hashes.read().clone();
107 StateSnapshot { accounts, storage, block_hashes }
108 }
109
110 fn clear(&mut self) {
111 self.flush_cache();
112 self.clear_into_state_snapshot();
113 }
114
115 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
116 let db = self.inner().db();
117 let StateSnapshot { accounts, storage, block_hashes } = state_snapshot;
118 *db.accounts.write() = accounts;
119 *db.storage.write() = storage;
120 *db.block_hashes.write() = block_hashes;
121 }
122}
123
124impl MaybeFullDatabase for ForkDbStateSnapshot {
125 fn maybe_as_full_db(&self) -> Option<&HashMap<Address, DbAccount>> {
126 Some(&self.local.cache.accounts)
127 }
128
129 fn clear_into_state_snapshot(&mut self) -> StateSnapshot {
130 std::mem::take(&mut self.state_snapshot)
131 }
132
133 fn read_as_state_snapshot(&self) -> StateSnapshot {
134 self.state_snapshot.clone()
135 }
136
137 fn clear(&mut self) {
138 std::mem::take(&mut self.state_snapshot);
139 self.local.clear()
140 }
141
142 fn init_from_state_snapshot(&mut self, state_snapshot: StateSnapshot) {
143 self.state_snapshot = state_snapshot;
144 }
145}
146
147impl MaybeForkedDatabase for ForkedDatabase {
148 fn maybe_reset(&mut self, url: Option<String>, block_number: BlockId) -> Result<(), String> {
149 self.reset(url, block_number)
150 }
151
152 fn maybe_flush_cache(&self) -> Result<(), String> {
153 self.flush_cache();
154 Ok(())
155 }
156
157 fn maybe_inner(&self) -> Result<&BlockchainDb, String> {
158 Ok(self.inner())
159 }
160}