BlockExecutor

Trait BlockExecutor 

pub trait BlockExecutor {
    type Transaction;
    type Receipt;
    type Evm: Evm
       where <Self::Evm as Evm>::Tx: FromRecoveredTx<Self::Transaction> + FromTxWithEncoded<Self::Transaction>;

    // Required methods
    fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError>;
    fn execute_transaction_with_commit_condition(
        &mut self,
        tx: impl ExecutableTx<Self>,
        f: impl FnOnce(&ExecutionResult<<Self::Evm as Evm>::HaltReason>) -> CommitChanges,
    ) -> Result<Option<u64>, BlockExecutionError>;
    fn finish(
        self,
    ) -> Result<(Self::Evm, BlockExecutionResult<Self::Receipt>), BlockExecutionError>;
    fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>);
    fn evm_mut(&mut self) -> &mut Self::Evm;
    fn evm(&self) -> &Self::Evm;

    // Provided methods
    fn execute_transaction(
        &mut self,
        tx: impl ExecutableTx<Self>,
    ) -> Result<u64, BlockExecutionError> { ... }
    fn execute_transaction_with_result_closure(
        &mut self,
        tx: impl ExecutableTx<Self>,
        f: impl FnOnce(&ExecutionResult<<Self::Evm as Evm>::HaltReason>),
    ) -> Result<u64, BlockExecutionError> { ... }
    fn apply_post_execution_changes(
        self,
    ) -> Result<BlockExecutionResult<Self::Receipt>, BlockExecutionError>
       where Self: Sized { ... }
    fn with_state_hook(self, hook: Option<Box<dyn OnStateHook>>) -> Self
       where Self: Sized { ... }
    fn execute_block(
        self,
        transactions: impl IntoIterator<Item = impl ExecutableTx<Self>>,
    ) -> Result<BlockExecutionResult<Self::Receipt>, BlockExecutionError>
       where Self: Sized { ... }
}
Available on crate feature evm only.
Expand description

A type that knows how to execute a single block.

The current abstraction assumes that block execution consists of the following steps:

  1. Apply pre-execution changes. Those might include system calls, irregular state transitions (DAO fork), etc.
  2. Apply block transactions to the state.
  3. Apply post-execution changes and finalize the state. This might include other system calls, block rewards, etc.

The output of BlockExecutor::finish is a BlockExecutionResult which contains all relevant information about the block execution.

Required Associated Types§

type Transaction

Input transaction type.

This represents the consensus transaction type that the block executor operates on. It’s typically a type from the consensus layer (e.g., EthereumTxEnvelope) that contains the raw transaction data, signature, and other consensus-level information.

This type is used in several contexts:

The transaction flow is:

  1. Self::Transaction (consensus tx) → Recovered<Self::Transaction> (with sender)
  2. Recovered<Self::Transaction>TxEnv (via FromRecoveredTx)
  3. TxEnv → EVM execution → ExecutionResult
  4. ExecutionResult + Self::TransactionSelf::Receipt

Common examples:

  • EthereumTxEnvelope for all Ethereum transaction variants
  • OpTxEnvelope for opstack transaction variants

type Receipt

Receipt type this executor produces.

type Evm: Evm where <Self::Evm as Evm>::Tx: FromRecoveredTx<Self::Transaction> + FromTxWithEncoded<Self::Transaction>

EVM used by the executor.

The EVM’s transaction type (Evm::Tx) must be able to be constructed from both:

This constraint ensures that the block executor can convert consensus transactions into the EVM’s transaction format for execution.

Required Methods§

fn apply_pre_execution_changes(&mut self) -> Result<(), BlockExecutionError>

Applies any necessary changes before executing the block’s transactions.

fn execute_transaction_with_commit_condition( &mut self, tx: impl ExecutableTx<Self>, f: impl FnOnce(&ExecutionResult<<Self::Evm as Evm>::HaltReason>) -> CommitChanges, ) -> Result<Option<u64>, BlockExecutionError>

Executes a single transaction and applies execution result to internal state. Invokes the given closure with an internal ExecutionResult produced by the EVM, and commits the transaction to the state on CommitChanges::Yes.

This is the most flexible transaction execution method, allowing conditional commitment based on the execution result. The closure receives the execution result and returns whether to commit the changes to state.

Use cases:

  • Conditional execution based on transaction outcome
  • Simulating transactions without committing
  • Custom validation logic before committing

The ExecutableTx constraint ensures that:

  1. The transaction can be converted to TxEnv via ToTxEnv for EVM execution
  2. The original transaction and signer can be accessed via RecoveredTx for receipt generation

Returns None if committing changes from the transaction should be skipped via CommitChanges::No, otherwise returns the gas used by the transaction.

fn finish( self, ) -> Result<(Self::Evm, BlockExecutionResult<Self::Receipt>), BlockExecutionError>

Applies any necessary changes after executing the block’s transactions, completes execution and returns the underlying EVM along with execution result.

fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>)

Sets a hook to be called after each state change during execution.

fn evm_mut(&mut self) -> &mut Self::Evm

Exposes mutable reference to EVM.

fn evm(&self) -> &Self::Evm

Exposes immutable reference to EVM.

Provided Methods§

fn execute_transaction( &mut self, tx: impl ExecutableTx<Self>, ) -> Result<u64, BlockExecutionError>

Executes a single transaction and applies execution result to internal state.

This method accepts any type implementing ExecutableTx, which ensures the transaction:

  • Can be converted to the EVM’s transaction environment for execution
  • Provides access to the original transaction and signer for receipt generation

Common input types include:

  • &Recovered<Transaction> - A transaction with its recovered sender
  • &WithEncoded<Recovered<Transaction>> - A transaction with sender and encoded bytes

The transaction is executed in the EVM, state changes are committed, and a receipt is generated internally.

Returns the gas used by the transaction.

fn execute_transaction_with_result_closure( &mut self, tx: impl ExecutableTx<Self>, f: impl FnOnce(&ExecutionResult<<Self::Evm as Evm>::HaltReason>), ) -> Result<u64, BlockExecutionError>

Executes a single transaction and applies execution result to internal state. Invokes the given closure with an internal ExecutionResult produced by the EVM.

This method is similar to execute_transaction but provides access to the raw execution result before it’s converted to a receipt. This is useful for:

  • Custom logging or metrics collection
  • Debugging transaction execution
  • Extracting additional information from the execution result

The transaction is always committed after the closure is invoked.

fn apply_post_execution_changes( self, ) -> Result<BlockExecutionResult<Self::Receipt>, BlockExecutionError>
where Self: Sized,

A helper to invoke BlockExecutor::finish returning only the BlockExecutionResult.

fn with_state_hook(self, hook: Option<Box<dyn OnStateHook>>) -> Self
where Self: Sized,

A builder-style helper to invoke BlockExecutor::set_state_hook.

fn execute_block( self, transactions: impl IntoIterator<Item = impl ExecutableTx<Self>>, ) -> Result<BlockExecutionResult<Self::Receipt>, BlockExecutionError>
where Self: Sized,

Executes all transactions in a block, applying pre and post execution changes.

This is a convenience method that orchestrates the complete block execution flow:

  1. Applies pre-execution changes (system calls, irregular state transitions)
  2. Executes all transactions in order
  3. Applies post-execution changes (block rewards, system calls)

Each transaction in the iterator must implement ExecutableTx, ensuring it can be:

  • Converted to the EVM’s transaction format for execution
  • Used to generate receipts with access to the original transaction data
§Example
let recovered_txs: Vec<Recovered<Transaction>> = block.transactions
    .iter()
    .map(|tx| tx.recover_signer())
    .collect::<Result<_, _>>()?;

let result = executor.execute_block(recovered_txs.iter())?;

Dyn Compatibility§

This trait is not dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety", so this trait is not object safe.

Implementors§

§

impl<'a, DB, I> BlockExecutor for MockExecutor<'a, DB, I>
where DB: Database, I: Inspector<Context<BlockEnv, TxEnv, CfgEnv, &'a mut State<DB>>>,

§

type Evm = EthEvm<&'a mut State<DB>, I, PrecompilesMap>

§

type Transaction = EthereumTxEnvelope<TxEip4844>

§

type Receipt = Receipt

§

impl<'db, DB, E, Spec, R> BlockExecutor for EthBlockExecutor<'_, E, Spec, R>
where DB: Database + 'db, E: Evm<DB = &'db mut State<DB>>, <E as Evm>::Tx: FromRecoveredTx<<R as ReceiptBuilder>::Transaction> + FromTxWithEncoded<<R as ReceiptBuilder>::Transaction>, Spec: EthExecutorSpec, R: ReceiptBuilder, <R as ReceiptBuilder>::Transaction: Transaction + Encodable2718, <R as ReceiptBuilder>::Receipt: TxReceipt<Log = Log>,