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<'i, 'db, I: InspectorExt + ?Sized>(
42 db: &'db mut dyn DatabaseExt,
43 env: Env,
44 inspector: &'i mut I,
45) -> FoundryEvm<'db, &'i mut 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 chain_id(&self) -> u64 {
182 self.inner.ctx.cfg.chain_id
183 }
184
185 fn block(&self) -> &BlockEnv {
186 &self.inner.block
187 }
188
189 fn db_mut(&mut self) -> &mut Self::DB {
190 &mut self.inner.ctx.journaled_state.database
191 }
192
193 fn precompiles(&self) -> &Self::Precompiles {
194 &self.inner.precompiles
195 }
196
197 fn precompiles_mut(&mut self) -> &mut Self::Precompiles {
198 &mut self.inner.precompiles
199 }
200
201 fn inspector(&self) -> &Self::Inspector {
202 &self.inner.inspector
203 }
204
205 fn inspector_mut(&mut self) -> &mut Self::Inspector {
206 &mut self.inner.inspector
207 }
208
209 fn set_inspector_enabled(&mut self, _enabled: bool) {
210 unimplemented!("FoundryEvm is always inspecting")
211 }
212
213 fn transact_raw(
214 &mut self,
215 tx: Self::Tx,
216 ) -> Result<ResultAndState<Self::HaltReason>, Self::Error> {
217 self.inner.ctx.tx = tx;
218
219 let mut handler = FoundryHandler::<I>::default();
220 let result = handler.inspect_run(&mut self.inner)?;
221
222 Ok(ResultAndState::new(result, self.inner.ctx.journaled_state.inner.state.clone()))
223 }
224
225 fn transact_system_call(
226 &mut self,
227 _caller: Address,
228 _contract: Address,
229 _data: Bytes,
230 ) -> Result<ExecResultAndState<ExecutionResult>, Self::Error> {
231 unimplemented!()
232 }
233
234 fn finish(self) -> (Self::DB, EvmEnv<Self::Spec>)
235 where
236 Self: Sized,
237 {
238 let Context { block: block_env, cfg: cfg_env, journaled_state, .. } = self.inner.ctx;
239
240 (journaled_state.database, EvmEnv { block_env, cfg_env })
241 }
242}
243
244impl<'db, I: InspectorExt> Deref for FoundryEvm<'db, I> {
245 type Target = Context<BlockEnv, TxEnv, CfgEnv, &'db mut dyn DatabaseExt>;
246
247 fn deref(&self) -> &Self::Target {
248 &self.inner.ctx
249 }
250}
251
252impl<I: InspectorExt> DerefMut for FoundryEvm<'_, I> {
253 fn deref_mut(&mut self) -> &mut Self::Target {
254 &mut self.inner.ctx
255 }
256}
257
258pub struct FoundryHandler<'db, I: InspectorExt> {
259 create2_overrides: Vec<(usize, CallInputs)>,
260 _phantom: PhantomData<(&'db mut dyn DatabaseExt, I)>,
261}
262
263impl<I: InspectorExt> Default for FoundryHandler<'_, I> {
264 fn default() -> Self {
265 Self { create2_overrides: Vec::new(), _phantom: PhantomData }
266 }
267}
268
269impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> {
272 type Evm = RevmEvm<
273 EthEvmContext<&'db mut dyn DatabaseExt>,
274 I,
275 EthInstructions<EthInterpreter, EthEvmContext<&'db mut dyn DatabaseExt>>,
276 PrecompilesMap,
277 EthFrame<EthInterpreter>,
278 >;
279 type Error = EVMError<DatabaseError>;
280 type HaltReason = HaltReason;
281}
282
283impl<'db, I: InspectorExt> FoundryHandler<'db, I> {
284 fn handle_create_frame(
287 &mut self,
288 evm: &mut <Self as Handler>::Evm,
289 init: &mut FrameInit,
290 ) -> Result<Option<FrameResult>, <Self as Handler>::Error> {
291 if let FrameInput::Create(inputs) = &init.frame_input
292 && let CreateScheme::Create2 { salt } = inputs.scheme
293 {
294 let (ctx, inspector) = evm.ctx_inspector();
295
296 if inspector.should_use_create2_factory(ctx, inputs) {
297 let gas_limit = inputs.gas_limit;
298
299 let create2_deployer = evm.inspector().create2_deployer();
301
302 let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
304
305 self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
307
308 let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash;
310 if code_hash == KECCAK_EMPTY {
311 return Ok(Some(FrameResult::Call(CallOutcome {
312 result: InterpreterResult {
313 result: InstructionResult::Revert,
314 output: Bytes::copy_from_slice(
315 format!("missing CREATE2 deployer: {create2_deployer}").as_bytes(),
316 ),
317 gas: Gas::new(gas_limit),
318 },
319 memory_offset: 0..0,
320 })));
321 } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH {
322 return Ok(Some(FrameResult::Call(CallOutcome {
323 result: InterpreterResult {
324 result: InstructionResult::Revert,
325 output: "invalid CREATE2 deployer bytecode".into(),
326 gas: Gas::new(gas_limit),
327 },
328 memory_offset: 0..0,
329 })));
330 }
331
332 init.frame_input = FrameInput::Call(Box::new(call_inputs));
334 }
335 }
336 Ok(None)
337 }
338
339 fn handle_create2_override(
341 &mut self,
342 evm: &mut <Self as Handler>::Evm,
343 result: FrameResult,
344 ) -> FrameResult {
345 if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) {
346 let (_, call_inputs) = self.create2_overrides.pop().unwrap();
347 let FrameResult::Call(mut call) = result else {
348 unreachable!("create2 override should be a call frame");
349 };
350
351 let address = match call.instruction_result() {
353 return_ok!() => Address::try_from(call.output().as_ref())
354 .map_err(|_| {
355 call.result = InterpreterResult {
356 result: InstructionResult::Revert,
357 output: "invalid CREATE2 factory output".into(),
358 gas: Gas::new(call_inputs.gas_limit),
359 };
360 })
361 .ok(),
362 _ => None,
363 };
364
365 FrameResult::Create(CreateOutcome { result: call.result, address })
366 } else {
367 result
368 }
369 }
370}
371
372impl<I: InspectorExt> InspectorHandler for FoundryHandler<'_, I> {
373 type IT = EthInterpreter;
374
375 fn inspect_run_exec_loop(
376 &mut self,
377 evm: &mut Self::Evm,
378 first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
379 ) -> Result<FrameResult, Self::Error> {
380 let res = evm.inspect_frame_init(first_frame_input)?;
381
382 if let ItemOrResult::Result(frame_result) = res {
383 return Ok(frame_result);
384 }
385
386 loop {
387 let call_or_result = evm.inspect_frame_run()?;
388
389 let result = match call_or_result {
390 ItemOrResult::Item(mut init) => {
391 if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? {
393 return Ok(frame_result);
394 }
395
396 match evm.inspect_frame_init(init)? {
397 ItemOrResult::Item(_) => continue,
398 ItemOrResult::Result(result) => result,
399 }
400 }
401 ItemOrResult::Result(result) => result,
402 };
403
404 let result = self.handle_create2_override(evm, result);
406
407 if let Some(result) = evm.frame_return_result(result)? {
408 return Ok(result);
409 }
410 }
411 }
412}