foundry_evm_core/
evm.rs

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
87/// Get the precompiles for the given spec.
88fn 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
98/// Get the call inputs for the CREATE2 factory.
99fn 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        // Create first frame
136        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        // Run execution loop
141        let mut frame_result = handler.inspect_run_exec_loop(&mut self.inner, first_frame_input)?;
142
143        // Handle last frame result
144        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
259// Blanket Handler implementation for FoundryHandler, needed for implementing the InspectorHandler
260// trait.
261impl<'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    /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2
275    /// factory.
276    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                // Get CREATE2 deployer.
290                let create2_deployer = evm.inspector().create2_deployer();
291
292                // Generate call inputs for CREATE2 factory.
293                let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer);
294
295                // Push data about current override to the stack.
296                self.create2_overrides.push((evm.journal().depth(), call_inputs.clone()));
297
298                // Sanity check that CREATE2 deployer exists.
299                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                // Rewrite the frame init
324                init.frame_input = FrameInput::Call(Box::new(call_inputs));
325            }
326        }
327        Ok(None)
328    }
329
330    /// Transforms CREATE2 factory call results back into CREATE outcomes.
331    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            // Decode address from output.
343            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                    // Handle CREATE/CREATE2 frame initialization
383                    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            // Handle CREATE2 override transformation if needed
396            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}