FABRKNT
Inside Revm — EVM エンジンを読む
Revmの心臓部
レッスン 7 / 17·CONTENT10 分25 XP
コース
Inside Revm — EVM エンジンを読む
レッスンの役割
CONTENT
順序
7 / 17

レッスン6 — カスタム Opcode を配線する — そして失敗モード

問い

Hyperliquid は perp 用オーダーブック専用 Opcode を追加 — 200 命令の Solidity 関数が 1 バイトのネイティブディスパッチに。配線は 3 行、ショートカットは 100 倍ガス削減。それでも大半のチェーンが 50 個出さない理由は? オプションではない 3 注意点。

原理(最小モデル)

  • メカニクス 3 行. 未割当バイト選択 + standard_table をコピー + 1 スロット上書き = 配線完了、関数は前レッスンの add と同形。
  • 複利的勝ち 2 つ. ① 内部ステップごとのインタープリターループ オーバーヘッドなし、② Rust 側で SIMD / FFI / 事前計算テーブル利用可能。
  • 実利の桁. 複雑オプションプライサ = Solidity 500K ガス → カスタム Opcode 5K ガス(100 倍)。
  • 注意点 1: コンセンサス互換性. 標準 EVM から外れる → メインネットとブロック共有不可、自前チェーン限定。
  • 注意点 2: ガス価格. 強力ショートカットには適切ガス、誤価格 = DoS ベクター、方法論 = 最悪ケースベンチ + ガス予算変換 + 安全マージン 2-3 倍。
  • 注意点 3: 検証性 (ZK). 新 Opcode の zkVM 統合 = Opcode あたり数週間の追加作業、暗号演算はさらに重い。
  • 正しい数. 各 Opcode はコンセンサスリスク + 価格リスク + 検証コスト = 大半のチェーンの正解は 0-3 個

具体例

メカニクス:

const HYPER_FAST_SWAP: u8 = 0x0C;

let mut table = standard_table();
table[HYPER_FAST_SWAP as usize] = Instruction::new(my_hyper_fast_swap);

関数は add と同形:

pub fn my_hyper_fast_swap<IT: ITy, H: ?Sized>(context: Ictx<'_, H, IT>) -> Result {
    popn_top!([amount_in, pool_id], amount_out, context.interpreter);
    *amount_out = compute_swap_native(*amount_in, *pool_id);
    Ok(())
}

フロー:

flowchart LR
    Std[standard_table — 256スロット] -->|複製| Mine[フォーク用テーブル]
    Mine -->|0x0C を上書き| Custom[my_hyper_fast_swap]
    Bytecode[bytecode 0x0C ...] -->|interpreter dispatch| Mine
    Mine --> Custom
    Custom --> Result[結果がスタックへ]

ガス価格方法論 3 文:

  1. 最悪ケースをベンチ — 病的入力(最大 pool ID、最大 amount)で実時間測定
  2. ガス予算に変換 — スループット目標を最悪時間で割る
  3. 安全マージン 2-3 倍 — 分散・将来のハードウェア変化・あなたのベンチ vs 攻撃者のベンチギャップ

失敗例(誤解)

「Revm がモジュラーだからカスタム Opcode は無料」— 間違い。各 Opcode = コンセンサスリスク + 価格リスク + 検証コスト、大半のチェーンの正解は 0-3 個

「自前チェーンならコンセンサス互換性を無視できる」— そのとおりだが代償。メインネットとブロック共有不可 = go-ethereum とピア不可能、0x0C を触る最初の tx で state-root 不一致 → ピア切断。

「ガス価格は試行錯誤で決められる」— 致命的。誤価格 = DoS ベクター、攻撃者が病的入力を低ガスで実行 = ノードリソース枯渇。3 文の方法論なしにリリースしない

ステップで組み立てる

Step 1: 未割当バイト選択

crates/interpreter/src/instructions.rs で代入の左辺に出現しないバイト = 未割当。

Step 2: 関数を add 同形で書く

<IT: ITy, H: ?Sized> + popn_top! + その場書き込み。

Step 3: standard_table をコピーして 1 スロット上書き

table[BYTE as usize] = Instruction::new(my_fn); = 配線完了。

Step 4: 注意点 1 (コンセンサス) を理解

自前チェーン限定、メインネット非互換、ブロック共有不可。

Step 5: 注意点 2 (ガス価格) の 3 文方法論

最悪ケースベンチ + ガス予算変換 + 安全マージン 2-3 倍。

Step 6: 注意点 3 (検証性) で ZK ロードマップ確認

zkVM 統合 = Opcode あたり数週間、暗号演算はさらに重い。

答え合わせ

  • メカニクスが 3 行で済む構造的理由: 命令テーブルが 既にディスパッチを抽象化済み(前レッスン)= 1 スロット上書きで配線完了、関数自体は add と同形(<IT: ITy, H: ?Sized> + popn_top! + その場書き込み)。テーブル設計の合成性が「ディスパッチに触れずに Opcode 追加」を可能にする。
  • 100 倍ガス削減の根拠: 複雑 Solidity 関数 200 EVM 命令 = 200 ディスパッチ + 200 gas! + スタック移動、カスタム Opcode 1 = 1 ディスパッチ + Rust ネイティブコード(SIMD / FFI / 事前計算テーブル可)。Solidity 500K ガス → カスタム 5K ガス。
  • 大半のチェーンの正解が 0-3 個の理由: 各 Opcode = 3 コスト(コンセンサスリスク = 実装バグごとにフォーク、価格リスク = 誤価格で DoS、検証コスト = zkVM 統合に数週間)。利益(100 倍ガス削減)と費用(数週間 × 3 リスク領域)のバランスで、ホットパスに集中する 0-3 個が大半のチェーンの最適。

合格基準

  • メカニクス 3 行(バイト選択 + テーブルコピー + スロット上書き)を即書ける。
  • 関数が add 同形である理由を即答できる。
  • 注意点 3 つ(コンセンサス互換性 + ガス価格 + 検証性)を即答できる。
  • ガス価格 3 文方法論(最悪ケースベンチ + 予算変換 + 安全マージン)を即答できる。
  • 大半のチェーンの正解が 0-3 個の理由を 1 文で説明できる。

まとめ(3行)

  • カスタム Opcode 配線 = 3 行(未割当バイト + テーブルコピー + スロット上書き)、関数は add 同形(<IT: ITy, H: ?Sized> + popn_top!)、Solidity 500K → カスタム 5K ガス(100 倍削減)。
  • 注意点 3 = コンセンサス互換性(自前チェーン限定)+ ガス価格(DoS 防止の方法論必須)+ 検証性(zkVM 統合 Opcode あたり数週間)。
  • 大半のチェーンの正解 = 0-3 個、各 Opcode の 3 コスト(リスク + 価格 + 検証)がホットパスに集中させる、次レッスンでクイズ + ドリルでフォーク出荷。