mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 19:09:54 +00:00
chore: inspector stack from evm-inspectors (#7076)
This commit is contained in:
@ -52,7 +52,10 @@ use reth_provider::{
|
||||
CanonStateSubscriptions, HeaderProvider, HeaderSyncMode, ProviderFactory,
|
||||
StageCheckpointReader,
|
||||
};
|
||||
use reth_revm::EvmProcessorFactory;
|
||||
use reth_revm::{
|
||||
stack::{Hook, InspectorStackConfig},
|
||||
EvmProcessorFactory,
|
||||
};
|
||||
use reth_stages::{
|
||||
prelude::*,
|
||||
stages::{
|
||||
@ -68,7 +71,6 @@ use reth_transaction_pool::{
|
||||
blobstore::{DiskFileBlobStore, DiskFileBlobStoreConfig},
|
||||
EthTransactionPool, TransactionPool, TransactionValidationTaskExecutor,
|
||||
};
|
||||
use revm_inspectors::stack::Hook;
|
||||
use secp256k1::SecretKey;
|
||||
use std::{
|
||||
net::{SocketAddr, SocketAddrV4},
|
||||
@ -803,7 +805,6 @@ impl NodeConfig {
|
||||
}
|
||||
|
||||
let (tip_tx, tip_rx) = watch::channel(B256::ZERO);
|
||||
use revm_inspectors::stack::InspectorStackConfig;
|
||||
let factory = reth_revm::EvmProcessorFactory::new(self.chain.clone(), evm_config);
|
||||
|
||||
let stack_config = InspectorStackConfig {
|
||||
|
||||
@ -23,15 +23,18 @@ pub mod state_change;
|
||||
/// revm executor factory.
|
||||
pub use factory::EvmProcessorFactory;
|
||||
|
||||
/// reexport for convenience
|
||||
pub use revm_inspectors::*;
|
||||
|
||||
/// Re-export everything
|
||||
pub use revm::{self, *};
|
||||
|
||||
/// Ethereum DAO hardfork state change data.
|
||||
pub mod eth_dao_fork;
|
||||
|
||||
/// An inspector stack abstracting the implementation details of
|
||||
/// each inspector and allowing to hook on block/transaction execution,
|
||||
/// used in the main Reth executor.
|
||||
pub mod stack;
|
||||
|
||||
/// Optimism-specific implementation and utilities for the executor
|
||||
#[cfg(feature = "optimism")]
|
||||
pub mod optimism;
|
||||
|
||||
// Convenience re-exports.
|
||||
pub use revm::{self, *};
|
||||
pub use revm_inspectors::*;
|
||||
|
||||
@ -170,7 +170,7 @@ where
|
||||
|
||||
self.db_mut().set_state_clear_flag(state_clear_flag);
|
||||
|
||||
let mut cfg: CfgEnvWithHandlerCfg =
|
||||
let mut cfg =
|
||||
CfgEnvWithHandlerCfg::new_with_spec_id(self.evm.cfg().clone(), self.evm.spec_id());
|
||||
EvmConfig::fill_cfg_and_block_env(
|
||||
&mut cfg,
|
||||
@ -260,7 +260,7 @@ where
|
||||
fill_op_tx_env(self.evm.tx_mut(), transaction, sender, envelope_buf.into());
|
||||
}
|
||||
|
||||
let hash = transaction.hash();
|
||||
let hash = transaction.hash_ref();
|
||||
let should_inspect = self.evm.context.external.should_inspect(self.evm.env(), hash);
|
||||
let out = if should_inspect {
|
||||
// push inspector handle register.
|
||||
@ -268,7 +268,7 @@ where
|
||||
let output = self.evm.transact();
|
||||
tracing::trace!(
|
||||
target: "evm",
|
||||
?hash, ?output, ?transaction, env = ?self.evm.context.evm.env,
|
||||
%hash, ?output, ?transaction, env = ?self.evm.context.evm.env,
|
||||
"Executed transaction"
|
||||
);
|
||||
// pop last handle register
|
||||
|
||||
202
crates/revm/src/stack.rs
Normal file
202
crates/revm/src/stack.rs
Normal file
@ -0,0 +1,202 @@
|
||||
use revm::{
|
||||
inspectors::CustomPrintTracer,
|
||||
interpreter::{CallInputs, CallOutcome, CreateInputs, CreateOutcome, Interpreter},
|
||||
primitives::{Address, Env, Log, B256, U256},
|
||||
Database, EvmContext, Inspector,
|
||||
};
|
||||
use std::fmt::Debug;
|
||||
|
||||
/// A hook to inspect the execution of the EVM.
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub enum Hook {
|
||||
/// No hook.
|
||||
#[default]
|
||||
None,
|
||||
/// Hook on a specific block.
|
||||
Block(u64),
|
||||
/// Hook on a specific transaction hash.
|
||||
Transaction(B256),
|
||||
/// Hooks on every transaction in a block.
|
||||
All,
|
||||
}
|
||||
|
||||
impl Hook {
|
||||
/// Returns `true` if this hook should be used.
|
||||
#[inline]
|
||||
pub fn is_enabled(&self, block_number: u64, tx_hash: &B256) -> bool {
|
||||
match self {
|
||||
Hook::None => false,
|
||||
Hook::Block(block) => block_number == *block,
|
||||
Hook::Transaction(hash) => hash == tx_hash,
|
||||
Hook::All => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An inspector that calls multiple inspectors in sequence.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct InspectorStack {
|
||||
/// An inspector that prints the opcode traces to the console.
|
||||
pub custom_print_tracer: Option<CustomPrintTracer>,
|
||||
/// The provided hook
|
||||
pub hook: Hook,
|
||||
}
|
||||
|
||||
impl Debug for InspectorStack {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("InspectorStack")
|
||||
.field("custom_print_tracer", &self.custom_print_tracer.is_some())
|
||||
.field("hook", &self.hook)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl InspectorStack {
|
||||
/// Creates a new inspector stack with the given configuration.
|
||||
#[inline]
|
||||
pub fn new(config: InspectorStackConfig) -> Self {
|
||||
Self {
|
||||
hook: config.hook,
|
||||
custom_print_tracer: config.use_printer_tracer.then(Default::default),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns `true` if this inspector should be used.
|
||||
#[inline]
|
||||
pub fn should_inspect(&self, env: &Env, tx_hash: &B256) -> bool {
|
||||
self.custom_print_tracer.is_some() &&
|
||||
self.hook.is_enabled(env.block.number.saturating_to(), tx_hash)
|
||||
}
|
||||
}
|
||||
|
||||
/// Configuration for the inspectors.
|
||||
#[derive(Clone, Copy, Debug, Default)]
|
||||
pub struct InspectorStackConfig {
|
||||
/// Enable revm inspector printer.
|
||||
/// In execution this will print opcode level traces directly to console.
|
||||
pub use_printer_tracer: bool,
|
||||
|
||||
/// Hook on a specific block or transaction.
|
||||
pub hook: Hook,
|
||||
}
|
||||
|
||||
/// Helper macro to call the same method on multiple inspectors without resorting to dynamic
|
||||
/// dispatch.
|
||||
#[macro_export]
|
||||
macro_rules! call_inspectors {
|
||||
([$($inspector:expr),+ $(,)?], |$id:ident $(,)?| $call:expr $(,)?) => {{$(
|
||||
if let Some($id) = $inspector {
|
||||
$call
|
||||
}
|
||||
)+}}
|
||||
}
|
||||
|
||||
impl<DB> Inspector<DB> for InspectorStack
|
||||
where
|
||||
DB: Database,
|
||||
{
|
||||
#[inline]
|
||||
fn initialize_interp(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
inspector.initialize_interp(interp, context);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn step(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
inspector.step(interp, context);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn step_end(&mut self, interp: &mut Interpreter, context: &mut EvmContext<DB>) {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
inspector.step_end(interp, context);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn log(&mut self, context: &mut EvmContext<DB>, log: &Log) {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
inspector.log(context, log);
|
||||
});
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call(
|
||||
&mut self,
|
||||
context: &mut EvmContext<DB>,
|
||||
inputs: &mut CallInputs,
|
||||
) -> Option<CallOutcome> {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
if let Some(outcome) = inspector.call(context, inputs) {
|
||||
return Some(outcome);
|
||||
}
|
||||
});
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn call_end(
|
||||
&mut self,
|
||||
context: &mut EvmContext<DB>,
|
||||
inputs: &CallInputs,
|
||||
outcome: CallOutcome,
|
||||
) -> CallOutcome {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
let new_ret = inspector.call_end(context, inputs, outcome.clone());
|
||||
|
||||
// If the inspector returns a different ret or a revert with a non-empty message,
|
||||
// we assume it wants to tell us something
|
||||
if new_ret != outcome {
|
||||
return new_ret;
|
||||
}
|
||||
});
|
||||
|
||||
outcome
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn create(
|
||||
&mut self,
|
||||
context: &mut EvmContext<DB>,
|
||||
inputs: &mut CreateInputs,
|
||||
) -> Option<CreateOutcome> {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
if let Some(out) = inspector.create(context, inputs) {
|
||||
return Some(out);
|
||||
}
|
||||
});
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn create_end(
|
||||
&mut self,
|
||||
context: &mut EvmContext<DB>,
|
||||
inputs: &CreateInputs,
|
||||
outcome: CreateOutcome,
|
||||
) -> CreateOutcome {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
let new_ret = inspector.create_end(context, inputs, outcome.clone());
|
||||
|
||||
// If the inspector returns a different ret or a revert with a non-empty message,
|
||||
// we assume it wants to tell us something
|
||||
if new_ret != outcome {
|
||||
return new_ret;
|
||||
}
|
||||
});
|
||||
|
||||
outcome
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn selfdestruct(&mut self, contract: Address, target: Address, value: U256) {
|
||||
call_inspectors!([&mut self.custom_print_tracer], |inspector| {
|
||||
Inspector::<DB>::selfdestruct(inspector, contract, target, value);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user