How it’s verified

What is proved, what is checked, what is trusted.

Eita is an EVM engine: it re-executes every block of a chain and compares the result with the chain. Some of that rests on machine-checked proofs, some on checks that run on every block, and some is trusted — tested, not proved. This page says which is which. The engine is open source; every claim about it below points at the file that backs it.

Proved in Lean

One specification, and the code generated from it.

  • The spec EVM semantics in Lean 4, translated clause by clause from the Ethereum execution specs.

    EELS is the reference, not the Yellow Paper; the translation cites EELS by file and line. Every fork from Frontier to Osaka is a delta over its predecessor, Amsterdam is staged, and the OP Stack and Arc chain rules sit on top.

    lean/Evm/<Fork>/ · ethereum/execution-specs
  • Emitted code What executes is emitted from the spec, not written by hand.

    Emitters in Lean generate the ARM64 and x86-64 interpreters’ opcode handlers, the JIT’s chunk code, the gas formulas, the fork tables and the host’s effect layer — CALL, CREATE, SSTORE, SELFDESTRUCT, transaction application, fee settlement, block rewards. The effect layer is proved equal to each fork’s spec. A drift check requires the committed generated files to be byte-identical to what the emitters produce now, the effect proofs to check with no sorry, and no gas constant to be copied into the host by hand.

    scripts/verify-host-emit.sh · runs in CI on every change
  • Open debt The proof obligations still owed are listed, and the count may only go down.

    19 sorry remain in the spec layer — per-fork refinement theorems and three trie lemmas; none in an executable definition — and several forks’ refinement statements are still placeholders. A generated matrix lists every obligation and CI fails if the debt rises. The axiom closure of the audited theorems is checked against a committed baseline: Lean’s standard axioms only.

    refinement-coverage.md · verify-coverage.sh · verify-axioms.sh
Checked as it runs

Every block against the chain, the state against its root.

  • Every block The header gate: each block’s header is reproduced and compared with the chain’s.

    Gas used, logs bloom, receipts root, transactions root and withdrawals root are recomputed from the execution, and every sender is recovered from its signature. The header is checked against its parent by EELS validate_header — gas limit, base fee, blob gas, timestamp, number, extra data, difficulty — and the ommers by validate_ommers; the header rules are emitted from Lean too. Not checked: the proof-of-work seal (ethash).

    src/chains/block-system.lisp · receipts.lisp · HeaderValidity.lean
  • On a schedule The full state root, recomputed from the replay’s own state and compared with the header.

    On Ethereum every 10,000 blocks at the tip; on Arc at each anchor, every 32,768 blocks. A metric record carries the newest verified root, so you can tell whether a state root at or after its block has been checked. Between anchors, the header gate is the check.

    src/state/root.lisp
  • Conformance The ethereum/tests battery, on both execution tiers.

    The Cancun BlockchainTests (111,983 tests, Frontier to Cancun): 111,835 pass and none fail on both the threaded interpreter and the JIT; the 40 skipped and 108 expected failures are listed with their reasons. A sample runs in CI.

    docs/testing.md
  • Fact log The replay writes what each block did, in shards with content hashes.

    Blocks, transactions, logs, transfers, account and storage diffs go into a binary columnar log. Each sealed shard records a content hash over its canonical rows (independent of compression and grouping) and a digest of the file. The format is specified in Lean, where decoding is proved to invert encoding; the writer and readers are checked against vectors emitted from that spec, not proved equal to it. The fact log is hosted, not open source.

  • Metrics Every metric is a fold over the fact log, with its provenance.

    One pass over the rows, the same code for the history and the live tip. Each record carries its block, whether it is final, the metric’s version and the newest verified state root. Arc’s windows add their block range, the anchors checked in it, a sha256 over the sealed shard footers behind them, and an oracle check: USDC totalSupply() against the folded mints minus burns.

Not verified

Where a bug could hide that the proofs do not rule out.

  • Metric code The folds are hand-written, not derived from Lean.

    The inputs are verified; the arithmetic over them is ordinary code, checked against an oracle where one exists (Ethereum’s daily fees against a node’s headers and receipts, Arc’s USDC supply against totalSupply()), not proved.

  • Prices, formulas Oracle prices and protocol formulas in metrics.

    Prices are read from oracle contracts’ events and storage; lending health and similar protocol numbers are our transcriptions of the protocols’ own formulas, not the protocols’ code executed. A transcription can be wrong and goes stale when a protocol upgrades.

  • Off-chain Anything that is not in the chain.

    Which contracts belong to which protocol, token labels and any off-chain data are curated by hand.

  • Native code The hand-written C helpers and the third-party libraries.

    256-bit division and bit operations, buffer copies and the transaction-scoped state in C; the precompiles over libsecp256k1, mcl, blst, OpenSSL and the slh-dsa crate; zlib. They are tested — against GMP, the test fixtures and the EIP vectors — not proved. Precompile gas is computed in Lean.

    docs/trusted-surface.md lists all of it
  • Runtime The SBCL runtime, the Lisp host around the emitted code, and the toolchain.

    World tables, journal and frame plumbing are Common Lisp not yet emitted from Lean; under them, the SBCL runtime and compiler, the Lean kernel and the emitters’ printers.

  • Consensus Which chain is canonical.

    Eita does not validate consensus: it has no p2p networking and no Engine API, and takes its blocks from a node or an archive. It checks that the blocks it is given execute to the headers they carry.