Skip to content

Commit

Permalink
feat: Hook on Execution (paradigmxyz#1567)
Browse files Browse the repository at this point in the history
  • Loading branch information
gakonst authored Feb 27, 2023
1 parent 7275f8d commit 56394ee
Show file tree
Hide file tree
Showing 5 changed files with 312 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions crates/executor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ readme = "README.md"
reth-primitives = { path = "../primitives" }
reth-interfaces = { path = "../interfaces" }
reth-revm = { path = "../revm" }
reth-revm-inspectors = { path = "../revm/revm-inspectors" }
reth-rlp = { path = "../rlp" }
reth-db = { path = "../storage/db" }
reth-provider = { path = "../storage/provider" }
Expand Down
98 changes: 65 additions & 33 deletions crates/executor/src/executor.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::execution_result::{
AccountChangeSet, AccountInfoChangeSet, ExecutionResult, TransactionChangeSet,
};

use hashbrown::hash_map::Entry;
use reth_interfaces::executor::{BlockExecutor, Error};
use reth_primitives::{
Expand All @@ -14,6 +15,7 @@ use reth_revm::{
env::{fill_cfg_and_block_env, fill_tx_env},
into_reth_log, to_reth_acc,
};
use reth_revm_inspectors::stack::{InspectorStack, InspectorStackConfig};
use revm::{
db::AccountState,
primitives::{Account as RevmAccount, AccountInfo, Bytecode, ResultAndState},
Expand All @@ -28,19 +30,24 @@ where
{
chain_spec: &'a ChainSpec,
evm: EVM<&'a mut SubState<DB>>,
/// Enable revm inspector printer.
/// In execution this will print opcode level traces directly to console.
pub use_printer_tracer: bool,
stack: InspectorStack,
}

impl<'a, DB> Executor<'a, DB>
where
DB: StateProvider,
{
fn new(chain_spec: &'a ChainSpec, db: &'a mut SubState<DB>) -> Self {
/// Creates a new executor from the given chain spec and database.
pub fn new(chain_spec: &'a ChainSpec, db: &'a mut SubState<DB>) -> Self {
let mut evm = EVM::new();
evm.database(db);
Executor { chain_spec, evm, use_printer_tracer: false }
Executor { chain_spec, evm, stack: InspectorStack::new(InspectorStackConfig::default()) }
}

/// Configures the executor with the given inspectors.
pub fn with_stack(mut self, stack: InspectorStack) -> Self {
self.stack = stack;
self
}

fn db(&mut self) -> &mut SubState<DB> {
Expand Down Expand Up @@ -327,18 +334,44 @@ where
}
}
}
}

impl<'a, DB> BlockExecutor<ExecutionResult> for Executor<'a, DB>
where
DB: StateProvider,
{
fn execute(
/// Runs a single transaction in the configured environment and proceeds
/// to return the result and state diff (without applying it).
///
/// Assumes the rest of the block environment has been filled via `init_block_env`.
pub fn transact(
&mut self,
transaction: &TransactionSigned,
sender: Address,
) -> Result<ResultAndState, Error> {
// Fill revm structure.
fill_tx_env(&mut self.evm.env.tx, transaction, sender);

let out = if self.stack.should_inspect(&self.evm.env, transaction.hash()) {
// execution with inspector.
let output = self.evm.inspect(&mut self.stack);
tracing::trace!(
target: "evm",
hash = ?transaction.hash(), ?output, ?transaction, env = ?self.evm.env,
"Executed transaction"
);
output
} else {
// main execution.
self.evm.transact()
};
out.map_err(|e| Error::EVM(format!("{e:?}")))
}

/// Runs the provided transactions and commits their state. Will proceed
/// to return the total gas used by this batch of transaction as well as the
/// changesets generated by each tx.
pub fn execute_transactions(
&mut self,
block: &Block,
total_difficulty: U256,
senders: Option<Vec<Address>>,
) -> Result<ExecutionResult, Error> {
) -> Result<(Vec<TransactionChangeSet>, u64), Error> {
let senders = self.recover_senders(&block.body, senders)?;

self.init_env(&block.header, total_difficulty);
Expand All @@ -357,27 +390,8 @@ where
block_available_gas,
})
}

// Fill revm structure.
fill_tx_env(&mut self.evm.env.tx, transaction, sender);

// Execute transaction.
let out = if self.use_printer_tracer {
// execution with inspector.
let output = self.evm.inspect(revm::inspectors::CustomPrintTracer::default());
tracing::trace!(
target: "evm",
hash = ?transaction.hash(), ?output, ?transaction, env = ?self.evm.env,
"Executed transaction"
);
output
} else {
// main execution.
self.evm.transact()
};

// cast the error and extract returnables.
let ResultAndState { result, state } = out.map_err(|e| Error::EVM(format!("{e:?}")))?;
let ResultAndState { result, state } = self.transact(transaction, sender)?;

// commit changes
let (changeset, new_bytecodes) = self.commit_changes(state);
Expand All @@ -404,6 +418,23 @@ where
});
}

Ok((tx_changesets, cumulative_gas_used))
}
}

impl<'a, DB> BlockExecutor<ExecutionResult> for Executor<'a, DB>
where
DB: StateProvider,
{
fn execute(
&mut self,
block: &Block,
total_difficulty: U256,
senders: Option<Vec<Address>>,
) -> Result<ExecutionResult, Error> {
let (tx_changesets, cumulative_gas_used) =
self.execute_transactions(block, total_difficulty, senders)?;

// Check if gas used matches the value set in header.
if block.gas_used != cumulative_gas_used {
return Err(Error::BlockGasUsed { got: cumulative_gas_used, expected: block.gas_used })
Expand Down Expand Up @@ -485,7 +516,8 @@ pub fn execute<DB: StateProvider>(
chain_spec: &ChainSpec,
db: &mut SubState<DB>,
) -> Result<ExecutionResult, Error> {
let mut executor = Executor::new(chain_spec, db);
let mut executor = Executor::new(chain_spec, db)
.with_stack(InspectorStack::new(InspectorStackConfig::default()));
executor.execute(block, total_difficulty, senders)
}

Expand Down
5 changes: 5 additions & 0 deletions crates/revm/revm-inspectors/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,3 +9,8 @@
/// An inspector implementation for an EIP2930 Accesslist
pub mod access_list;

/// An inspector stack abstracting the implementation details of
/// each inspector and allowing to hook on block/transaciton execution,
/// used in the main RETH executor.
pub mod stack;
Loading

0 comments on commit 56394ee

Please sign in to comment.