pub trait Handler {
type Evm: EvmTr<Context: ContextTr<Journal: JournalTr, Local: LocalContextTr>, Frame: FrameTr<FrameInit = FrameInit, FrameResult = FrameResult>>;
type Error: EvmTrError<Self::Evm>;
type HaltReason: HaltReasonTr;
Show 23 methods
// Provided methods
fn run(
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> { ... }
fn run_system_call(
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> { ... }
fn run_without_catch_error(
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> { ... }
fn validate(
&self,
evm: &mut Self::Evm,
) -> Result<InitialAndFloorGas, Self::Error> { ... }
fn tx_gas(
&self,
evm: &mut Self::Evm,
init_and_floor_gas: &InitialAndFloorGas,
) -> GasTracker { ... }
fn pre_execution(
&self,
evm: &mut Self::Evm,
gas: &mut GasTracker,
) -> Result<Option<PreExecutionOutput>, Self::Error> { ... }
fn execution(
&mut self,
evm: &mut Self::Evm,
checkpoint: JournalCheckpoint,
gas: &mut GasTracker,
) -> Result<Option<FrameResult>, Self::Error> { ... }
fn runtime_oog_result(
&mut self,
evm: &mut Self::Evm,
init_and_floor_gas: &InitialAndFloorGas,
gas: &mut GasTracker,
) -> Result<FrameResult, Self::Error> { ... }
fn post_execution(
&self,
evm: &mut Self::Evm,
exec_result: &mut FrameResult,
init_and_floor_gas: InitialAndFloorGas,
eip7702_gas_refund: i64,
) -> Result<ResultGas, Self::Error> { ... }
fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> { ... }
fn validate_initial_tx_gas(
&self,
evm: &mut Self::Evm,
) -> Result<InitialAndFloorGas, Self::Error> { ... }
fn load_accounts(&self, evm: &mut Self::Evm) -> Result<(), Self::Error> { ... }
fn apply_eip7702_auth_list(
&self,
evm: &mut Self::Evm,
gas: &mut GasTracker,
) -> Result<Option<u64>, Self::Error> { ... }
fn validate_against_state_and_deduct_caller(
&self,
evm: &mut Self::Evm,
_init_and_floor_gas: &mut InitialAndFloorGas,
) -> Result<(), Self::Error> { ... }
fn first_frame_input(
&mut self,
evm: &mut Self::Evm,
gas: &mut GasTracker,
) -> Result<Option<FrameInit>, Self::Error> { ... }
fn last_frame_result(
&mut self,
evm: &mut Self::Evm,
frame_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
parent_gas: &mut GasTracker,
) -> Result<(), Self::Error> { ... }
fn run_exec_loop(
&mut self,
evm: &mut Self::Evm,
first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
) -> Result<FrameResult, Self::Error> { ... }
fn eip7623_check_gas_floor(
&self,
_evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
init_and_floor_gas: InitialAndFloorGas,
) { ... }
fn refund(
&self,
evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
eip7702_refund: i64,
) -> Result<(), Self::Error> { ... }
fn reimburse_caller(
&self,
evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
) -> Result<(), Self::Error> { ... }
fn reward_beneficiary(
&self,
evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
) -> Result<(), Self::Error> { ... }
fn execution_result(
&mut self,
evm: &mut Self::Evm,
result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
result_gas: ResultGas,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> { ... }
fn catch_error(
&self,
evm: &mut Self::Evm,
error: Self::Error,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error> { ... }
}Expand description
The main implementation of Ethereum Mainnet transaction execution.
The Handler::run method serves as the entry point for execution and provides
out-of-the-box support for executing Ethereum mainnet transactions.
This trait allows EVM variants to customize execution logic by implementing their own method implementations.
The handler logic consists of four phases:
- Validation - Validates tx/block/config fields and loads caller account and validates initial gas requirements and balance checks.
- Pre-execution - Loads and warms accounts, deducts initial gas
- Execution - Executes the main frame loop, delegating to
EvmTrfor creating and running call frames. - Post-execution - Calculates final refunds, validates gas floor, reimburses caller, and rewards beneficiary
The Handler::catch_error method handles cleanup of intermediate state if an error
occurs during execution.
§Returns
Returns execution status, error, gas spend and logs. State change is not returned and it is contained inside Context Journal. This setup allows multiple transactions to be chain executed.
To finalize the execution and obtain changed state, call JournalTr::finalize function.
Required Associated Types§
Sourcetype Evm: EvmTr<Context: ContextTr<Journal: JournalTr, Local: LocalContextTr>, Frame: FrameTr<FrameInit = FrameInit, FrameResult = FrameResult>>
type Evm: EvmTr<Context: ContextTr<Journal: JournalTr, Local: LocalContextTr>, Frame: FrameTr<FrameInit = FrameInit, FrameResult = FrameResult>>
The EVM type containing Context, Instruction, and Precompiles implementations.
Sourcetype Error: EvmTrError<Self::Evm>
type Error: EvmTrError<Self::Evm>
The error type returned by this handler.
Sourcetype HaltReason: HaltReasonTr
type HaltReason: HaltReasonTr
The halt reason type included in the output
Provided Methods§
Sourcefn run(
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
fn run( &mut self, evm: &mut Self::Evm, ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
The main entry point for transaction execution.
This method calls Handler::run_without_catch_error and if it returns an error,
calls Handler::catch_error to handle the error and cleanup.
The Handler::catch_error method ensures intermediate state is properly cleared.
§Error handling
In case of error, the journal can be in an inconsistent state and should be cleared by calling
JournalTr::discard_tx method or dropped.
§Returns
Returns execution result, error, gas spend and logs.
Sourcefn run_system_call(
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
fn run_system_call( &mut self, evm: &mut Self::Evm, ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
Runs the system call.
System call is a special transaction where caller is a crate::SYSTEM_ADDRESS
It is used to call a system contracts and it skips all the validation and pre-execution and most of post-execution phases.
For example it will not deduct the caller or reward the beneficiary.
State changs can be obtained by calling JournalTr::finalize method from the EvmTr::Context.
§Error handling
By design system call should not fail and should always succeed.
In case of an error (If fetching account/storage on rpc fails), the journal can be in an inconsistent
state and should be cleared by calling JournalTr::discard_tx method or dropped.
Sourcefn run_without_catch_error(
&mut self,
evm: &mut Self::Evm,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
fn run_without_catch_error( &mut self, evm: &mut Self::Evm, ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
Called by Handler::run to execute the core handler logic.
Executes the four phases in sequence: Handler::validate, Handler::pre_execution, Handler::execution, Handler::post_execution.
Returns any errors without catching them or calling Handler::catch_error.
Sourcefn validate(
&self,
evm: &mut Self::Evm,
) -> Result<InitialAndFloorGas, Self::Error>
fn validate( &self, evm: &mut Self::Evm, ) -> Result<InitialAndFloorGas, Self::Error>
Validates the execution environment and transaction parameters.
Calculates initial and floor gas requirements, verifies they are covered by the gas limit, validates the transaction against state, and deducts the caller.
Sourcefn tx_gas(
&self,
evm: &mut Self::Evm,
init_and_floor_gas: &InitialAndFloorGas,
) -> GasTracker
fn tx_gas( &self, evm: &mut Self::Evm, init_and_floor_gas: &InitialAndFloorGas, ) -> GasTracker
Creates the transaction-level GasTracker from the validated initial gas.
The gas limit is the transaction gas limit, remaining is the regular
gas budget left after the intrinsic gas (constrained by the EIP-8037
TX_MAX_GAS_LIMIT cap) and reservoir is the state gas pool, so the
intrinsic gas is accounted as already spent.
Sourcefn pre_execution(
&self,
evm: &mut Self::Evm,
gas: &mut GasTracker,
) -> Result<Option<PreExecutionOutput>, Self::Error>
fn pre_execution( &self, evm: &mut Self::Evm, gas: &mut GasTracker, ) -> Result<Option<PreExecutionOutput>, Self::Error>
Prepares the EVM state for execution.
Loads the beneficiary account (EIP-3651: Warm COINBASE) and all accounts/storage from the access list (EIP-2929).
For EIP-7702 transactions, applies the authorization list and delegates successful authorizations. Authorizations are applied before execution begins.
Returns the pre-execution gas decisions (PreExecutionOutput): the
EIP-7702 gas refund and the still-open EIP-2780 runtime gas phase
checkpoint, which Handler::execution settles. Returns None when
the EIP-2780 authorization charges ran out of gas: the transaction
stays valid but must skip execution and be included as an out-of-gas
halt (Handler::runtime_oog_result).
Sourcefn execution(
&mut self,
evm: &mut Self::Evm,
checkpoint: JournalCheckpoint,
gas: &mut GasTracker,
) -> Result<Option<FrameResult>, Self::Error>
fn execution( &mut self, evm: &mut Self::Evm, checkpoint: JournalCheckpoint, gas: &mut GasTracker, ) -> Result<Option<FrameResult>, Self::Error>
Creates and executes the initial frame, then processes the execution loop.
First-frame creation completes the EIP-2780 runtime gas phase: it
charges the recipient/create-target costs on the transaction-level
gas, and checkpoint (opened at pre-execution around the applied
authorizations) is committed here — or reverted when those charges run
out of gas, in which case None is returned and the caller includes
the transaction as an out-of-gas halt
(Handler::runtime_oog_result).
Always calls Handler::last_frame_result to handle returned gas from the call.
Sourcefn runtime_oog_result(
&mut self,
evm: &mut Self::Evm,
init_and_floor_gas: &InitialAndFloorGas,
gas: &mut GasTracker,
) -> Result<FrameResult, Self::Error>
fn runtime_oog_result( &mut self, evm: &mut Self::Evm, init_and_floor_gas: &InitialAndFloorGas, gas: &mut GasTracker, ) -> Result<FrameResult, Self::Error>
Builds the result for a transaction whose EIP-2780 runtime gas phase
ran out of gas (Handler::pre_execution or Handler::execution
returned None).
The transaction is valid but its gas cannot cover the state-dependent runtime charges. It is included as an out-of-gas halt: execution is skipped, all regular gas is consumed (the reservoir is returned), and the runtime state changes were already reverted when the phase bailed out.
Sourcefn post_execution(
&self,
evm: &mut Self::Evm,
exec_result: &mut FrameResult,
init_and_floor_gas: InitialAndFloorGas,
eip7702_gas_refund: i64,
) -> Result<ResultGas, Self::Error>
fn post_execution( &self, evm: &mut Self::Evm, exec_result: &mut FrameResult, init_and_floor_gas: InitialAndFloorGas, eip7702_gas_refund: i64, ) -> Result<ResultGas, Self::Error>
Handles the final steps of transaction execution.
Calculates final refunds and validates the gas floor (EIP-7623) to ensure minimum gas is spent. After EIP-7623, at least floor gas must be consumed.
Reimburses unused gas to the caller and rewards the beneficiary with transaction fees. The effective gas price determines rewards, with the base fee being burned.
Finally, finalizes output by returning the journal state and clearing internal state for the next execution.
Sourcefn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error>
fn validate_env(&self, evm: &mut Self::Evm) -> Result<(), Self::Error>
Validates block, transaction and configuration fields.
Performs all validation checks that can be done without loading state. For example, verifies transaction gas limit is below block gas limit.
Sourcefn validate_initial_tx_gas(
&self,
evm: &mut Self::Evm,
) -> Result<InitialAndFloorGas, Self::Error>
fn validate_initial_tx_gas( &self, evm: &mut Self::Evm, ) -> Result<InitialAndFloorGas, Self::Error>
Calculates initial gas costs based on transaction type and input data.
Includes additional costs for access list and authorization list.
Verifies the initial cost does not exceed the transaction gas limit.
Sourcefn load_accounts(&self, evm: &mut Self::Evm) -> Result<(), Self::Error>
fn load_accounts(&self, evm: &mut Self::Evm) -> Result<(), Self::Error>
Loads access list and beneficiary account, marking them as warm in the context::Journal.
Sourcefn apply_eip7702_auth_list(
&self,
evm: &mut Self::Evm,
gas: &mut GasTracker,
) -> Result<Option<u64>, Self::Error>
fn apply_eip7702_auth_list( &self, evm: &mut Self::Evm, gas: &mut GasTracker, ) -> Result<Option<u64>, Self::Error>
Processes the authorization list, validating authority signatures, nonces and chain IDs. Applies valid authorizations to accounts.
Returns the EIP-7702 gas refund, or None when the EIP-2780
authorization charges ran out of gas — Handler::pre_execution owns
the runtime gas phase checkpoint and reverts it in that case.
Sourcefn validate_against_state_and_deduct_caller(
&self,
evm: &mut Self::Evm,
_init_and_floor_gas: &mut InitialAndFloorGas,
) -> Result<(), Self::Error>
fn validate_against_state_and_deduct_caller( &self, evm: &mut Self::Evm, _init_and_floor_gas: &mut InitialAndFloorGas, ) -> Result<(), Self::Error>
Deducts the maximum possible fee from caller’s balance.
If cfg.is_balance_check_disabled, this method will add back enough funds to ensure that the caller’s balance is at least tx.value() before returning. Note that the amount of funds added back in this case may exceed the maximum fee.
Unused fees are returned to caller after execution completes.
Sourcefn first_frame_input(
&mut self,
evm: &mut Self::Evm,
gas: &mut GasTracker,
) -> Result<Option<FrameInit>, Self::Error>
fn first_frame_input( &mut self, evm: &mut Self::Evm, gas: &mut GasTracker, ) -> Result<Option<FrameInit>, Self::Error>
Creates initial frame input from the transaction parameters and the transaction-level gas, forwarding all remaining regular gas and the reservoir to the frame.
Under EIP-2780 the target loading also records the runtime
recipient/create-target charges on gas and marks the refundable ones
on the frame inputs’ charged_* flags (see
execution::create_init_frame), so Handler::last_frame_result
can refund them from the outcome.
Returns None when those charges run out of gas.
Sourcefn last_frame_result(
&mut self,
evm: &mut Self::Evm,
frame_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
parent_gas: &mut GasTracker,
) -> Result<(), Self::Error>
fn last_frame_result( &mut self, evm: &mut Self::Evm, frame_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult, parent_gas: &mut GasTracker, ) -> Result<(), Self::Error>
Processes the result of the initial call and settles it into the transaction-level gas.
Emulates how a parent frame settles a returning child
(handle_reservoir_remaining_gas): a failing frame rolls its
state-gas charges back in LIFO order and drops its refund counter, an
exceptional halt additionally consumes its regular gas; unused regular
gas then returns to the transaction-level gas and the reservoir is
adopted from the frame. The EIP-2780 refundable first-frame charge is
refunded from the outcome’s charged_* flags, mirroring
EthFrame::return_result.
The settled transaction-level gas is written back to the frame result, which carries it into the post-execution phase.
Sourcefn run_exec_loop(
&mut self,
evm: &mut Self::Evm,
first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit,
) -> Result<FrameResult, Self::Error>
fn run_exec_loop( &mut self, evm: &mut Self::Evm, first_frame_input: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameInit, ) -> Result<FrameResult, Self::Error>
Executes the main frame processing loop.
This loop manages the frame stack, processing each frame until execution completes. For each iteration:
- Calls the current frame
- Handles the returned frame input or result
- Creates new frames or propagates results as needed
Sourcefn eip7623_check_gas_floor(
&self,
_evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
init_and_floor_gas: InitialAndFloorGas,
)
fn eip7623_check_gas_floor( &self, _evm: &mut Self::Evm, exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult, init_and_floor_gas: InitialAndFloorGas, )
Validates that the minimum gas floor requirements are satisfied.
Ensures that at least the floor gas amount has been consumed during execution.
Sourcefn refund(
&self,
evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
eip7702_refund: i64,
) -> Result<(), Self::Error>
fn refund( &self, evm: &mut Self::Evm, exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult, eip7702_refund: i64, ) -> Result<(), Self::Error>
Calculates the final gas refund amount, including any EIP-7702 refunds.
Sourcefn reimburse_caller(
&self,
evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
) -> Result<(), Self::Error>
fn reimburse_caller( &self, evm: &mut Self::Evm, exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult, ) -> Result<(), Self::Error>
Returns unused gas costs to the transaction sender’s account.
Sourcefn reward_beneficiary(
&self,
evm: &mut Self::Evm,
exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
) -> Result<(), Self::Error>
fn reward_beneficiary( &self, evm: &mut Self::Evm, exec_result: &mut <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult, ) -> Result<(), Self::Error>
Transfers transaction fees to the block beneficiary’s account.
Sourcefn execution_result(
&mut self,
evm: &mut Self::Evm,
result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult,
result_gas: ResultGas,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
fn execution_result( &mut self, evm: &mut Self::Evm, result: <<Self::Evm as EvmTr>::Frame as FrameTr>::FrameResult, result_gas: ResultGas, ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
Processes the final execution output.
This method, retrieves the final state from the journal, converts internal results to the external output format. Internal state is cleared and EVM is prepared for the next transaction.
Sourcefn catch_error(
&self,
evm: &mut Self::Evm,
error: Self::Error,
) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
fn catch_error( &self, evm: &mut Self::Evm, error: Self::Error, ) -> Result<ExecutionResult<Self::HaltReason>, Self::Error>
Handles cleanup when an error occurs during execution.
Ensures the journal state is properly cleared before propagating the error.
On happy path journal is cleared in Handler::execution_result method.
Dyn Compatibility§
This trait is dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".