1use std::{
2 marker::PhantomData,
3 ops::{Deref, DerefMut},
4};
5
6use crate::{
7 EthCheatCtx, EthInspectorExt,
8 backend::{DatabaseExt, JournaledState},
9 constants::DEFAULT_CREATE2_DEPLOYER_CODEHASH,
10};
11use alloy_consensus::constants::KECCAK_EMPTY;
12use alloy_evm::{Evm, EvmEnv, EvmFactory, eth::EthEvmContext, precompiles::PrecompilesMap};
13use alloy_primitives::{Address, Bytes, U256};
14use foundry_fork_db::DatabaseError;
15use revm::{
16 Context,
17 context::{
18 BlockEnv, Cfg, CfgEnv, ContextTr, CreateScheme, Evm as RevmEvm, JournalTr, LocalContextTr,
19 TxEnv,
20 result::{EVMError, ExecResultAndState, ExecutionResult, HaltReason, ResultAndState},
21 },
22 handler::{
23 EthFrame, EvmTr, FrameResult, FrameTr, Handler, ItemOrResult, instructions::EthInstructions,
24 },
25 inspector::{InspectorEvmTr, InspectorHandler},
26 interpreter::{
27 CallInput, CallInputs, CallOutcome, CallScheme, CallValue, CreateInputs, CreateOutcome,
28 FrameInput, Gas, InstructionResult, InterpreterResult, SharedMemory,
29 interpreter::EthInterpreter, interpreter_action::FrameInit, return_ok,
30 },
31 primitives::hardfork::SpecId,
32};
33
34pub fn new_eth_evm_with_inspector<'db, I: EthInspectorExt>(
35 db: &'db mut dyn DatabaseExt,
36 evm_env: EvmEnv,
37 tx_env: TxEnv,
38 inspector: I,
39) -> FoundryEvm<'db, I> {
40 let eth_evm =
41 alloy_evm::EthEvmFactory::default().create_evm_with_inspector(db, evm_env, inspector);
42 let mut inner = eth_evm.into_inner();
43 inner.ctx.cfg.tx_chain_id_check = true;
44 inner.ctx.tx = tx_env;
45
46 let mut evm = FoundryEvm { inner };
47 evm.inspector().get_networks().inject_precompiles(evm.precompiles_mut());
48 evm
49}
50
51fn get_create2_factory_call_inputs(
53 salt: U256,
54 inputs: &CreateInputs,
55 deployer: Address,
56) -> CallInputs {
57 let calldata = [&salt.to_be_bytes::<32>()[..], &inputs.init_code()[..]].concat();
58 CallInputs {
59 caller: inputs.caller(),
60 bytecode_address: deployer,
61 known_bytecode: None,
62 target_address: deployer,
63 scheme: CallScheme::Call,
64 value: CallValue::Transfer(inputs.value()),
65 input: CallInput::Bytes(calldata.into()),
66 gas_limit: inputs.gas_limit(),
67 is_static: false,
68 return_memory_offset: 0..0,
69 }
70}
71
72pub struct FoundryEvm<'db, I: EthInspectorExt> {
73 #[allow(clippy::type_complexity)]
74 inner: RevmEvm<
75 EthEvmContext<&'db mut dyn DatabaseExt>,
76 I,
77 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,
78 PrecompilesMap,
79 EthFrame<EthInterpreter>,
80 >,
81}
82
83impl<'db, I: EthInspectorExt> Evm for FoundryEvm<'db, I> {
84 type Precompiles = PrecompilesMap;
85 type Inspector = I;
86 type DB = &'db mut dyn DatabaseExt;
87 type Error = EVMError<DatabaseError>;
88 type HaltReason = HaltReason;
89 type Spec = SpecId;
90 type Tx = TxEnv;
91 type BlockEnv = BlockEnv;
92
93 fn block(&self) -> &BlockEnv {
94 &self.inner.block
95 }
96
97 fn chain_id(&self) -> u64 {
98 self.inner.ctx.cfg.chain_id
99 }
100
101 fn components(&self) -> (&Self::DB, &Self::Inspector, &Self::Precompiles) {
102 (&self.inner.ctx.journaled_state.database, &self.inner.inspector, &self.inner.precompiles)
103 }
104
105 fn components_mut(&mut self) -> (&mut Self::DB, &mut Self::Inspector, &mut Self::Precompiles) {
106 (
107 &mut self.inner.ctx.journaled_state.database,
108 &mut self.inner.inspector,
109 &mut self.inner.precompiles,
110 )
111 }
112
113 fn set_inspector_enabled(&mut self, _enabled: bool) {
114 unimplemented!("FoundryEvm is always inspecting")
115 }
116
117 fn transact_raw(
118 &mut self,
119 tx: Self::Tx,
120 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
121 self.inner.ctx.tx = tx;
122
123 let mut handler = FoundryHandler::<I>::default();
124 let result = handler.inspect_run(&mut self.inner)?;
125
126 Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))
127 }
128
129 fn transact_system_call(
130 &mut self,
131 _caller: Address,
132 _contract: Address,
133 _data: Bytes,
134 ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {
135 unimplemented!()
136 }
137
138 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
139 where
140 Self: Sized,
141 {
142 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;
143
144 (journaled_state.database, EvmEnv { block_env, cfg_env })
145 }
146}
147
148impl<'db, I: EthInspectorExt> Deref for FoundryEvm<'db, I> {
149 type Target = Context<BlockEnv, TxEnv, CfgEnv, &'db mut dyn DatabaseExt>;
150
151 fn deref(&self) -> &Self::Target {
152 &self.inner.ctx
153 }
154}
155
156impl<I: EthInspectorExt> DerefMut for FoundryEvm<'_, I> {
157 fn deref_mut(&mut self) -> &mut Self::Target {
158 &mut self.inner.ctx
159 }
160}
161
162pub trait NestedEvm {
167 type Tx;
169 type Block;
171 type Spec;
173
174 fn journal_inner_mut(&mut self) -> &mut JournaledState;
176
177 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>>;
179
180 fn transact(
182 &mut self,
183 tx: Self::Tx,
184 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>>;
185
186 fn to_evm_env(&self) -> EvmEnv<Self::Spec, Self::Block>;
188}
189
190impl<I: EthInspectorExt> NestedEvm for FoundryEvm<'_, I> {
191 type Tx = TxEnv;
192 type Block = BlockEnv;
193 type Spec = SpecId;
194
195 fn journal_inner_mut(&mut self) -> &mut JournaledState {
196 &mut self.inner.ctx.journaled_state.inner
197 }
198
199 fn run_execution(&mut self, frame: FrameInput) -> Result<FrameResult, EVMError<DatabaseError>> {
200 let mut handler = FoundryHandler::<I>::default();
201
202 let memory =
204 SharedMemory::new_with_buffer(self.inner.ctx().local().shared_memory_buffer().clone());
205 let first_frame_input = FrameInit { depth: 0, memory, frame_input: frame };
206
207 let mut frame_result = handler.inspect_run_exec_loop(&mut self.inner, first_frame_input)?;
209
210 handler.last_frame_result(&mut self.inner, &mut frame_result)?;
212
213 Ok(frame_result)
214 }
215
216 fn transact(
217 &mut self,
218 tx: TxEnv,
219 ) -> Result<ResultAndState<HaltReason>, EVMError<DatabaseError>> {
220 Evm::transact_raw(self, tx)
221 }
222
223 fn to_evm_env(&self) -> EvmEnv {
224 EvmEnv { cfg_env: self.inner.ctx.cfg.clone(), block_env: self.inner.ctx.block.clone() }
225 }
226}
227
228pub type NestedEvmClosure<'a, Block, Tx, Spec> =
230 &'a mut dyn FnMut(
231 &mut dyn NestedEvm<Block = Block, Tx = Tx, Spec = Spec>,
232 ) -> Result<(), EVMError<DatabaseError>>;
233
234pub fn with_cloned_context<CTX: EthCheatCtx>(
239 ecx: &mut CTX,
240 f: impl FnOnce(
241 &mut dyn DatabaseExt<CTX::Block, CTX::Tx, <CTX::Cfg as Cfg>::Spec>,
242 EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>,
243 CTX::Tx,
244 JournaledState,
245 ) -> Result<
246 (EvmEnv<<CTX::Cfg as Cfg>::Spec, CTX::Block>, JournaledState),
247 EVMError<DatabaseError>,
248 >,
249) -> Result<(), EVMError<DatabaseError>> {
250 let evm_env = ecx.evm_clone();
251 let tx_env = ecx.tx_clone();
252
253 let (db, journal_inner) = ecx.db_journal_inner_mut();
254 let journal_inner_clone = journal_inner.clone();
255
256 let (sub_evm_env, sub_inner) = f(db, evm_env, tx_env, journal_inner_clone)?;
257
258 ecx.set_journal_inner(sub_inner);
260 ecx.set_evm(sub_evm_env);
261
262 Ok(())
263}
264
265pub struct FoundryHandler<'db, I: EthInspectorExt> {
266 create2_overrides: Vec<(usize, CallInputs)>,
267 _phantom: PhantomData<(&'db mut dyn DatabaseExt, I)>,
268}
269
270impl<I: EthInspectorExt> Default for FoundryHandler<'_, I> {
271 fn default() -> Self {
272 Self { create2_overrides: Vec::new(), _phantom: PhantomData }
273 }
274}
275
276impl<'db, I: EthInspectorExt> Handler for FoundryHandler<'db, I> {
279 type Evm = RevmEvm<
280 EthEvmContext<&'db mut dyn DatabaseExt>,
281 I,
282 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,
283 PrecompilesMap,
284 EthFrame<EthInterpreter>,
285 >;
286 type Error = EVMError<DatabaseError>;
287 type HaltReason = HaltReason;
288}
289
290impl<'db, I: EthInspectorExt> FoundryHandler<'db, I> {
291 fn handle_create_frame(
294 &mut self,
295 evm: &mut <Self as Handler>::Evm,
296 init: &mut FrameInit,
297 ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {
298 if let FrameInput::Create(inputs) = &init.frame_input
299 && let CreateScheme::Create2 { salt } = inputs.scheme()
300 {
301 let (ctx, inspector) = evm.ctx_inspector();
302
303 if inspector.should_use_create2_factory(ctx.journal().depth(), inputs) {
304 let gas_limit = inputs.gas_limit();
305
306 let create2_deployer = evm.inspector().create2_deployer();
308
309 let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
311
312 self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
314
315 let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
317 if code_hash == KECCAK_EMPTY {
318 return Ok(Some(FrameResult::Call(CallOutcome {
319 result: InterpreterResult {
320 result: InstructionResult::Revert,
321 output: Bytes::from(
322 format!("missing CREATE2 deployer: {create2_deployer}")
323 .into_bytes(),
324 ),
325 gas: Gas::new(gas_limit),
326 },
327 memory_offset: 0..0,
328 was_precompile_called: false,
329 precompile_call_logs: vec![],
330 })));
331 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
332 return Ok(Some(FrameResult::Call(CallOutcome {
333 result: InterpreterResult {
334 result: InstructionResult::Revert,
335 output: "invalid CREATE2 deployer bytecode".into(),
336 gas: Gas::new(gas_limit),
337 },
338 memory_offset: 0..0,
339 was_precompile_called: false,
340 precompile_call_logs: vec![],
341 })));
342 }
343
344 init.frame_input = FrameInput::Call(Box::new(call_inputs));
346 }
347 }
348 Ok(None)
349 }
350
351 fn handle_create2_override(
353 &mut self,
354 evm: &mut <Self as Handler>::Evm,
355 result: FrameResult,
356 ) -> FrameResult {
357 if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
358 let (_, call_inputs) = self.create2_overrides.pop().unwrap();
359 let FrameResult::Call(mut call) = result else {
360 unreachable!("create2 override should be a call frame");
361 };
362
363 let address = match call.instruction_result() {
365 return_ok!() => Address::try_from(call.output().as_ref())
366 .map_err(|_| {
367 call.result = InterpreterResult {
368 result: InstructionResult::Revert,
369 output: "invalid CREATE2 factory output".into(),
370 gas: Gas::new(call_inputs.gas_limit),
371 };
372 })
373 .ok(),
374 _ => None,
375 };
376
377 FrameResult::Create(CreateOutcome { result: call.result, address })
378 } else {
379 result
380 }
381 }
382}
383
384impl<I: EthInspectorExt> InspectorHandler for FoundryHandler<'_, I> {
385 type IT = EthInterpreter;
386
387 fn inspect_run_exec_loop(
388 &mut self,
389 evm: &mut Self::Evm,
390 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
391 ) -> Result<FrameResult, Self::Error> {
392 let res = evm.inspect_frame_init(first_frame_input)?;
393
394 if let ItemOrResult::Result(frame_result) = res {
395 return Ok(frame_result);
396 }
397
398 loop {
399 let call_or_result = evm.inspect_frame_run()?;
400
401 let result = match call_or_result {
402 ItemOrResult::Item(mut init) => {
403 if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {
405 return Ok(frame_result);
406 }
407
408 match evm.inspect_frame_init(init)? {
409 ItemOrResult::Item(_) => continue,
410 ItemOrResult::Result(result) => result,
411 }
412 }
413 ItemOrResult::Result(result) => result,
414 };
415
416 let result = self.handle_create2_override(evm, result);
418
419 if let Some(result) = evm.frame_return_result(result)? {
420 return Ok(result);
421 }
422 }
423 }
424}