Skip to content

migrate: anvil to revm 21 #10361

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 27 commits into from
Apr 29, 2025
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
9f7b1f2
downgrade op-revm to 2.0.0 to resolve dep conflict
yash-atreya Apr 24, 2025
84d11f1
add `as_mut_dyn` to trait `MaybeFullDatabase` as we now require mut d…
yash-atreya Apr 24, 2025
6990086
Revert "add `as_mut_dyn` to trait `MaybeFullDatabase` as we now requi…
yash-atreya Apr 24, 2025
29600d7
fix: Inspector should be generic over CTX not DB
yash-atreya Apr 24, 2025
6a5d57b
fix: pass TxEnv to evm.transact
yash-atreya Apr 24, 2025
e4cc032
fix: inspector inference in TransactionExecutor and build_access_list…
yash-atreya Apr 24, 2025
213593b
workaround: dup LogCollector to use with AnvilEvmContext
yash-atreya Apr 24, 2025
fdb9239
fix tests
yash-atreya Apr 24, 2025
78e2f76
fix traces test
yash-atreya Apr 24, 2025
b7b9ddd
fix: use default kzg settings in blob validation
yash-atreya Apr 24, 2025
7fced07
reintroduce OptimismHardfork
yash-atreya Apr 24, 2025
af4e00a
fix: disable nonce check if nonce is None
yash-atreya Apr 24, 2025
f1cdd41
fix!: load state tests by addressing breaking changes in state files
yash-atreya Apr 24, 2025
673696a
fix: access_list test by using evm.inspect_with_tx
yash-atreya Apr 25, 2025
4d9b1bc
fix: replace evm.transact with evm.inspect_with_tx
yash-atreya Apr 25, 2025
298c535
fix: make impl Inspector for AnvilInspector generic over CTX
yash-atreya Apr 25, 2025
1abfdcf
fix: clone inspector in TransactionExecutor to enable evm.inspect_commit
yash-atreya Apr 25, 2025
0efb119
Merge branch 'zerosnacks/revm-bump-2' into yash/anvil-revm-21
yash-atreya Apr 25, 2025
4730007
fix: remove cloned inspector from TransactionExecutor
yash-atreya Apr 25, 2025
1afa5a2
feat(`anvil`): op support revm 21 (#10407)
yash-atreya Apr 29, 2025
57a0fec
docs EitherEvm
yash-atreya Apr 29, 2025
42ccf70
nit
yash-atreya Apr 29, 2025
f8ef782
refac: return TxEnv and Deposit parts separately
yash-atreya Apr 29, 2025
d02f5b8
nits
yash-atreya Apr 29, 2025
d1c2316
nit
yash-atreya Apr 29, 2025
0b8f251
make anvil result aliases more generic
yash-atreya Apr 29, 2025
7e46fad
nit
yash-atreya Apr 29, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
508 changes: 145 additions & 363 deletions Cargo.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ solar-sema = { version = "=0.1.2", default-features = false }
## revm
revm = { version = "21.0.0", default-features = false }
revm-inspectors = { version = "0.18.1", features = ["serde"] }
op-revm = { version = "3.0.2", default-features = false }
op-revm = { version = "2.0.0", default-features = false }

## alloy
alloy-consensus = { version = "0.13.0", default-features = false }
Expand Down
70 changes: 40 additions & 30 deletions crates/anvil/src/eth/backend/executor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use crate::{
error::InvalidTransactionError,
pool::transactions::PoolTransaction,
},
inject_precompiles,
// inject_precompiles,
mem::inspector::AnvilInspector,
PrecompileFactory,
};
Expand Down Expand Up @@ -320,14 +320,22 @@ impl<DB: Db + ?Sized, V: TransactionValidator> Iterator for &mut TransactionExec
}

let exec_result = {
let mut evm = new_evm_with_inspector(&mut *self.db, &env, &mut inspector);
let mut evm: Evm<
_,
&mut dyn Inspector<
revm::Context<BlockEnv, revm::context::TxEnv, CfgEnv, WrapDatabaseRef<&DB>>,
>,
_,
_,
> = new_evm_with_inspector(&mut *self.db, &env, &mut inspector);
// if let Some(factory) = &self.precompile_factory {
// inject_precompiles(&mut evm, factory.precompiles());
// }

trace!(target: "backend", "[{:?}] executing", transaction.hash());
// transact and commit the transaction
match evm.transact_commit() {

match evm.transact_commit(env.tx) {
Ok(exec_result) => exec_result,
Err(err) => {
warn!(target: "backend", "[{:?}] failed to execute: {:?}", transaction.hash(), err);
Expand Down Expand Up @@ -414,44 +422,46 @@ pub type AnvilEvm<'db, DB, I, P = FoundryPrecompiles> =
Evm<AnvilEvmContext<'db, DB>, I, EthInstructions<EthInterpreter, AnvilEvmContext<'db, DB>>, P>;

/// Creates a database with given database and inspector, optionally enabling odyssey features.
pub fn new_evm_with_inspector<'db, DB>(
pub fn new_evm_with_inspector<'db, CTX, DB>(
db: DB,
env: &Env,
inspector: &'db mut dyn Inspector<DB>,
) -> AnvilEvm<'db, DB, &'db mut dyn Inspector<DB>>
inspector: &'db mut dyn Inspector<CTX>,
) -> AnvilEvm<'db, DB, &'db mut dyn Inspector<CTX>>
where
DB: Database<Error = DatabaseError>,
{
Evm {
data: EvmData {
ctx: AnvilEvmContext {
journaled_state: {
let mut journal = Journal::new(db);
journal.set_spec_id(env.evm_env.cfg_env.spec);
journal
},
block: env.evm_env.block_env.clone(),
cfg: env.evm_env.cfg_env.clone(),
tx: env.tx.clone(),
chain: (),
error: Ok(()),
},
inspector,
let evm_context = AnvilEvmContext {
journaled_state: {
let mut journal = Journal::new(db);
journal.set_spec_id(env.evm_env.cfg_env.spec);
journal
},
instruction: EthInstructions::default(),
precompiles: FoundryPrecompiles::new(),
}
block: env.evm_env.block_env.clone(),
cfg: env.evm_env.cfg_env.clone(),
tx: env.tx.clone(),
chain: (),
error: Ok(()),
};

let evm = Evm::new_with_inspector(
evm_context,
inspector,
EthInstructions::default(),
FoundryPrecompiles::new(),
);

evm
}

/// Creates a new EVM with the given inspector and wraps the database in a `WrapDatabaseRef`.
pub fn new_evm_with_inspector_ref<'db, DB>(
db: &'db mut DB,
pub fn new_evm_with_inspector_ref<'db, CTX, DB>(
db: &'db DB,
env: &Env,
inspector: &'db mut dyn Inspector<WrapDatabaseRef<&'db mut DB>>,
) -> AnvilEvm<'db, WrapDatabaseRef<&'db mut DB>, &'db mut dyn Inspector<WrapDatabaseRef<&'db mut DB>>>
inspector: &'db mut dyn Inspector<CTX>,
) -> AnvilEvm<'db, WrapDatabaseRef<&'db DB>, &'db mut dyn Inspector<CTX>>
where
DB: Database<Error = DatabaseError> + DatabaseRef + 'db,
WrapDatabaseRef<&'db mut DB>: Database<Error = DatabaseError>,
DB: DatabaseRef<Error = DatabaseError> + 'db + ?Sized,
WrapDatabaseRef<&'db DB>: Database<Error = DatabaseError>,
{
new_evm_with_inspector(WrapDatabaseRef(db), env, inspector)
}
63 changes: 60 additions & 3 deletions crates/anvil/src/eth/backend/mem/inspector.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,23 @@
//! Anvil specific [`revm::Inspector`] implementation

use crate::foundry_common::ErrorExt;
use alloy_primitives::{Address, Log, U256};
use alloy_sol_types::SolInterface;
use foundry_evm::{
backend::DatabaseError,
call_inspectors,
constants::HARDHAT_CONSOLE_ADDRESS,
decode::decode_console_logs,
inspectors::{LogCollector, TracingInspector},
inspectors::{hh_to_ds, TracingInspector},
traces::{
render_trace_arena_inner, CallTraceDecoder, SparsedTraceArena, TracingInspectorConfig,
},
};
use foundry_evm_core::abi::console;
use revm::{
interpreter::{
interpreter::EthInterpreter, CallInputs, CallOutcome, CreateInputs, CreateOutcome,
EOFCreateInputs, Interpreter,
EOFCreateInputs, Gas, InstructionResult, Interpreter, InterpreterResult,
},
Database, Inspector,
};
Expand Down Expand Up @@ -130,7 +134,8 @@ where

fn log(&mut self, interp: &mut Interpreter, ecx: &mut AnvilEvmContext<'_, D>, log: Log) {
call_inspectors!([&mut self.tracer, &mut self.log_collector], |inspector| {
inspector.log(interp, ecx, log);
// TODO: rm the log.clone
inspector.log(interp, ecx, log.clone());
});
}

Expand Down Expand Up @@ -220,3 +225,55 @@ pub fn print_logs(logs: &[Log]) {
tracing::info!(target: crate::logging::EVM_CONSOLE_LOG_TARGET, "{}", log);
}
}

// DUPLICATION foundry_evm
// Duplicated workaround due to the `FoundryEvmContext` database being hardcoded to `dyn
// DatabaseExt` instead of being generic.
/// An inspector that collects logs during execution.
///
/// The inspector collects logs from the `LOG` opcodes as well as Hardhat-style `console.sol` logs.
#[derive(Clone, Debug, Default)]
pub struct LogCollector {
/// The collected logs. Includes both `LOG` opcodes and Hardhat-style `console.sol` logs.
pub logs: Vec<Log>,
}

impl LogCollector {
#[cold]
fn do_hardhat_log(&mut self, inputs: &CallInputs) -> Option<CallOutcome> {
if let Err(err) = self.hardhat_log(&inputs.input) {
let result = InstructionResult::Revert;
let output = err.abi_encode_revert();
return Some(CallOutcome {
result: InterpreterResult { result, output, gas: Gas::new(inputs.gas_limit) },
memory_offset: inputs.return_memory_offset.clone(),
})
}
None
}

fn hardhat_log(&mut self, data: &[u8]) -> alloy_sol_types::Result<()> {
let decoded = console::hh::ConsoleCalls::abi_decode(data, false)?;
self.logs.push(hh_to_ds(&decoded));
Ok(())
}
}

impl<DB: Database<Error = DatabaseError>> Inspector<AnvilEvmContext<'_, DB>, EthInterpreter>
for LogCollector
{
fn log(&mut self, _interp: &mut Interpreter, _context: &mut AnvilEvmContext<'_, DB>, log: Log) {
self.logs.push(log.clone());
}

fn call(
&mut self,
_context: &mut AnvilEvmContext<'_, DB>,
inputs: &mut CallInputs,
) -> Option<CallOutcome> {
if inputs.target_address == HARDHAT_CONSOLE_ADDRESS {
return self.do_hardhat_log(inputs);
}
None
}
}
Loading
Loading