eot 0.2.0

EVM opcodes library with fork-aware gas costs, static metadata, and bytecode analysis
Documentation

eot - EVM Opcode Table

EVM opcodes library with fork-aware gas costs, static metadata, and bytecode analysis.

Crates.io Documentation Build Status License: MIT

Overview

eot provides a single OpCode(u8) type backed by a static [Option<OpCodeInfo>; 256] lookup table for O(1) opcode lookups with zero heap allocation. Every opcode carries its name, stack I/O, gas cost, group, introduction fork, EIP reference, immediate size, and termination flag.

Fork-specific gas costs (EIP-150, EIP-1884, EIP-2929) are resolved at query time via OpCode::gas_cost(fork), so there's no need for per-fork enum types. A DynamicGasCalculator handles warm/cold access, memory expansion, and complex call pricing for more precise analysis.

Quick start

use eot::{OpCode, Fork};

// O(1) lookup
let add = OpCode::ADD;
assert_eq!(add.gas_cost(Fork::Frontier), 3);
assert!(add.is_valid_in(Fork::Frontier));

// Parse from byte
let op = OpCode::new(0x60).unwrap();
assert_eq!(op, OpCode::PUSH1);
assert_eq!(op.info().unwrap().immediate_size, 1);

// Parse from string
let op: OpCode = "KECCAK256".parse().unwrap();
assert_eq!(op.byte(), 0x20);

// Gas cost evolution
assert_eq!(OpCode::SLOAD.gas_cost(Fork::Frontier), 50);
assert_eq!(OpCode::SLOAD.gas_cost(Fork::TangerineWhistle), 200);
assert_eq!(OpCode::SLOAD.gas_cost(Fork::Istanbul), 800);
assert_eq!(OpCode::SLOAD.gas_cost(Fork::Berlin), 2100); // cold access

Features

  • 149 opcodes from Frontier through Prague with full metadata
  • Zero-allocation lookups via a static 256-element array
  • Fork-aware gas costs encoding EIP-150, EIP-1884, EIP-2929 repricing
  • Dynamic gas calculator for warm/cold access, memory expansion, call pricing
  • Sequence analysis with optimization suggestions
  • Fork comparison to see what changed between any two forks
  • Validation of the opcode table against known historical facts
  • Optional serde support behind the serde feature flag

Supported forks

Fork Date Key changes
Frontier Jul 2015 Base set (130+ opcodes)
Homestead Mar 2016 DELEGATECALL
Tangerine Whistle Oct 2016 EIP-150 gas repricing
Spurious Dragon Nov 2016 EIP-161/170
Byzantium Oct 2017 REVERT, RETURNDATASIZE, RETURNDATACOPY, STATICCALL
Constantinople Feb 2019 SHL, SHR, SAR, CREATE2, EXTCODEHASH
Petersburg Feb 2019 Reverted EIP-1283
Istanbul Dec 2019 CHAINID, SELFBALANCE, EIP-1884 repricing
Berlin Apr 2021 EIP-2929 warm/cold access costs
London Aug 2021 BASEFEE (EIP-1559)
Paris Sep 2022 DIFFICULTY becomes PREVRANDAO
Shanghai Apr 2023 PUSH0 (EIP-3855)
Cancun Mar 2024 TLOAD, TSTORE, MCOPY, BLOBHASH, BLOBBASEFEE
Prague May 2025
Fusaka Dec 2025 EOF (EIP-7692), CLZ, RJUMP, CALLF, DUPN, SWAPN, EXTCALL, +13 more

Gas analysis

use eot::gas::{DynamicGasCalculator, ExecutionContext};
use eot::Fork;

let calc = DynamicGasCalculator::new(Fork::Berlin);
let mut ctx = ExecutionContext::new();

// Cold SLOAD
let cold = calc.calculate_gas_cost(0x54, &ctx, &[0x100]).unwrap();

// Warm the slot, then re-read
let key = {
    let mut k = [0u8; 32];
    k[24..32].copy_from_slice(&0x100u64.to_be_bytes());
    k
};
let addr = ctx.current_address;
ctx.mark_storage_accessed(&addr, &key);
let warm = calc.calculate_gas_cost(0x54, &ctx, &[0x100]).unwrap();

assert!(warm < cold);

Architecture

src/
  lib.rs              OpCode, OpCodeInfo, Fork, Group, OPCODE_TABLE, gas_cost_for_fork()
  gas.rs              Gas constants, GasCostCategory, GasAnalysis
  gas/calculator.rs   DynamicGasCalculator (warm/cold, memory, calls)
  gas/context.rs      ExecutionContext, Address/StorageKey types
  gas/analysis.rs     GasAnalyzer, GasComparator, GasOptimizationAdvisor
  validation.rs       Static table validation

The entire opcode table is a single static [Option<OpCodeInfo>; 256] initialized at compile time. No HashMap, no heap allocation, no per-fork enum duplication.

Contributing

  1. Adding an opcode or fork: edit the opcodes! invocation in src/lib.rs and add the fork variant to the Fork enum. Run cargo tt to verify.
  2. Fixing gas costs: update gas_cost_for_fork() in src/lib.rs for historical changes, or the base_gas in the opcode table for base costs.
  3. Adding analysis features: extend gas/analysis.rs or gas/calculator.rs.