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 { ... }
}
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:
- Apply pre-execution changes. Those might include system calls, irregular state transitions (DAO fork), etc.
- Apply block transactions to the state.
- 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
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:
- As the generic parameter for
RecoveredTx<T>
inExecutableTx
- As the generic parameter for
FromRecoveredTx<T>
andFromTxWithEncoded<T>
in the EVM constraint - To generate receipts after transaction execution
The transaction flow is:
Self::Transaction
(consensus tx) →Recovered<Self::Transaction>
(with sender)Recovered<Self::Transaction>
→TxEnv
(viaFromRecoveredTx
)TxEnv
→ EVM execution →ExecutionResult
ExecutionResult
+Self::Transaction
→Self::Receipt
Common examples:
EthereumTxEnvelope
for all Ethereum transaction variantsOpTxEnvelope
for opstack transaction variants
type Receipt
type Receipt
Receipt type this executor produces.
type Evm: Evm
where
<Self::Evm as Evm>::Tx: FromRecoveredTx<Self::Transaction> + FromTxWithEncoded<Self::Transaction>
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:
FromRecoveredTx<Self::Transaction>
- for transactions with recovered sendersFromTxWithEncoded<Self::Transaction>
- for transactions with encoded bytes
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>
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>
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:
- The transaction can be converted to
TxEnv
viaToTxEnv
for EVM execution - 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>
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>>)
fn set_state_hook(&mut self, hook: Option<Box<dyn OnStateHook>>)
Sets a hook to be called after each state change during execution.
Provided Methods§
fn execute_transaction(
&mut self,
tx: impl ExecutableTx<Self>,
) -> Result<u64, BlockExecutionError>
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>
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,
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>>) -> Selfwhere
Self: Sized,
fn with_state_hook(self, hook: Option<Box<dyn OnStateHook>>) -> Selfwhere
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,
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:
- Applies pre-execution changes (system calls, irregular state transitions)
- Executes all transactions in order
- 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.