FABRKNT
Reth Expert — 本番エンジニアリング
Reth ベースのチェーン — 拡張パターンを読む
レッスン 20 / 25·CONTENT14 分40 XP
コース
Reth Expert — 本番エンジニアリング
レッスンの役割
CONTENT
順序
20 / 25

レッスン19 — Custom ChainSpec(fork / genesis / precompile schedule)

問い

mainnet では検証が通るブロックが、あなたの chain では reject される。同じブロック、同じクライアントバイナリ、同じ Revm — なのに結果が違う。ChainSpec のどこかが「この高さでは、ここのルールが違う」と言っているから — 何が入っているか?

原理(最小モデル)

  • ChainSpec = chain のプロトコル定義. Chain ID / Hardfork activation / Base fee params / Genesis / Precompile schedule / レガシー params。
  • 6 カテゴリ. Chain ID(EIP-155 replay protection)+ Hardfork activation(block-height / timestamp スイッチ)+ Base fee(EIP-1559 elasticity / change denominator)+ Genesis(初期 allocation / state root / gas limit)+ Precompile schedule(各 fork でアクティブな precompile アドレス)+ レガシー(block gas limit / DAO fork / mining difficulty)。
  • 拡張 ChainSpec. L2 chain は base ChainSpec をラップし chain 固有 fork(Bedrock / Canyon / Ecotone / Fjord)+ 独自 precompile schedule を追加。
  • Hardfork enum がプロトコル史. 声に出して読むのが chain 理解の最速ルート。
  • Precompile activation は ChainSpec に住む. EVM config 単独ではなく ChainSpec → activation 自体がコンセンサスルール。
  • L2 chainspec の追加項目. L1 chain ID / L1 block oracle / Sequencer address / Withdrawal config。

具体例

ChainSpec 6 カテゴリ:

カテゴリ何を制御
Chain IDEIP-155 replay protection キー
Hardfork activationProtocol upgrade を切り替える block-height / timestamp スイッチ
Base fee paramsEIP-1559 elasticity、change denominator
Genesis初期 allocation、state root、gas limit
Precompile schedule各 fork でアクティブな precompile アドレス
その他レガシーBlock gas limit、DAO fork、mining difficulty(legacy)

OP Hardfork enum 例:

pub enum OptimismHardfork {
    Bedrock,
    Regolith,
    Canyon,
    Ecotone,
    Fjord,
    Granite,
    Holocene,
    // ...
}

Precompile schedule の対応:

Fork F において、アドレス A は ネイティブ関数 impl I にマップされる

実体は chain の EVM config crate、activation 判定は ChainSpec(activation 自体がコンセンサスルール)。

Genesis 出荷物:

  • Genesis JSON ファイル(allocation / gas limit / 初期 difficulty/seal)
  • chainspec crate 内 Genesis Rust struct(JSON からロード可能)
  • 計算済み genesis state root — 全ノード合意が必要

L2 chainspec 追加項目:

  • L1 chain ID — L2 がアンカーされている先(cross-domain message verification)
  • L1 block oracle address on L2 — 現 L1 block hash を記録するコントラクト
  • Sequencer address — sequencer 署名つき batch の検証用
  • Withdrawal config — L2 → L1 withdrawal の時間遅延

失敗例(誤解)

「Precompile activation は EVM config 単独で十分」— 間違い。Block N でどの precompile がアクティブかを 2 ノードが食い違って判定 → 一方が「成功」もう一方が「revert」→ stateRoot 乖離 → コンセンサス分裂。activation はコンセンサスルール → ChainSpec に置く(EVM config はその指示を実行するだけ)。

「Genesis state root はどうでもいい」— 間違い。コード上の root と実ネットワークの root が食い違えば、全ノードが block 1 で食い違う → chain が起動しない / 1 ブロックで分岐。

「ChainSpec は単なる config ファイル」— 半分間違い6 カテゴリすべてがコンセンサスクリティカル。chain ID 違い = replay 攻撃、hardfork 高さ違い = 分裂、precompile schedule 違い = stateRoot 乖離。「config」より「プロトコル定義」が正確。

🛑 予測。 "ChainSpec" は config 風に聞こえるが何が入っているか カテゴリを 5 つ 予想する。5 つに届かない / 全部 gas 関連 → consensus rule の範囲を過小評価。(答え: Chain ID / Hardfork activation / Base fee params / Genesis / Precompile schedule / レガシー params。6 カテゴリすべて consensus rule、ChainSpec 1 つ間違えると chain が分裂する。)

ステップで組み立てる

Step 1: 6 カテゴリ即答

Chain ID / Hardfork / Base fee / Genesis / Precompile schedule / レガシー。

Step 2: Hardfork enum を音読

OptimismHardfork::Bedrock / Regolith / Canyon / Ecotone / Fjord / ... を声に出す → chain のプロトコル史。

Step 3: 「fork F は block H、timestamp T でアクティブか?」関数

OP chainspec の is_fork_active_at_block / is_fork_active_at_timestamp を辿る。

Step 4: OP mainnet と Base の Bedrock activation block

両方が異なる block を持つ → OP mainnet は本番、Base は別。同じ OptimismHardfork::Bedrock でも chain ごとに高さが違う。

Step 5: L2 chainspec の追加 4 項目

L1 chain ID / L1 block oracle / Sequencer address / Withdrawal config。

答え合わせ

  • Precompile activation を ChainSpec に置く理由: 2 ノードが block N で精コンパイル set を食い違うと → 一方が呼び出し成功、もう一方が「アドレスは empty」と revert → stateRoot 乖離 → 分裂。activation はコンセンサスルール → 全ノード合意必要 → ChainSpec(プロトコル定義)に住む。
  • Genesis state root のコード ↔ 実ネットワーク食い違いの結末: 新ノード起動時、ChainSpec の genesis root を「正しい root」として使う → 実ネットワークのノードが違う root を持つ → block 1 をネットワークから受信 → 自分の post-state root と食い違う → block 1 を invalid と判定 → ネットワークから孤立。
  • L1 chainspec と L2 chainspec の追加 4 項目の存在理由: L2 は親 chain(L1)にアンカーされる → ① L1 chain ID(どの L1)+ ② L1 block oracle(L1 状態へのアクセス)+ ③ Sequencer address(sequencer 認証)+ ④ Withdrawal config(cross-layer 時間遅延)。L1 自体はアンカー先がない → 不要。

合格基準

  • 6 カテゴリを即答できる。
  • Hardfork enum を音読 → activation table が読める。
  • Precompile activation が ChainSpec に住む理由を説明できる。
  • Genesis state root の重要性を言える。
  • L2 chainspec の追加 4 項目を即答できる。

まとめ(3行)

  • ChainSpec = 6 カテゴリ(Chain ID / Hardfork activation / Base fee / Genesis / Precompile schedule / レガシー)、すべて consensus-critical。
  • Hardfork enum はプロトコル史、activation table は「fork F が block H、timestamp T でアクティブか」を答える関数。
  • L2 chainspec は L1 chain ID / L1 block oracle / Sequencer / Withdrawal の 4 項目を追加 — L1 は自分でアンカーされないので不要。