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