FABRKNT
Reth Expert — 本番エンジニアリング
本番エンジニアリング
レッスン 14 / 25·CONTENT28 分60 XP
コース
Reth Expert — 本番エンジニアリング
レッスンの役割
CONTENT
順序
14 / 25

レッスン13 — Chaos engineering を Rust EVM ノードに

問い

カスタム Reth フォークを出荷しているチームの大半は upstream のテストスイートを回して終わる。それは間違い。upstream のテストはハッピーパス(全ピア正直 / 全ディスク健全 / 全クロック正確)の正しさ。敵対的条件(DoS / 破損ページ / ずれたクロック / 嘘をつくピア)で生き残ることは別物 — どう検証するか?

原理(最小モデル)

  • Differential fuzzing + Chaos は補完. Fuzz = 「有効入力で正しい答えか」、Chaos = 「乱れた条件下で正しい答えが返らなくなるか」。両方必要。
  • 4 chaos カテゴリ. Network(パケット損失 / 分断)+ Disk(MDBX 破損 / write 失敗)+ Time(クロックずれ)+ Byzantine(嘘をつくピア)。各カテゴリにツール + 失敗シグネチャ + 対応パターン。
  • Network = tc / Toxiproxy / Pumba. Linux カーネルレベル / アプリレベルプロキシ / Docker ラッパ。
  • Disk = chaosfs / カーネル fault injection. FUSE で破損バイトを返す + fail_io_timeout で syscall 失敗注入。
  • Time = libfaketime. LD_PRELOAD でクロックずれ注入。単調クロック逆行は VM pause / resume が必要。
  • Byzantine = カスタム Reth フォーク. 意図的に間違った state root を提案するペイロードビルダー。tcchaosfs では注入不可。
  • 3 実践レベル. CI 内 chaos(毎 PR)+ Game day(四半期)+ Production chaos(週次、Netflix 風)。
  • 信頼性トライアングル. Fuzzing(正しさ)+ Chaos(耐性)+ Auditing(潜在的バグ)= 3 つそろって production-grade。

具体例

4 chaos カテゴリ表:

カテゴリ何を注入現実世界の等価
Network chaosパケット損失、レイテンシ、分断、ピア排除クラウドリージョン障害、BGP、DDoS
Disk chaosMDBX ページ破損、write 失敗、レイテンシ故障 SSD、ビット腐敗、FS バグ
Time chaosクロックずれ、NTP ドリフト、単調逆行クロックドリフト、閏秒、VM 仮想化
Byzantine chaos敵対ピアが無効ブロック / 矛盾投票 / 嘘悪意バリデータ、鍵漏洩、MitM

Network chaos:

# tc で 30% パケット損失
tc qdisc add dev eth0 root netem loss 30%

# 200ms レイテンシ
tc qdisc add dev eth0 root netem delay 200ms

# Docker コンテナ向け(Pumba)
pumba netem --duration 5m loss --percent 30 my-reth-validator

Disk chaos:

# MDBX データディレクトリに chaosfs をマウント
chaosfs --backend ./reth-data --mount ./reth-mdbx --corrupt-rate 0.001

# カーネル fault injection
echo 1 > /sys/kernel/debug/fail_io_timeout/probability
echo 100 > /sys/kernel/debug/fail_io_timeout/interval

Time chaos:

LD_PRELOAD=/usr/lib/x86_64-linux-gnu/libfaketime.so.1 FAKETIME=+30s reth node

Byzantine chaos(カスタム Reth フォーク):

// byzantine-reth フォークで: 標準のペイロードビルダーを、
// state root の 1 bit を反転させたブロックを提案するものに差し替える。
impl PayloadBuilder for ByzantinePayloadBuilder {
    fn build(&self, attrs: PayloadAttributes) -> ExecutionPayload {
        let mut block = self.honest.build(attrs);
        block.state_root ^= 1; // 1 bit 反転
        block
    }
}

3 実践レベル:

  • CI 内 Chaos: chaos サブセット毎 PR、4 ノードテストネットで network loss + clock skew + disk fault、毎 commit
  • Game day: 四半期半日、チームが手動 realistic 失敗を staging chain に注入、バグ + runbook ギャップを発見
  • Production chaos: Netflix 風週 1、コントロールウィンドウで本番バリデータ意図的 1 台落とす。最も規律ある(Tempo / OP / Hyperliquid)チームが実行。

失敗例(誤解)

tc で Byzantine も注入できる」— 間違いtc はネットワーク層、Byzantine ピアはアプリケーション層(実 Reth コードを動かして能動的に誤動作)。カスタム Reth フォーク が必要。

「サイレントなディスク破損は気づける」— 間違い。サイレント = MDBX のチェックサムが捕まえない種類の破損(1 ビット反転で意味的に valid だが間違った値)→ ノードが間違った state を serve → 他ノードと分岐 → フォーク。「サイレント」 = レッスン1にとって最悪の失敗モード

「Production chaos は危険、staging で十分」— 半分間違い。Production には staging で再現できない条件(実トラフィック / 実クライアント / 実ハードウェア)がある。規律あるチームは production も chaos する、ただし on-call が revert 準備済み + コントロールウィンドウ。

🛑 予測。 4 バリデータ BFT テストネット、1 バリデータに 80% パケット損失を 30 秒注入。起きるべき 3 つと 起きるべきでない 1 つ?(答え: 起きるべき: ① 残り 3 ノード quorum がブロック生成継続(BFT safety: f=1 に対して 3 of 4 ≥ 2f+1)、② 落ちたバリデータが復旧時に手動介入なしでキャッチアップ、③ 落ちたバリデータが inactivity でスラッシュ(policy 次第)。起きるべきでない: チェーン停止(safety 維持されているのに liveness が止まる = BFT バグ)。)

ステップで組み立てる

Step 1: 4 chaos カテゴリを即答

Network / Disk / Time / Byzantine。各カテゴリのツール 1-2 つ言える。

Step 2: tc で network chaos を 1 回実行

tc qdisc add dev eth0 root netem loss 30% → 4 バリデータテストネットで観察。

Step 3: chaosfs で disk chaos

FUSE でマウント → MDBX が破損バイトを返したとき Reth が検出するか + 優雅に停止するかサイレント不正 state serve か。

Step 4: libfaketime で time chaos

LD_PRELOAD で 30s 進める → 「未来の」ブロック提案 → ネットワークが reject + スラッシュ。

Step 5: Byzantine フォークで意図 1 bit 反転

PayloadBuilder を override → state root XOR 1 → 正直ノードが 1 スロット以内に reject すべき。

Step 6: 3 実践レベルに進化

CI 内 → Game day → Production。最後は文化、ツールではない

Step 7: 信頼性トライアングルを完成

Fuzz(正しさ)+ Chaos(耐性)+ Auditing(潜在的)= production-grade。1 つ ship なし = 既知の壊れたコード ship。

答え合わせ

  • Byzantine chaos がカスタムフォーク必要な理由: Byzantine ピアは Reth コードを動かして能動的誤動作(state root 1 bit 反転 / 矛盾投票 / 嘘な state)。tc(ネットワーク層)/ chaosfs(ファイル層)では「アプリが嘘をつく」を表現不能。コードレベルの override が必須。
  • 「サイレント破損」のカスケード: ① MDBX が間違った値を返す(チェックサムも一致してしまう種類)→ ② Reth が間違った state を計算 + serve → ③ stateRoot 検証が他ノードと一致しない → ④ ピアから「あなたのブロックは無効」とアナウンス → ⑤ ノードが分岐したフォークに居る → ⑥ 復旧は手動診断 + DB 再 sync。fork は 1 ノードから始まる
  • libfaketime でできないこと: 単調クロック逆行(Rust の Instant は単調保証 + プロセスがサスペンド/resume したり VM がマイグレートすると見える)→ LD_PRELOAD は実時計は嘘つけるが Instant は嘘つけない。カーネル時間ストレッチ or VM pause/resume が必要。

合格基準

  • 4 chaos カテゴリを即答できる。
  • 各カテゴリのツール 1-2 を言える。
  • Byzantine chaos がカスタムフォーク必要な理由を説明できる。
  • 「サイレント破損」のカスケードを 4 ステップで辿れる。
  • 信頼性トライアングルの 3 柱を即答できる。

まとめ(3行)

  • Chaos engineering = 4 カテゴリ(Network / Disk / Time / Byzantine)の失敗注入、ハッピーパステストでは見えない耐性を検証。
  • Network = tc / Toxiproxy、Disk = chaosfs、Time = libfaketime、Byzantine = カスタム Reth フォーク(コードレベル override 必須)。
  • 信頼性トライアングル(Fuzz + Chaos + Auditing)= production-grade、3 実践レベル(CI / Game day / Production)で文化として実装。