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