Skip to content

Commit

Permalink
Merge pull request #18 from DanielSchiavini/journal
Browse files Browse the repository at this point in the history
fix: Save evm context after errors
  • Loading branch information
charles-cooper authored May 3, 2024
2 parents bfd1451 + 999d1ca commit 532b6bb
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 16 deletions.
4 changes: 4 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,7 @@ build-prod:

test: build
poetry run pytest -s tests/*

lint:
cargo clippy --workspace --all-targets --all-features
cargo fmt --all
6 changes: 3 additions & 3 deletions src/evm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,9 @@ impl EVM {
let evm_context: EvmContext<DB> =
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().ok().cloned();
result
}
}
25 changes: 12 additions & 13 deletions src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::database::DB;
use crate::utils::pyerr;
use std::mem::replace;

use pyo3::exceptions::PyRuntimeError;
use pyo3::PyResult;
use revm::inspectors::TracerEip3155;
Expand All @@ -12,18 +12,20 @@ use revm::{
};
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(
evm_context: EvmContext<DB>,
handler_cfg: HandlerCfg,
tracing: bool,
is_static: bool,
) -> PyResult<(ExecutionResult, EvmContext<DB>)> {
) -> (PyResult<ExecutionResult>, EvmContext<DB>) {
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 {
Expand All @@ -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 {
Expand All @@ -44,15 +46,12 @@ 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<EXT>(
mut evm: Evm<'_, EXT, DB>,
is_static: bool,
) -> PyResult<(ExecutionResult, EvmContext<DB>)> {
fn run_evm<EXT>(evm: &mut Evm<'_, EXT, DB>, is_static: bool) -> PyResult<ExecutionResult> {
let logs_i = evm.context.evm.journaled_state.logs.len();

evm.handler
Expand Down Expand Up @@ -137,7 +136,7 @@ fn run_evm<EXT>(
let logs = ctx.evm.journaled_state.logs[logs_i..].to_vec();

// Returns output of transaction.
Ok((output(ctx, result, logs)?, evm.context.evm))
output(ctx, result, logs)
}

fn call_inputs<EXT>(
Expand Down
6 changes: 6 additions & 0 deletions tests/fixtures/min.bin
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
61003e61000f60003961003e6000f35f3560e01c637ae2b5c781186100365760443610341761003a5760043560243580820382811161003a579050905060405260206040f35b5f5ffd5b5f80fd84183e8000a16576797065728300030b0012

@external
@view
def min(x: uint256, y: uint256) -> uint256:
return x - y
17 changes: 17 additions & 0 deletions tests/test_evm.py
Original file line number Diff line number Diff line change
Expand Up @@ -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")

0 comments on commit 532b6bb

Please sign in to comment.