Skip to content

Commit

Permalink
feat: Evm structure (Cached Instructions and Precompiles) (#2049)
Browse files Browse the repository at this point in the history
* feat: frame ctx inside Evm

* feat: full Evm

* Inspector trait wip

* wip working inspector

* rename

* Inspector and Op support. Cleanup

* traits, examples and cleanup

* Cleanup all unused Getters

* Cleanup and some renames

* fix tests, clippy fmt

* rm bench

* no_std

* doc

* doc links

* support inspector selfdestruct and logs

* add erc20 example and cleanup
  • Loading branch information
rakita authored Feb 7, 2025
1 parent 83a3087 commit b3fbb88
Show file tree
Hide file tree
Showing 90 changed files with 2,721 additions and 3,892 deletions.
27 changes: 2 additions & 25 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 1 addition & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ members = [
"crates/specification",
"crates/context",
"crates/context/interface",
"crates/handler/interface",
"crates/handler",

# variants
Expand All @@ -27,7 +26,7 @@ members = [

# examples
"examples/block_traces",
"examples/cheatcode_inspector",
#"examples/cheatcode_inspector",
"examples/contract_deployment",
"examples/database_components",
"examples/uniswap_get_reserves",
Expand All @@ -54,8 +53,6 @@ statetest-types = { path = "crates/statetest-types", package = "revm-statetest-t
context = { path = "crates/context", package = "revm-context", version = "1.0.0", default-features = false }
context-interface = { path = "crates/context/interface", package = "revm-context-interface", version = "1.0.0", default-features = false }
handler = { path = "crates/handler", package = "revm-handler", version = "1.0.0", default-features = false }
handler-interface = { path = "crates/handler/interface", package = "revm-handler-interface", version = "1.0.0", default-features = false }

# misc
cfg-if = { version = "1.0", default-features = false }
auto_impl = { version = "1.2.0" }
Expand Down
11 changes: 6 additions & 5 deletions bins/revme/src/cmd/bench/analysis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET};
use revm::{
bytecode::Bytecode,
primitives::{bytes, hex, Bytes, TxKind},
Context, ExecuteEvm,
Context, ExecuteEvm, MainBuilder, MainContext,
};

const BYTES: &str = include_str!("analysis.hex");
Expand All @@ -13,21 +13,22 @@ pub fn run() {
let bytecode = Bytecode::new_raw(Bytes::from(hex::decode(BYTES).unwrap()));

// BenchmarkDB is dummy state that implements Database trait.
let mut context = Context::builder()
let context = Context::mainnet()
.with_db(BenchmarkDB::new_bytecode(bytecode))
.modify_tx_chained(|tx| {
// Execution globals block hash/gas_limit/coinbase/timestamp..
tx.caller = BENCH_CALLER;
tx.kind = TxKind::Call(BENCH_TARGET);
//evm.env.tx.data = Bytes::from(hex::decode("30627b7c").unwrap());
tx.data = bytes!("8035F0CE");
});

let mut evm = context.build_mainnet();

let time = Instant::now();
let _ = context.exec_previous();
let _ = evm.transact_previous();
println!("First init: {:?}", time.elapsed());

let time = Instant::now();
let _ = context.exec_previous();
let _ = evm.transact_previous();
println!("Run: {:?}", time.elapsed());
}
19 changes: 11 additions & 8 deletions bins/revme/src/cmd/bench/burntpix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use revm::{
database_interface::EmptyDB,
primitives::{hex, keccak256, Address, Bytes, TxKind, B256, U256},
state::{AccountInfo, Bytecode},
transact_main, Context,
Context, ExecuteEvm, MainBuilder, MainContext,
};

use std::fs::File;
Expand All @@ -36,15 +36,18 @@ pub fn run() {

let db = init_db();

let mut context = Context::builder().with_db(db).modify_tx_chained(|tx| {
tx.caller = BENCH_CALLER;
tx.kind = TxKind::Call(BURNTPIX_MAIN_ADDRESS);
tx.data = run_call_data.clone().into();
tx.gas_limit = u64::MAX;
});
let mut evm = Context::mainnet()
.with_db(db)
.modify_tx_chained(|tx| {
tx.caller = BENCH_CALLER;
tx.kind = TxKind::Call(BURNTPIX_MAIN_ADDRESS);
tx.data = run_call_data.clone().into();
tx.gas_limit = u64::MAX;
})
.build_mainnet();

let started = Instant::now();
let tx_result = transact_main(&mut context).unwrap().result;
let tx_result = evm.transact_previous().unwrap().result;
let return_data = match tx_result {
ExecutionResult::Success {
output, gas_used, ..
Expand Down
9 changes: 5 additions & 4 deletions bins/revme/src/cmd/bench/snailtracer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,21 @@ use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET};
use revm::{
bytecode::Bytecode,
primitives::{bytes, hex, Bytes, TxKind},
transact_main, Context,
Context, ExecuteEvm, MainBuilder, MainContext,
};

pub fn simple_example(bytecode: Bytecode) {
let mut context = Context::builder()
let mut evm = Context::mainnet()
.with_db(BenchmarkDB::new_bytecode(bytecode.clone()))
.modify_tx_chained(|tx| {
// Execution globals block hash/gas_limit/coinbase/timestamp..
tx.caller = BENCH_CALLER;
tx.kind = TxKind::Call(BENCH_TARGET);
tx.data = bytes!("30627b7c");
tx.gas_limit = 1_000_000_000;
});
let _ = transact_main(&mut context).unwrap();
})
.build_mainnet();
let _ = evm.transact_previous().unwrap();
}

pub fn run() {
Expand Down
21 changes: 12 additions & 9 deletions bins/revme/src/cmd/bench/transfer.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,29 @@
use std::time::Instant;

use database::{BenchmarkDB, BENCH_CALLER, BENCH_TARGET};
use revm::{
bytecode::Bytecode,
primitives::{TxKind, U256},
Context, ExecuteEvm,
Context, ExecuteEvm, MainBuilder, MainContext,
};
use std::time::Instant;

pub fn run() {
let mut context = Context::builder()
let time = Instant::now();
let mut evm = Context::mainnet()
.with_db(BenchmarkDB::new_bytecode(Bytecode::new()))
.modify_tx_chained(|tx| {
// Execution globals block hash/gas_limit/coinbase/timestamp..
tx.caller = BENCH_CALLER;
tx.kind = TxKind::Call(BENCH_TARGET);
tx.value = U256::from(10);
});
})
.build_mainnet();
println!("Init: {:?}", time.elapsed());

let time = Instant::now();
let _ = context.exec_previous();
println!("First init: {:?}", time.elapsed());
let _ = evm.transact_previous();
println!("First run: {:?}", time.elapsed());

let time = Instant::now();
let _ = context.exec_previous();
println!("Run: {:?}", time.elapsed());
let _ = evm.transact_previous();
println!("Second run: {:?}", time.elapsed());
}
27 changes: 14 additions & 13 deletions bins/revme/src/cmd/evmrunner.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
use clap::Parser;
use database::BenchmarkDB;
use inspector::{exec::InspectEvm, inspectors::TracerEip3155};
use inspector::inspectors::TracerEip3155;
use revm::{
bytecode::{Bytecode, BytecodeDecodeError},
primitives::{address, hex, Address, TxKind},
transact_main, Context, Database, ExecuteEvm,
Context, Database, ExecuteEvm, InspectEvm, MainBuilder, MainContext,
};
use std::io::Error as IoError;
use std::path::PathBuf;
Expand Down Expand Up @@ -82,30 +82,31 @@ impl Cmd {

// BenchmarkDB is dummy state that implements Database trait.
// The bytecode is deployed at zero address.
let mut ctx = Context::builder().with_db(db).modify_tx_chained(|tx| {
tx.caller = CALLER;
tx.kind = TxKind::Call(Address::ZERO);
tx.data = input;
tx.nonce = nonce;
});
let mut evm = Context::mainnet()
.with_db(db)
.modify_tx_chained(|tx| {
tx.caller = CALLER;
tx.kind = TxKind::Call(Address::ZERO);
tx.data = input;
tx.nonce = nonce;
})
.build_mainnet_with_inspector(TracerEip3155::new(Box::new(std::io::stdout())));

if self.bench {
// Microbenchmark
let bench_options = microbench::Options::default().time(Duration::from_secs(3));

microbench::bench(&bench_options, "Run bytecode", || {
let _ = ctx.exec_previous().unwrap();
let _ = evm.transact_previous().unwrap();
});

return Ok(());
}

let out = if self.trace {
let inspector = TracerEip3155::new(Box::new(std::io::stdout()));
ctx.inspect_previous(inspector)
.map_err(|_| Errors::EVMError)?
evm.inspect_previous().map_err(|_| Errors::EVMError)?
} else {
let out = transact_main(&mut ctx).map_err(|_| Errors::EVMError)?;
let out = evm.transact_previous().map_err(|_| Errors::EVMError)?;
println!("Result: {:#?}", out.result);
out
};
Expand Down
41 changes: 24 additions & 17 deletions bins/revme/src/cmd/statetest/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use super::{
};
use database::State;
use indicatif::{ProgressBar, ProgressDrawTarget};
use inspector::{exec::InspectCommitEvm, inspectors::TracerEip3155};
use inspector::inspectors::TracerEip3155;
use revm::{
bytecode::Bytecode,
context::{block::BlockEnv, cfg::CfgEnv, tx::TxEnv},
Expand All @@ -16,7 +16,7 @@ use revm::{
database_interface::EmptyDB,
primitives::{keccak256, Bytes, TxKind, B256},
specification::{eip4844::TARGET_BLOB_GAS_PER_BLOCK_CANCUN, hardfork::SpecId},
Context, ExecuteCommitEvm,
Context, ExecuteCommitEvm, InspectCommitEvm, MainBuilder, MainContext,
};
use serde_json::json;
use statetest_types::{SpecName, Test, TestSuite};
Expand Down Expand Up @@ -411,28 +411,30 @@ pub fn execute_test_suite(
.with_cached_prestate(cache)
.with_bundle_update()
.build();
let mut ctx = Context::builder()
let mut evm = Context::mainnet()
.with_block(&block)
.with_tx(&tx)
.with_cfg(&cfg)
.with_db(&mut state);
.with_db(&mut state)
.build_mainnet();

// Do the deed
let (e, exec_result) = if trace {
let mut ctx = Context::builder()
let mut evm = Context::mainnet()
.with_block(&block)
.with_tx(&tx)
.with_cfg(&cfg)
.with_db(&mut state);
.with_db(&mut state)
.build_mainnet_with_inspector(
TracerEip3155::buffered(stderr()).without_summary(),
);

let timer = Instant::now();
let res = ctx.inspect_commit_previous(
TracerEip3155::buffered(stderr()).without_summary(),
);
let res = evm.inspect_commit_previous();
*elapsed.lock().unwrap() += timer.elapsed();

let spec = cfg.spec();
let db = &mut ctx.journaled_state.database;
let db = &mut evm.data.ctx.journaled_state.database;
// Dump state and traces if test failed
let output = check_evm_execution(
&test,
Expand All @@ -449,11 +451,11 @@ pub fn execute_test_suite(
(e, res)
} else {
let timer = Instant::now();
let res = ctx.exec_commit_previous();
let res = evm.transact_commit_previous();
*elapsed.lock().unwrap() += timer.elapsed();

let spec = cfg.spec();
let db = ctx.journaled_state.database;
let db = evm.data.ctx.journaled_state.database;
// Dump state and traces if test failed
let output = check_evm_execution(
&test,
Expand Down Expand Up @@ -491,19 +493,24 @@ pub fn execute_test_suite(

println!("\nTraces:");

let mut ctx = Context::builder()
let mut evm = Context::mainnet()
.with_db(&mut state)
.with_block(&block)
.with_tx(&tx)
.with_cfg(&cfg);
.with_cfg(&cfg)
.build_mainnet_with_inspector(
TracerEip3155::buffered(stderr()).without_summary(),
);

let _ = ctx
.inspect_commit_previous(TracerEip3155::buffered(stderr()).without_summary());
let _ = evm.inspect_commit_previous();

println!("\nExecution result: {exec_result:#?}");
println!("\nExpected exception: {:?}", test.expect_exception);
println!("\nState before: {cache_state:#?}");
println!("\nState after: {:#?}", ctx.journaled_state.database.cache);
println!(
"\nState after: {:#?}",
evm.data.ctx.journaled_state.database.cache
);
println!("\nSpecification: {:?}", cfg.spec);
println!("\nTx: {tx:#?}");
println!("Block: {block:#?}");
Expand Down
Loading

0 comments on commit b3fbb88

Please sign in to comment.