diff --git a/crates/cast/bin/cmd/run.rs b/crates/cast/bin/cmd/run.rs index c5f25bf7b40fa..dbded3c760333 100644 --- a/crates/cast/bin/cmd/run.rs +++ b/crates/cast/bin/cmd/run.rs @@ -94,6 +94,10 @@ pub struct RunArgs { /// Use current project artifacts for trace decoding. #[arg(long, visible_alias = "la")] pub with_local_artifacts: bool, + + /// Skip transaction preverification (nonce etc.) + #[arg(long, visible_alias = "sp")] + pub skip_preverification: bool, } impl RunArgs { @@ -181,6 +185,7 @@ impl RunArgs { odyssey, create2_deployer, ); + executor.set_skip_preverification(self.skip_preverification); let mut env = EnvWithHandlerCfg::new_with_spec_id(Box::new(env.clone()), executor.spec_id()); diff --git a/crates/evm/core/src/backend/mod.rs b/crates/evm/core/src/backend/mod.rs index 22e29bb13b47b..6cd5a53683f54 100644 --- a/crates/evm/core/src/backend/mod.rs +++ b/crates/evm/core/src/backend/mod.rs @@ -766,15 +766,37 @@ impl Backend { &mut self, env: &mut EnvWithHandlerCfg, inspector: &mut I, + ) -> eyre::Result { + self.inspect_inner(env, inspector, false) + } + + /// Executes the configured test call of the `env` without committing state changes and + /// skipping transaction preverification. + #[instrument(name = "inspect", level = "debug", skip_all)] + pub fn inspect_preverified( + &mut self, + env: &mut EnvWithHandlerCfg, + inspector: &mut I, + ) -> eyre::Result { + self.inspect_inner(env, inspector, true) + } + + #[instrument(name = "inspect", level = "debug", skip_all)] + pub fn inspect_inner( + &mut self, + env: &mut EnvWithHandlerCfg, + inspector: &mut I, + skip_preverification: bool, ) -> eyre::Result { self.initialize(env); let mut evm = crate::utils::new_evm_with_inspector(self, env.clone(), inspector); - let res = evm.transact().wrap_err("EVM error")?; + let res = if skip_preverification { evm.transact_preverified() } else { evm.transact() }; + let inner_res = res.wrap_err("EVM error")?; env.env = evm.context.evm.inner.env; - Ok(res) + Ok(inner_res) } /// Returns true if the address is a precompile diff --git a/crates/evm/evm/src/executors/mod.rs b/crates/evm/evm/src/executors/mod.rs index 5c26a6d6cdc5d..b861c4b6cd852 100644 --- a/crates/evm/evm/src/executors/mod.rs +++ b/crates/evm/evm/src/executors/mod.rs @@ -90,6 +90,8 @@ pub struct Executor { gas_limit: u64, /// Whether `failed()` should be called on the test contract to determine if the test failed. legacy_assertions: bool, + /// skips transaction preverification + skip_preverification: bool, } impl Executor { @@ -121,7 +123,7 @@ impl Executor { }, ); - Self { backend, env, inspector, gas_limit, legacy_assertions } + Self { backend, env, inspector, gas_limit, legacy_assertions, skip_preverification: false } } fn clone_with_backend(&self, backend: Backend) -> Self { @@ -194,6 +196,16 @@ impl Executor { self.legacy_assertions = legacy_assertions; } + /// Returns whether preverification of transactions should be skipped + pub fn skip_preverification(&self) -> bool { + self.skip_preverification + } + + /// Sets whether preverification of transactions should be skipped + pub fn set_skip_preverification(&mut self, skip_preverification: bool) { + self.skip_preverification = skip_preverification; + } + /// Creates the default CREATE2 Contract Deployer for local tests and scripts. pub fn deploy_create2_deployer(&mut self) -> eyre::Result<()> { trace!("deploying local create2 deployer"); @@ -451,8 +463,13 @@ impl Executor { #[instrument(name = "transact", level = "debug", skip_all)] pub fn transact_with_env(&mut self, mut env: EnvWithHandlerCfg) -> eyre::Result { let mut inspector = self.inspector().clone(); + let skip_preverification = self.skip_preverification; let backend = self.backend_mut(); - let result = backend.inspect(&mut env, &mut inspector)?; + let result = if skip_preverification { + backend.inspect_preverified(&mut env, &mut inspector)? + } else { + backend.inspect(&mut env, &mut inspector)? + }; let mut result = convert_executed_result(env, inspector, result, backend.has_state_snapshot_failure())?; self.commit(&mut result);