The EVM interpreter — fetches, decodes, and dispatches opcodes in a loop.
This is the core opcode-execution engine. It is invoked by EEVM.Handler
(the transaction-level pipeline) and by system contracts that need to
evaluate bytecode against an existing world state.
Execution ends when a terminating opcode is reached (STOP, RETURN, REVERT, INVALID), the program counter advances past the end of the bytecode (implicit STOP), or gas runs out before the opcode can execute. INVALID (0xFE) is special-cased: its "base" gas cost is set to the entire remaining gas, draining it completely before the opcode runs.
Opcode dispatch is data-driven via
EEVM.Interpreter.Instructions.Registry; opcode modules own their
semantics, and the interpreter only orchestrates.
Summary
Functions
Creates a MachineState from bytecode and options, then runs the execution loop.
The main execution loop. Runs until execution terminates.
Functions
@spec run( binary(), keyword() ) :: EEVM.Interpreter.MachineState.t()
Creates a MachineState from bytecode and options, then runs the execution loop.
Options
:gas— initial gas limit (default: 1_000_000):value— ETH value sent with the call, in wei:code— contract bytecode (usually the same as the first argument):calldata— ABI-encoded input data for the call:caller— address of the account initiating this call:origin— address of the original transaction signer:authorization_refund— EIP-7702 refund earned before execution; it is added to the refund counter even when execution fails
Returns the final MachineState after execution completes.
@spec run_loop(EEVM.Interpreter.MachineState.t()) :: EEVM.Interpreter.MachineState.t()
The main execution loop. Runs until execution terminates.
Three clauses handle the three possible states:
status: :running— fetch the current opcode, deduct static gas, delegate toexecute_opcode/2, and recurse.- Any non-running status (
:stopped,:returned,:reverted,:invalid,{:error, reason}) — the machine has halted; return as-is. - Out-of-gas during static cost deduction — the halted state is returned
directly from
MachineState.consume_gas/2.
This function is public because it is called recursively by itself. It is
the internal execution engine and not part of the public API — use run/2.