# `EEVM.Interpreter`
[🔗](https://github.com/mw2000/eevm/blob/v0.1.0/lib/eevm/interpreter.ex#L1)

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 the frame's per-hardfork
`EEVM.Interpreter.InstructionTable` (built from
`EEVM.Interpreter.Instructions.Registry`); opcode modules own their
semantics, and the interpreter only orchestrates.

# `finalize`

```elixir
@spec finalize(
  EEVM.Interpreter.MachineState.t(),
  non_neg_integer(),
  non_neg_integer()
) ::
  EEVM.Interpreter.MachineState.t()
```

Applies the transaction-end steps to a halted top-level state: deletes the
accounts that SELFDESTRUCTed and touched empty accounts (EIP-161), then settles the refund counter into
`frame.gas` and resets the counter to 0.

The refund is capped at a fraction of the gas used by the whole
transaction: 1/5 from London (EIP-3529), 1/2 before. When `env.tx.gas_limit`
is set, gas used counts from it and so includes intrinsic gas; otherwise it
counts from `initial_gas`. The execution refund counts only when execution
succeeded; `authorization_refund` (EIP-7702) always counts. From Prague the
gas charged after the refund is floored at the EIP-7623 calldata cost.

`run/2` calls this itself. Callers that charge more gas after execution
ends, such as the code deposit of a CREATE transaction, call `run_loop/1`,
charge that gas, then call this, so the cap counts it.

# `run`

```elixir
@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, with the
transaction-end steps of `finalize/3` applied.

# `run_loop`

```elixir
@spec run_loop(EEVM.Interpreter.MachineState.t()) :: EEVM.Interpreter.MachineState.t()
```

The main execution loop. Runs the active frame until it halts.

Any status but `:running` means the frame has already halted, and the state
is returned as-is. It runs one frame: CALL and CREATE run each child frame in
a nested call and merge the result into the parent
(`EEVM.Interpreter.Journal`). It is public for those callers and the
transaction handler; it is not part of the public API — use `run/2`.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
