EEVM — Ethereum Virtual Machine implementation in Elixir.
Execution engine targeting Cancun, with Prague and Osaka work in progress:
full opcode set, all precompiles (including BLS12-381 via NIF), transaction
validation and processing, MPT-backed state root, and harnesses for the
official ethereum/tests suites. Conformance with those suites is still in
progress, and many rules before Cancun are not yet gated per hardfork.
Quick Start
iex> result = EEVM.execute(<<0x60, 2, 0x60, 3, 0x01, 0x00>>)
iex> result.status
:stopped
iex> EEVM.stack_values(result)
[5]Module Map
EEVM.Interpreter— fetch-decode-execute loop and call framesEEVM.Interpreter.MachineState— frame-local state (pc, stack, memory, gas)EEVM.Precompiles— registered precompiles (0x01–0x11,0x100)EEVM.Transaction— envelope decoding, validation, signing, intrinsic gasEEVM.Block.Processor— end-to-end transaction-to-receipt pipelineEEVM.Database,EEVM.WorldState,EEVM.Storage— account and storage stateEEVM.MPT.Trie+EEVM.StateRoot— Merkle-Patricia trie and state-root hashEEVM.HardforkConfig— per-hardfork EIP activation flagsEEVM.SystemContracts— EIP-2935 (block hashes) and EIP-4788 (beacon roots)
Summary
Functions
Disassembles bytecode into a human-readable list of instructions.
Executes EVM bytecode and returns the final machine state.
Returns the list of logs emitted during execution.
Computes the 256-byte logs bloom filter for the executed transaction.
Returns the stack contents as a list (top first).
Executes bytecode with an opcode-level tracer attached.
Functions
@spec disassemble(binary()) :: [{non_neg_integer(), String.t(), String.t() | nil}]
Disassembles bytecode into a human-readable list of instructions.
Example
iex> EEVM.disassemble(<<0x60, 0x01, 0x60, 0x02, 0x01, 0x00>>)
[{0, "PUSH1", "0x01"}, {2, "PUSH1", "0x02"}, {4, "ADD", nil}, {5, "STOP", nil}]
@spec execute( binary(), keyword() ) :: EEVM.Interpreter.MachineState.t()
Executes EVM bytecode and returns the final machine state.
Options
:gas— initial gas limit (default: 1,000,000)
Example
iex> result = EEVM.execute(<<0x60, 0x0A, 0x60, 0x14, 0x01, 0x00>>)
iex> EEVM.stack_values(result)
[30]
@spec logs(EEVM.Interpreter.MachineState.t()) :: [map()]
Returns the list of logs emitted during execution.
@spec logs_bloom(EEVM.Interpreter.MachineState.t()) :: EEVM.Block.Bloom.t()
Computes the 256-byte logs bloom filter for the executed transaction.
@spec stack_values(EEVM.Interpreter.MachineState.t()) :: [non_neg_integer()]
Returns the stack contents as a list (top first).
Convenience wrapper for inspecting results.
@spec trace( binary(), keyword() ) :: {EEVM.Interpreter.MachineState.t(), EEVM.Tracer.t()}
Executes bytecode with an opcode-level tracer attached.
Returns {final_state, tracer}. The tracer holds one TraceStep per
executed opcode (see EEVM.Tracer). Use EEVM.Tracer.to_json/1 to emit
a trace in EIP-3155 / geth --json format.
Example
iex> {state, tracer} = EEVM.trace(<<0x60, 0x01, 0x60, 0x02, 0x01, 0x00>>)
iex> state.status
:stopped
iex> length(EEVM.Tracer.steps(tracer))
4