レッスン13 — Revm 自身のテスト — state test / EOF / execution-spec
問い
インタープリター + 命令テーブル + Database トレイトは歩いた。Revm チームが「Revm が EVM を正しく実行する」をどう証明しているか? コンセンサスクリティカルなエンジン = バグ 1 つでチェーン分裂、別の基準で計られる。3 テスト面の役割と境界は?
原理(最小モデル)
- 3 テスト面. State tests(
ethereum/tests、複数クライアント横断、pre → tx → post)/ EOF tests(ethereum/tests/EOFTests、EOF コンテナ validation)/ execution-spec-tests(ethereum/execution-spec-tests、仕様から生成)。 - State test の形. JSON 3 セクション =
pre(実行前状態)/transaction(適用)/post(fork ごとに state-root + logs ハッシュ)。runner = pre 構築 → tx 実行 → post ハッシュ化 → 比較。 - EOF test の形. バイトコードの validation 準拠、「validate される」or 「このエラーで reject される」アサーション、構造クリティカル(不正コンテナ accept / 有効 reject はチェーン分裂)。
- execution-spec-tests の強み. Python フレームワークで spec-aware DSL で書く → 全 fork に対し具体的 state test 自動生成 → pass = 構造的に仕様と一致。
- 3 面の役割分担. State tests = 実行セマンティクス確定後、EOF tests = コンテナ validation(別クラスバグ)、execution-spec-tests = 仕様変更を最速で捕まえる(EIP draft 段階)。
- Revm 消費者の教訓. ① pre → tx → post = EVM 実行の普遍形、② 他リファレンスへの differential(「自分は仕様ではないが一致」)= Building tier の Revm シミュレーション検証パターン、③ 生成テスト ≥ 手書き(仕様が権威時)。
- Revm が state tests を走らせる必要性. Revm 埋め込み全クライアントは Revm の正しさを継承 = Revm のバグは全下流クライアントのバグ、エンジン層の規律。
具体例
State test JSON:
{
"TestName": {
"env": { "currentNumber": "...", "currentTimestamp": "...", "currentGasLimit": "..." },
"pre": {
"0xAlice": { "balance": "0x..", "nonce": "0x..", "code": "0x..", "storage": {} }
},
"transaction": {
"data": ["0x..."],
"gasLimit": ["0x..."],
"to": "0xBob",
"value": ["0x.."]
},
"post": {
"Cancun": [{
"hash": "0x...post-state-trie-root...",
"logs": "0x...logs-bloom...",
"indexes": { "data": 0, "gas": 0, "value": 0 }
}]
}
}
}
EOF test:
{
"EmptyContainer": {
"code": "0x",
"results": { "Cancun": { "exception": "EOFException.MISSING_HEADER" } }
}
}
execution-spec-test:
@pytest.mark.valid_from("Cancun")
def test_my_opcode(state_test, fork):
pre = { Address(0x1000): Account(code=Op.MY_NEW_OPCODE + Op.STOP) }
tx = Transaction(to=Address(0x1000), gas_limit=100_000)
post = { Address(0x1000): Account(storage={0: 1}) }
state_test(env=Environment(), pre=pre, post=post, tx=tx)
3 面の捕まえタイミング:
| 面 | 捕まえタイミング | クラス |
|---|---|---|
| execution-spec-tests | EIP draft branch(活性化前) | 仕様変更 → 自動生成 |
| State tests | fork ロールアウト中 | 確定挙動の正典 |
| EOF tests | 別クラス(構造 validation) | コンテナ形式 |
失敗例(誤解)
「3 テスト面は冗長」— 間違い。コンセンサス正しさの空間を分割、execution-spec が仕様変更を最速で捕まえ、state tests が確定挙動を正典化、EOF tests がコンテナ validation を担当、各々別クラスのバグを捕まえる。
「Revm はライブラリだから state tests 走らせる必要なし」— 致命的。Revm 埋め込み全クライアント(Reth / Hyperliquid / Tempo / Berachain)は Revm の正しさを継承 = Revm のバグは全下流クライアントのバグ = エンジン層の規律。
「手書きテストで十分」— 間違い(仕様が権威時)。execution-spec-tests = テストが仕様から生成 = pass = 構造的に仕様と一致、手書きテストが取り逃すバグを捕まえる。
ステップで組み立てる
Step 1: State tests の役割
JSON 3 セクション(pre / tx / post)+ runner(pre 構築 → tx → post ハッシュ比較)= 確定挙動の正典、複数クライアント横断。
Step 2: EOF tests の役割
バイトコード validation 準拠、構造クリティカル(不正コンテナ accept / 有効 reject はチェーン分裂)。
Step 3: execution-spec-tests の役割
Python フレームワーク + spec-aware DSL → 全 fork に具体 state test 自動生成 = pass = 仕様一致、最速で仕様変更を捕まえる。
Step 4: 3 面の役割分担
実行セマンティクス(State)+ コンテナ validation(EOF)+ 仕様変更最速(execution-spec)= 冗長ではなく分割。
Step 5: Revm 消費者の教訓
pre → tx → post の普遍形 / differential パターン / 生成 ≥ 手書き。
Step 6: Revm が state tests 必須の理由
Revm 埋め込み全クライアントが正しさ継承 = エンジン層の規律。
答え合わせ
- 3 テスト面が分割する空間: ① State tests = 実行セマンティクス確定後の正典挙動、② EOF tests = コンテナ validation(実行前のパース / validate、別クラスバグ)、③ execution-spec-tests = 仕様変更を最速で捕まえる(EIP draft 段階で CI が回す)。「ガスコスト変更」を例に: execution-spec が EIP merge 前に捕まえ、State tests が fork ロールアウト中に捕まえ、EOF tests は捕まえない(構造ではない)。
- execution-spec-tests が「pass = 仕様一致」を保証する根拠: テストが spec-aware DSL で書かれ仕様から自動生成 = テスト pass = 構造的に仕様と一致。手書きテストは「自分が書いたものとは一致」しか保証しない、仕様との乖離を捕まえられない。新 EIP(新 opcode / precompile / ガス規則変更)がカバレッジを得る方法。
- Revm が state tests を走らせる必要性: Revm は ライブラリだが、埋め込み全クライアント(Reth / Hyperliquid / Tempo / Berachain)が Revm の正しさを継承 = Revm のバグは全下流クライアントのバグ = mainnet 起動前に互換性報告する必要 = エンジン層に住む規律。「ライブラリだから関係ない」が成立しない構造。
Expert への接続
このレッスンは revm 本体 の性質としての state-test 規律を扱う。Expert tier ではこれを systems 層に広げる 2 レッスンがある:
- Differential fuzzing と execution-spec-tests — 複数 EVM 実装にわたる random-sequence の diff testing
- Systems-code auditing — Reth/revm の patch を監査人の目で読む方法
合格基準
- 3 テスト面(State / EOF / execution-spec)の役割を即答できる。
- State test JSON 3 セクション(pre / tx / post)を即答できる。
- EOF test の構造クリティカル理由を 1 文で説明できる。
- execution-spec-tests が「pass = 仕様一致」を保証する根拠を即答できる。
- Revm 消費者の 3 教訓(pre→tx→post / differential / 生成 ≥ 手書き)を即答できる。
- 「Revm が state tests を走らせる必要性」の根拠(埋め込み全クライアント継承)を 1 文で説明できる。
まとめ(3行)
- 3 テスト面 = State tests(確定挙動の正典)+ EOF tests(コンテナ validation)+ execution-spec-tests(仕様変更最速、自動生成)= 冗長でなく分割。
- 「pass = 仕様一致」を保証するのは execution-spec-tests(DSL → 仕様から自動生成)、手書きテストは「自分が書いたものとは一致」しか保証しない、新 EIP カバレッジの正規ルート。
- Revm 埋め込み全クライアント(Reth / Hyperliquid / Tempo / Berachain)が正しさ継承 = Revm のバグは全下流バグ = state tests 走らせるのはエンジン層の規律、次は並列実行(block-stm)。