foundry_evm_core/backend/
cow.rs1use super::BackendError;
4use crate::{
5 FoundryInspectorExt,
6 backend::{
7 Backend, DatabaseExt, JournaledState, LocalForkId, RevertStateSnapshotAction,
8 diagnostic::RevertDiagnostic,
9 },
10 evm::{
11 EvmEnvFor, FoundryContextFor, FoundryEvmFactory, FoundryEvmNetwork, HaltReasonFor, SpecFor,
12 TxEnvFor,
13 },
14 fork::{CreateFork, ForkId},
15};
16use alloy_evm::Evm;
17use alloy_genesis::GenesisAccount;
18use alloy_primitives::{Address, B256, TxKind, U256};
19use eyre::WrapErr;
20use foundry_fork_db::DatabaseError;
21use revm::{
22 Database, DatabaseCommit,
23 bytecode::Bytecode,
24 context::{ContextTr, Transaction},
25 context_interface::result::ResultAndState,
26 database::DatabaseRef,
27 primitives::AddressMap,
28 state::{Account, AccountInfo, EvmState},
29};
30use std::{borrow::Cow, collections::BTreeMap, fmt::Debug};
31
32pub struct CowBackend<'a, FEN: FoundryEvmNetwork> {
49 pub backend: Cow<'a, Backend<FEN>>,
53 pending_init: Option<(SpecFor<FEN>, Address, TxKind)>,
56}
57
58impl<FEN: FoundryEvmNetwork> Clone for CowBackend<'_, FEN> {
59 fn clone(&self) -> Self {
60 Self { backend: self.backend.clone(), pending_init: self.pending_init }
61 }
62}
63
64impl<FEN: FoundryEvmNetwork> Debug for CowBackend<'_, FEN> {
65 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
66 f.debug_struct("CowBackend")
67 .field("backend", &self.backend)
68 .field("pending_init", &self.pending_init)
69 .finish()
70 }
71}
72
73impl<'a, FEN: FoundryEvmNetwork> CowBackend<'a, FEN> {
74 pub const fn new_borrowed(backend: &'a Backend<FEN>) -> Self {
76 Self { backend: Cow::Borrowed(backend), pending_init: None }
77 }
78
79 #[instrument(name = "inspect", level = "debug", skip_all)]
84 pub fn inspect<I: for<'db> FoundryInspectorExt<FoundryContextFor<'db, FEN>>>(
85 &mut self,
86 evm_env: &mut EvmEnvFor<FEN>,
87 tx_env: &mut TxEnvFor<FEN>,
88 inspector: I,
89 ) -> eyre::Result<ResultAndState<HaltReasonFor<FEN>>> {
90 self.pending_init = Some((evm_env.cfg_env.spec, tx_env.caller(), tx_env.kind()));
93
94 let mut evm = FEN::EvmFactory::default().create_foundry_evm_with_inspector(
95 self,
96 evm_env.clone(),
97 inspector,
98 );
99
100 let res = evm.transact(tx_env.clone()).wrap_err("EVM error")?;
101
102 *tx_env = evm.tx().clone();
103 *evm_env = evm.finish().1;
104
105 Ok(res)
106 }
107
108 pub fn has_state_snapshot_failure(&self) -> bool {
112 self.backend.has_state_snapshot_failure()
113 }
114
115 fn backend_mut(&mut self) -> &mut Backend<FEN> {
119 if let Some((spec_id, caller, tx_kind)) = self.pending_init.take() {
120 let backend = self.backend.to_mut();
121 backend.initialize(spec_id, caller, tx_kind);
122 return backend;
123 }
124 self.backend.to_mut()
125 }
126
127 fn initialized_backend_mut(&mut self) -> Option<&mut Backend<FEN>> {
129 if self.pending_init.is_none() {
130 return Some(self.backend.to_mut());
131 }
132 None
133 }
134}
135
136impl<FEN: FoundryEvmNetwork> DatabaseExt<FEN::EvmFactory> for CowBackend<'_, FEN> {
137 fn snapshot_state(
138 &mut self,
139 journaled_state: &JournaledState,
140 evm_env: &EvmEnvFor<FEN>,
141 ) -> U256 {
142 self.backend_mut().snapshot_state(journaled_state, evm_env)
143 }
144
145 fn revert_state(
146 &mut self,
147 id: U256,
148 journaled_state: &JournaledState,
149 evm_env: &mut EvmEnvFor<FEN>,
150 caller: Address,
151 action: RevertStateSnapshotAction,
152 ) -> Option<JournaledState> {
153 self.backend_mut().revert_state(id, journaled_state, evm_env, caller, action)
154 }
155
156 fn delete_state_snapshot(&mut self, id: U256) -> bool {
157 if let Some(backend) = self.initialized_backend_mut() {
159 return backend.delete_state_snapshot(id);
160 }
161 false
162 }
163
164 fn delete_state_snapshots(&mut self) {
165 if let Some(backend) = self.initialized_backend_mut() {
166 backend.delete_state_snapshots()
167 }
168 }
169
170 fn create_fork(&mut self, fork: CreateFork) -> eyre::Result<LocalForkId> {
171 self.backend.to_mut().create_fork(fork)
172 }
173
174 fn create_fork_at_transaction(
175 &mut self,
176 fork: CreateFork,
177 transaction: B256,
178 ) -> eyre::Result<LocalForkId> {
179 self.backend.to_mut().create_fork_at_transaction(fork, transaction)
180 }
181
182 fn select_fork(
183 &mut self,
184 id: LocalForkId,
185 evm_env: &mut EvmEnvFor<FEN>,
186 tx_env: &mut TxEnvFor<FEN>,
187 journaled_state: &mut JournaledState,
188 ) -> eyre::Result<()> {
189 self.backend_mut().select_fork(id, evm_env, tx_env, journaled_state)
190 }
191
192 fn roll_fork(
193 &mut self,
194 id: Option<LocalForkId>,
195 block_number: u64,
196 evm_env: &mut EvmEnvFor<FEN>,
197 journaled_state: &mut JournaledState,
198 ) -> eyre::Result<()> {
199 self.backend_mut().roll_fork(id, block_number, evm_env, journaled_state)
200 }
201
202 fn roll_fork_to_transaction(
203 &mut self,
204 id: Option<LocalForkId>,
205 transaction: B256,
206 evm_env: &mut EvmEnvFor<FEN>,
207 journaled_state: &mut JournaledState,
208 ) -> eyre::Result<()> {
209 self.backend_mut().roll_fork_to_transaction(id, transaction, evm_env, journaled_state)
210 }
211
212 fn transact(
213 &mut self,
214 id: Option<LocalForkId>,
215 transaction: B256,
216 evm_env: EvmEnvFor<FEN>,
217 journaled_state: &mut JournaledState,
218 inspector: &mut dyn for<'db> FoundryInspectorExt<
219 <FEN::EvmFactory as FoundryEvmFactory>::FoundryContext<'db>,
220 >,
221 ) -> eyre::Result<()> {
222 self.backend_mut().transact(id, transaction, evm_env, journaled_state, inspector)
223 }
224
225 fn transact_from_tx(
226 &mut self,
227 tx_env: TxEnvFor<FEN>,
228 evm_env: EvmEnvFor<FEN>,
229 journaled_state: &mut JournaledState,
230 inspector: &mut dyn for<'db> FoundryInspectorExt<
231 <FEN::EvmFactory as FoundryEvmFactory>::FoundryContext<'db>,
232 >,
233 ) -> eyre::Result<()> {
234 self.backend_mut().transact_from_tx(tx_env, evm_env, journaled_state, inspector)
235 }
236
237 fn active_fork_id(&self) -> Option<LocalForkId> {
238 self.backend.active_fork_id()
239 }
240
241 fn active_fork_url(&self) -> Option<String> {
242 self.backend.active_fork_url()
243 }
244
245 fn ensure_fork(&self, id: Option<LocalForkId>) -> eyre::Result<LocalForkId> {
246 self.backend.ensure_fork(id)
247 }
248
249 fn ensure_fork_id(&self, id: LocalForkId) -> eyre::Result<&ForkId> {
250 self.backend.ensure_fork_id(id)
251 }
252
253 fn diagnose_revert(&self, callee: Address, evm_state: &EvmState) -> Option<RevertDiagnostic> {
254 self.backend.diagnose_revert(callee, evm_state)
255 }
256
257 fn load_allocs(
258 &mut self,
259 allocs: &BTreeMap<Address, GenesisAccount>,
260 journaled_state: &mut JournaledState,
261 ) -> Result<(), BackendError> {
262 self.backend.to_mut().load_allocs(allocs, journaled_state)
263 }
264
265 fn clone_account(
266 &mut self,
267 source: &GenesisAccount,
268 target: &Address,
269 journaled_state: &mut JournaledState,
270 ) -> Result<(), BackendError> {
271 self.backend.to_mut().clone_account(source, target, journaled_state)
272 }
273
274 fn is_persistent(&self, acc: &Address) -> bool {
275 self.backend.is_persistent(acc)
276 }
277
278 fn remove_persistent_account(&mut self, account: &Address) -> bool {
279 self.backend.to_mut().remove_persistent_account(account)
280 }
281
282 fn add_persistent_account(&mut self, account: Address) -> bool {
283 self.backend.to_mut().add_persistent_account(account)
284 }
285
286 fn allow_cheatcode_access(&mut self, account: Address) -> bool {
287 self.backend.to_mut().allow_cheatcode_access(account)
288 }
289
290 fn revoke_cheatcode_access(&mut self, account: &Address) -> bool {
291 self.backend.to_mut().revoke_cheatcode_access(account)
292 }
293
294 fn has_cheatcode_access(&self, account: &Address) -> bool {
295 self.backend.has_cheatcode_access(account)
296 }
297
298 fn set_blockhash(&mut self, block_number: U256, block_hash: B256) {
299 self.backend.to_mut().set_blockhash(block_number, block_hash);
300 }
301}
302
303impl<FEN: FoundryEvmNetwork> DatabaseRef for CowBackend<'_, FEN> {
304 type Error = DatabaseError;
305
306 fn basic_ref(&self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
307 DatabaseRef::basic_ref(self.backend.as_ref(), address)
308 }
309
310 fn code_by_hash_ref(&self, code_hash: B256) -> Result<Bytecode, Self::Error> {
311 DatabaseRef::code_by_hash_ref(self.backend.as_ref(), code_hash)
312 }
313
314 fn storage_ref(&self, address: Address, index: U256) -> Result<U256, Self::Error> {
315 DatabaseRef::storage_ref(self.backend.as_ref(), address, index)
316 }
317
318 fn block_hash_ref(&self, number: u64) -> Result<B256, Self::Error> {
319 DatabaseRef::block_hash_ref(self.backend.as_ref(), number)
320 }
321}
322
323impl<FEN: FoundryEvmNetwork> Database for CowBackend<'_, FEN> {
324 type Error = DatabaseError;
325
326 fn basic(&mut self, address: Address) -> Result<Option<AccountInfo>, Self::Error> {
327 DatabaseRef::basic_ref(self, address)
328 }
329
330 fn code_by_hash(&mut self, code_hash: B256) -> Result<Bytecode, Self::Error> {
331 DatabaseRef::code_by_hash_ref(self, code_hash)
332 }
333
334 fn storage(&mut self, address: Address, index: U256) -> Result<U256, Self::Error> {
335 DatabaseRef::storage_ref(self, address, index)
336 }
337
338 fn block_hash(&mut self, number: u64) -> Result<B256, Self::Error> {
339 DatabaseRef::block_hash_ref(self, number)
340 }
341}
342
343impl<FEN: FoundryEvmNetwork> DatabaseCommit for CowBackend<'_, FEN> {
344 fn commit(&mut self, changes: AddressMap<Account>) {
345 self.backend.to_mut().commit(changes)
346 }
347}