From 3f20426c99a9bc9069d7f569104b4a9a62b4b628 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Thu, 10 Jul 2025 12:53:14 +0530 Subject: [PATCH 1/3] fix(`evm`): Handler impl for FoundryEvm --- crates/evm/core/src/evm.rs | 64 ++------------------------------------ 1 file changed, 2 insertions(+), 62 deletions(-) diff --git a/crates/evm/core/src/evm.rs b/crates/evm/core/src/evm.rs index f9475aad43fe0..7ce56b831dfdd 100644 --- a/crates/evm/core/src/evm.rs +++ b/crates/evm/core/src/evm.rs @@ -266,6 +266,8 @@ impl Default for FoundryHandler<'_, I> { } } +// Blanket Handler implementation for FoundryHandler, needed for implementing the InspectorHandler +// trait. impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { type Evm = RevmEvm< EthEvmContext<&'db mut dyn DatabaseExt>, @@ -276,68 +278,6 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { >; type Error = EVMError; type HaltReason = HaltReason; - - fn run_exec_loop( - &mut self, - evm: &mut Self::Evm, - first_frame_input: <::Frame as FrameTr>::FrameInit, - ) -> Result { - let res = evm.frame_init(first_frame_input)?; - - if let ItemOrResult::Result(frame_result) = res { - return Ok(frame_result); - } - - loop { - let call_or_result = evm.frame_run()?; - - let result = match call_or_result { - ItemOrResult::Item(init) => { - match evm.frame_init(init)? { - ItemOrResult::Item(_) => { - continue; - } - // Do not pop the frame since no new frame was created - ItemOrResult::Result(result) => result, - } - } - ItemOrResult::Result(result) => result, - }; - - let result = if self - .create2_overrides - .last() - .is_some_and(|(depth, _)| *depth == evm.journal().depth()) - { - let (_, call_inputs) = self.create2_overrides.pop().unwrap(); - let FrameResult::Call(mut call) = result else { - unreachable!("create2 override should be a call frame"); - }; - - // Decode address from output. - let address = match call.instruction_result() { - return_ok!() => Address::try_from(call.output().as_ref()) - .map_err(|_| { - call.result = InterpreterResult { - result: InstructionResult::Revert, - output: "invalid CREATE2 factory output".into(), - gas: Gas::new(call_inputs.gas_limit), - }; - }) - .ok(), - _ => None, - }; - - FrameResult::Create(CreateOutcome { result: call.result, address }) - } else { - result - }; - - if let Some(result) = evm.frame_return_result(result)? { - return Ok(result); - } - } - } } impl InspectorHandler for FoundryHandler<'_, I> { From 1a145c86f8575ec5de104963cac8cb1cacea6ba3 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:29:10 +0530 Subject: [PATCH 2/3] cleanup --- crates/evm/core/src/evm.rs | 177 +++++++++++++++++++++---------------- 1 file changed, 100 insertions(+), 77 deletions(-) diff --git a/crates/evm/core/src/evm.rs b/crates/evm/core/src/evm.rs index 7ce56b831dfdd..cbe32b87dd809 100644 --- a/crates/evm/core/src/evm.rs +++ b/crates/evm/core/src/evm.rs @@ -280,6 +280,102 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { type HaltReason = HaltReason; } +impl<'db, I: InspectorExt> FoundryHandler<'db, I> { + /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2 factory. + fn handle_create_frame( + &mut self, + evm: &mut ::Evm, + init: &mut FrameInit, + ) -> Result, ::Error> { + if let FrameInput::Create(inputs) = &init.frame_input + && let CreateScheme::Create2 { salt } = inputs.scheme + { + let (ctx, inspector) = evm.ctx_inspector(); + + if inspector.should_use_create2_factory(ctx, inputs) { + let gas_limit = inputs.gas_limit; + + // Get CREATE2 deployer. + let create2_deployer = evm.inspector().create2_deployer(); + + // Generate call inputs for CREATE2 factory. + let call_inputs = + get_create2_factory_call_inputs(salt, inputs, create2_deployer); + + // Push data about current override to the stack. + self.create2_overrides + .push((evm.journal().depth(), call_inputs.clone())); + + // Sanity check that CREATE2 deployer exists. + let code_hash = + evm.journal_mut().load_account(create2_deployer)?.info.code_hash; + if code_hash == KECCAK_EMPTY { + return Ok(Some(FrameResult::Call(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: Bytes::copy_from_slice( + format!("missing CREATE2 deployer: {create2_deployer}") + .as_bytes(), + ), + gas: Gas::new(gas_limit), + }, + memory_offset: 0..0, + }))); + } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH { + return Ok(Some(FrameResult::Call(CallOutcome { + result: InterpreterResult { + result: InstructionResult::Revert, + output: "invalid CREATE2 deployer bytecode".into(), + gas: Gas::new(gas_limit), + }, + memory_offset: 0..0, + }))); + } + + // Rewrite the frame init + init.frame_input = FrameInput::Call(Box::new(call_inputs)); + } + } + Ok(None) + } + + /// Transforms CREATE2 factory call results back into CREATE outcomes. + fn handle_create2_override( + &mut self, + evm: &mut ::Evm, + result: FrameResult, + ) -> FrameResult { + if self + .create2_overrides + .last() + .is_some_and(|(depth, _)| *depth == evm.journal().depth()) + { + let (_, call_inputs) = self.create2_overrides.pop().unwrap(); + let FrameResult::Call(mut call) = result else { + unreachable!("create2 override should be a call frame"); + }; + + // Decode address from output. + let address = match call.instruction_result() { + return_ok!() => Address::try_from(call.output().as_ref()) + .map_err(|_| { + call.result = InterpreterResult { + result: InstructionResult::Revert, + output: "invalid CREATE2 factory output".into(), + gas: Gas::new(call_inputs.gas_limit), + }; + }) + .ok(), + _ => None, + }; + + FrameResult::Create(CreateOutcome { result: call.result, address }) + } else { + result + } + } +} + impl InspectorHandler for FoundryHandler<'_, I> { type IT = EthInterpreter; @@ -299,55 +395,9 @@ impl InspectorHandler for FoundryHandler<'_, I> { let result = match call_or_result { ItemOrResult::Item(mut init) => { - // Correctly match on FrameInit::Create - if let FrameInput::Create(inputs) = &init.frame_input - && let CreateScheme::Create2 { salt } = inputs.scheme - { - let (ctx, inspector) = evm.ctx_inspector(); - - if inspector.should_use_create2_factory(ctx, inputs) { - let gas_limit = inputs.gas_limit; - - // Get CREATE2 deployer. - let create2_deployer = evm.inspector().create2_deployer(); - - // Generate call inputs for CREATE2 factory. - let call_inputs = - get_create2_factory_call_inputs(salt, inputs, create2_deployer); - - // Push data about current override to the stack. - self.create2_overrides - .push((evm.journal().depth(), call_inputs.clone())); - - // Sanity check that CREATE2 deployer exists. - let code_hash = - evm.journal_mut().load_account(create2_deployer)?.info.code_hash; - if code_hash == KECCAK_EMPTY { - return Ok(FrameResult::Call(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output: Bytes::copy_from_slice( - format!("missing CREATE2 deployer: {create2_deployer}") - .as_bytes(), - ), - gas: Gas::new(gas_limit), - }, - memory_offset: 0..0, - })); - } else if code_hash != DEFAULT_CREATE2_DEPLOYER_CODEHASH { - return Ok(FrameResult::Call(CallOutcome { - result: InterpreterResult { - result: InstructionResult::Revert, - output: "invalid CREATE2 deployer bytecode".into(), - gas: Gas::new(gas_limit), - }, - memory_offset: 0..0, - })); - } - - // Rewrite the frame init - init.frame_input = FrameInput::Call(Box::new(call_inputs)); - } + // Handle CREATE/CREATE2 frame initialization + if let Some(frame_result) = self.handle_create_frame(evm, &mut init)? { + return Ok(frame_result); } match evm.inspect_frame_init(init)? { @@ -359,34 +409,7 @@ impl InspectorHandler for FoundryHandler<'_, I> { }; // Handle CREATE2 override transformation if needed - let result = if self - .create2_overrides - .last() - .is_some_and(|(depth, _)| *depth == evm.journal().depth()) - { - let (_, call_inputs) = self.create2_overrides.pop().unwrap(); - let FrameResult::Call(mut call) = result else { - unreachable!("create2 override should be a call frame"); - }; - - // Decode address from output. - let address = match call.instruction_result() { - return_ok!() => Address::try_from(call.output().as_ref()) - .map_err(|_| { - call.result = InterpreterResult { - result: InstructionResult::Revert, - output: "invalid CREATE2 factory output".into(), - gas: Gas::new(call_inputs.gas_limit), - }; - }) - .ok(), - _ => None, - }; - - FrameResult::Create(CreateOutcome { result: call.result, address }) - } else { - result - }; + let result = self.handle_create2_override(evm, result); if let Some(result) = evm.frame_return_result(result)? { return Ok(result); From c59149b47f39163d3f8a61a00b7863aee4f2a9a4 Mon Sep 17 00:00:00 2001 From: Yash Atreya <44857776+yash-atreya@users.noreply.github.com> Date: Thu, 10 Jul 2025 13:37:30 +0530 Subject: [PATCH 3/3] fmt --- crates/evm/core/src/evm.rs | 21 +++++++-------------- 1 file changed, 7 insertions(+), 14 deletions(-) diff --git a/crates/evm/core/src/evm.rs b/crates/evm/core/src/evm.rs index cbe32b87dd809..a40bcd44d442f 100644 --- a/crates/evm/core/src/evm.rs +++ b/crates/evm/core/src/evm.rs @@ -281,7 +281,8 @@ impl<'db, I: InspectorExt> Handler for FoundryHandler<'db, I> { } impl<'db, I: InspectorExt> FoundryHandler<'db, I> { - /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2 factory. + /// Handles CREATE2 frame initialization, potentially transforming it to use the CREATE2 + /// factory. fn handle_create_frame( &mut self, evm: &mut ::Evm, @@ -299,23 +300,19 @@ impl<'db, I: InspectorExt> FoundryHandler<'db, I> { let create2_deployer = evm.inspector().create2_deployer(); // Generate call inputs for CREATE2 factory. - let call_inputs = - get_create2_factory_call_inputs(salt, inputs, create2_deployer); + let call_inputs = get_create2_factory_call_inputs(salt, inputs, create2_deployer); // Push data about current override to the stack. - self.create2_overrides - .push((evm.journal().depth(), call_inputs.clone())); + self.create2_overrides.push((evm.journal().depth(), call_inputs.clone())); // Sanity check that CREATE2 deployer exists. - let code_hash = - evm.journal_mut().load_account(create2_deployer)?.info.code_hash; + let code_hash = evm.journal_mut().load_account(create2_deployer)?.info.code_hash; if code_hash == KECCAK_EMPTY { return Ok(Some(FrameResult::Call(CallOutcome { result: InterpreterResult { result: InstructionResult::Revert, output: Bytes::copy_from_slice( - format!("missing CREATE2 deployer: {create2_deployer}") - .as_bytes(), + format!("missing CREATE2 deployer: {create2_deployer}").as_bytes(), ), gas: Gas::new(gas_limit), }, @@ -345,11 +342,7 @@ impl<'db, I: InspectorExt> FoundryHandler<'db, I> { evm: &mut ::Evm, result: FrameResult, ) -> FrameResult { - if self - .create2_overrides - .last() - .is_some_and(|(depth, _)| *depth == evm.journal().depth()) - { + if self.create2_overrides.last().is_some_and(|(depth, _)| *depth == evm.journal().depth()) { let (_, call_inputs) = self.create2_overrides.pop().unwrap(); let FrameResult::Call(mut call) = result else { unreachable!("create2 override should be a call frame");