From 827a0132b4e2eb197abf0138ce51a64852344186 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Fri, 3 May 2024 15:39:19 +0200 Subject: [PATCH 1/3] fix: Save evm context after errors --- src/evm.rs | 6 +++--- src/executor.rs | 36 +++++++++++++++++++----------------- tests/fixtures/min.bin | 6 ++++++ tests/test_evm.py | 17 +++++++++++++++++ 4 files changed, 45 insertions(+), 20 deletions(-) create mode 100644 tests/fixtures/min.bin diff --git a/src/evm.rs b/src/evm.rs index 318bf96..8d0ddfe 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -373,9 +373,9 @@ impl EVM { let evm_context: EvmContext = replace(&mut self.context, EvmContext::new(DB::new_memory())); let (result, evm_context) = - call_evm(evm_context, self.handler_cfg, self.tracing, is_static)?; + call_evm(evm_context, self.handler_cfg, self.tracing, is_static); self.context = evm_context; - self.result = Some(result.clone()); - Ok(result) + self.result = result.as_ref().map(|r| r.clone()).ok(); + result } } diff --git a/src/executor.rs b/src/executor.rs index 9666187..6c208e2 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -1,18 +1,20 @@ -use crate::database::DB; -use crate::utils::pyerr; +use std::mem::replace; + use pyo3::exceptions::PyRuntimeError; use pyo3::PyResult; +use revm::{ + Context, ContextWithHandlerCfg, Evm, EvmContext, FrameOrResult, FrameResult, + inspector_handle_register, +}; use revm::inspectors::TracerEip3155; use revm::precompile::Log; -use revm::primitives::TransactTo; use revm::primitives::{ExecutionResult, ShanghaiSpec}; -use revm::{ - inspector_handle_register, Context, ContextWithHandlerCfg, Evm, EvmContext, FrameOrResult, - FrameResult, -}; +use revm::primitives::TransactTo; +use revm_interpreter::{CallInputs, CreateInputs, gas, SuccessOrHalt}; use revm_interpreter::primitives::HandlerCfg; -use revm_interpreter::{gas, CallInputs, CreateInputs, SuccessOrHalt}; -use std::mem::replace; + +use crate::database::DB; +use crate::utils::pyerr; /// Calls the EVM with the given context and handler configuration. pub(crate) fn call_evm( @@ -20,10 +22,10 @@ pub(crate) fn call_evm( handler_cfg: HandlerCfg, tracing: bool, is_static: bool, -) -> PyResult<(ExecutionResult, EvmContext)> { +) -> (PyResult, EvmContext) { if tracing { let tracer = TracerEip3155::new(Box::new(crate::pystdout::PySysStdout {})); - let evm = Evm::builder() + let mut evm = Evm::builder() .with_context_with_handler_cfg(ContextWithHandlerCfg { cfg: handler_cfg, context: Context { @@ -33,9 +35,9 @@ pub(crate) fn call_evm( }) .append_handler_register(inspector_handle_register) .build(); - run_evm(evm, is_static) + (run_evm(&mut evm, is_static), evm.context.evm) } else { - let evm = Evm::builder() + let mut evm = Evm::builder() .with_context_with_handler_cfg(ContextWithHandlerCfg { cfg: handler_cfg, context: Context { @@ -44,15 +46,15 @@ pub(crate) fn call_evm( }, }) .build(); - run_evm(evm, is_static) + (run_evm(&mut evm, is_static), evm.context.evm) } } /// Calls the given evm. This is originally a copy of revm::Evm::transact, but it calls our own output function fn run_evm( - mut evm: Evm<'_, EXT, DB>, + evm: &mut Evm<'_, EXT, DB>, is_static: bool, -) -> PyResult<(ExecutionResult, EvmContext)> { +) -> PyResult { let logs_i = evm.context.evm.journaled_state.logs.len(); evm.handler @@ -137,7 +139,7 @@ fn run_evm( let logs = ctx.evm.journaled_state.logs[logs_i..].to_vec(); // Returns output of transaction. - Ok((output(ctx, result, logs)?, evm.context.evm)) + Ok(output(ctx, result, logs)?) } fn call_inputs( diff --git a/tests/fixtures/min.bin b/tests/fixtures/min.bin new file mode 100644 index 0000000..7bd5459 --- /dev/null +++ b/tests/fixtures/min.bin @@ -0,0 +1,6 @@ +61003e61000f60003961003e6000f35f3560e01c637ae2b5c781186100365760443610341761003a5760043560243580820382811161003a579050905060405260206040f35b5f5ffd5b5f80fd84183e8000a16576797065728300030b0012 + +@external +@view +def min(x: uint256, y: uint256) -> uint256: + return x - y \ No newline at end of file diff --git a/tests/test_evm.py b/tests/test_evm.py index a643b27..ed0aef0 100644 --- a/tests/test_evm.py +++ b/tests/test_evm.py @@ -280,3 +280,20 @@ def test_get_blobhashes(blob_hashes): # the contract logs 6 blob hashes, so pad with 0s assert logged == blob_hashes + [b"\0" * 32] * (6 - len(blob_hashes)) + + +@pytest.mark.parametrize("kwargs", KWARG_CASES) +def test_call_reverting(kwargs): + evm = EVM() + code = load_contract_bin("min.bin") + deploy_address = evm.deploy(address, code) + + with pytest.raises(RuntimeError) as err: + evm.message_call( + caller=address, + to=deploy_address, + value=10, + ) + + assert evm.get_code(deploy_address), "The code should still be deployed after revert" + assert str(err.value).startswith("Transaction(LackOfFundForMaxFee") From 726631ae98a938d1a83dce8f0a06a217052a9b76 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Fri, 3 May 2024 15:41:31 +0200 Subject: [PATCH 2/3] Linting --- Makefile | 4 ++++ src/evm.rs | 1 + src/executor.rs | 19 ++++++++----------- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/Makefile b/Makefile index 0fceda9..d82287f 100644 --- a/Makefile +++ b/Makefile @@ -13,3 +13,7 @@ build-prod: test: build poetry run pytest -s tests/* + +lint: + cargo clippy --workspace --all-targets --all-features + cargo fmt --all diff --git a/src/evm.rs b/src/evm.rs index 8d0ddfe..936ec54 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -368,6 +368,7 @@ impl EVM { } } + #[allow(clippy::useless_asref)] fn run_env(&mut self, env: RevmEnv, is_static: bool) -> PyResult { self.context.env = Box::new(env); let evm_context: EvmContext = diff --git a/src/executor.rs b/src/executor.rs index 6c208e2..9c84100 100644 --- a/src/executor.rs +++ b/src/executor.rs @@ -2,16 +2,16 @@ use std::mem::replace; use pyo3::exceptions::PyRuntimeError; use pyo3::PyResult; -use revm::{ - Context, ContextWithHandlerCfg, Evm, EvmContext, FrameOrResult, FrameResult, - inspector_handle_register, -}; use revm::inspectors::TracerEip3155; use revm::precompile::Log; -use revm::primitives::{ExecutionResult, ShanghaiSpec}; use revm::primitives::TransactTo; -use revm_interpreter::{CallInputs, CreateInputs, gas, SuccessOrHalt}; +use revm::primitives::{ExecutionResult, ShanghaiSpec}; +use revm::{ + inspector_handle_register, Context, ContextWithHandlerCfg, Evm, EvmContext, FrameOrResult, + FrameResult, +}; use revm_interpreter::primitives::HandlerCfg; +use revm_interpreter::{gas, CallInputs, CreateInputs, SuccessOrHalt}; use crate::database::DB; use crate::utils::pyerr; @@ -51,10 +51,7 @@ pub(crate) fn call_evm( } /// Calls the given evm. This is originally a copy of revm::Evm::transact, but it calls our own output function -fn run_evm( - evm: &mut Evm<'_, EXT, DB>, - is_static: bool, -) -> PyResult { +fn run_evm(evm: &mut Evm<'_, EXT, DB>, is_static: bool) -> PyResult { let logs_i = evm.context.evm.journaled_state.logs.len(); evm.handler @@ -139,7 +136,7 @@ fn run_evm( let logs = ctx.evm.journaled_state.logs[logs_i..].to_vec(); // Returns output of transaction. - Ok(output(ctx, result, logs)?) + output(ctx, result, logs) } fn call_inputs( From 999d1ca348a6531b75a18df44c169e5ad6013e38 Mon Sep 17 00:00:00 2001 From: Daniel Schiavini Date: Fri, 3 May 2024 16:19:02 +0200 Subject: [PATCH 3/3] Clippy warning --- src/evm.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evm.rs b/src/evm.rs index 936ec54..e18d069 100644 --- a/src/evm.rs +++ b/src/evm.rs @@ -368,7 +368,6 @@ impl EVM { } } - #[allow(clippy::useless_asref)] fn run_env(&mut self, env: RevmEnv, is_static: bool) -> PyResult { self.context.env = Box::new(env); let evm_context: EvmContext = @@ -376,7 +375,7 @@ impl EVM { let (result, evm_context) = call_evm(evm_context, self.handler_cfg, self.tracing, is_static); self.context = evm_context; - self.result = result.as_ref().map(|r| r.clone()).ok(); + self.result = result.as_ref().ok().cloned(); result } }