レッスン18 — op-stack-on-reth を読む
問い
Optimism は「Reth ベース L2」の正典。node コードは paradigmxyz/reth/crates/optimism/。Tempo の node crate も同様の構造で公開済み(tempoxyz/tempo)。ここを読めれば向こうも読める — ディレクトリ構造を一目で解く方法は?
原理(最小モデル)
- Reth ベース chain の sub-crate 構造. chainspec / node / evm / payload / consensus / rpc / txpool / hardforks。
- 依存関係は extension model の証拠.
reth-optimism-nodeはreth-node-builder+reth-chainspecなどの core crate に依存 + OP 固有 sibling crate に依存、reth-node-ethereumには依存しない(並列 mainnet node crate)。 - 5 分で辿る背骨. ① NodeBuilder composition / ② ChainSpec / ③ Executor / EVM config / ④ Payload builder / ⑤ Genesis JSON。
- 初回読書 4 ステップ.
README.md+Cargo.toml→chainspec/→node/(NodeBuilder composition)→ NodeBuilder 順に各カスタマイズ crate → tests。 - Tempo の構造予測. tempo-chainspec / tempo-node / tempo-evm / tempo-payload-builder / tempo-pool / tempo-consensus(L1 なので存在)。
具体例
OP Stack の sub-crate(reth バージョンで揺れるのでソース確認推奨):
| Subdirectory | 担当 |
|---|---|
chainspec/ | OP chain spec — fork、genesis、gas params、precompile schedule |
node/ | トップレベル NodeBuilder 配線 — 「これが OP node である」 |
evm/ | EVM config — custom precompile、deposit tx semantics、L1 cost logic |
payload/ | Payload builder — sequencer mode での block 生成 |
consensus/ | OP の consensus engine(finality は L1 に委ねる) |
rpc/ | Custom RPC namespace(optimism_* メソッド) |
txpool/(または類似) | Deposit-tx を認識する mempool policy |
hardforks/ | Bedrock、Canyon、Ecotone、Fjord、... の fork activation logic |
依存関係探索:
cargo tree -p reth-optimism-node
見えるもの:
reth-optimism-node→reth-node-builder/reth-chainspec/reth-evm/reth-payload-builder/reth-rpc-builder/revm/alloy-*- OP 固有 sibling:
reth-optimism-chainspec/reth-optimism-evm/reth-optimism-payload-builder/ ... reth-node-ethereumには依存しない(並列 mainnet node)
5 分背骨:
- NodeBuilder composition —
*-node/src/lib.rsかnode/builder.rs - ChainSpec —
*-chainspec/src/ - Executor / EVM config —
*-evm/src/ - Payload builder —
*-payload-builder/src/か*-payload/src/ - Genesis JSON — chainspec crate インラインまたは独立
.json
初回読書順:
README.md+Cargo.toml— どの crate が存在するか把握chainspec/— fork activation を声に出すnode/— NodeBuilder composition、どこがカスタマイズされているか- NodeBuilder で名前が出てきた順 に各 crate
- Tests — 特に state-transition test
Tempo 予測構造:
tempo-chainspec相当 — Tempo 固有 fork 高、gas params、決済固有 precompiletempo-node相当 — NodeBuilder compositiontempo-evm相当 — 決済 primitives 用 precompile(FX rate / settlement-proof / regulated-asset)tempo-payload-builder相当 — sequencer 用tempo-pool相当 — 決済固有 mempool policy(merchant 認可)tempo-consensus相当 — Tempo は L1 なので存在
メタ観察: tempoxyz/reth = 0 commits ahead, 1374 commits behind。Reth 本体は触られていない。
失敗例(誤解)
「OP は reth-node-ethereum に依存する」— 間違い。並列関係。両者は共有 reth-core crate(reth-node-builder / reth-chainspec)を消費するが、互いに依存しない。OP も Ethereum も「chain」の選択肢、Ethereum が特権ではない。
「Reth ベース chain の構造は chain ごとに完全に違う」— 間違い。SDK が共通骨格を強制: chainspec / node / evm / payload / consensus / rpc の sub-crate 構造。chain 固有部分は各 sub-crate 内、骨格は同じ。
「Tempo は L2 なので OP と同構造」— 間違い。Tempo は L1(独立 consensus 持つ)→ tempo-consensus が存在、Deposit tx / L1 cost / L1 block oracle なし。OP は L2(L1 にアンカー)。観点で違いがある。
🛑 予測。
node.rsというファイルにOpNodeという型を見つけた。OpNodeが 何であるか と 何をするか を理解するために、次にどこを見る? 実装している trait を予測してから。(答え: ①impl FullNodeTypes for OpNodeを探す(Node primitives 定義)+ ②impl NodeAdapter for OpNodeまたはimpl Node for OpNodeを探す(NodeBuilder 配線)+ ③OpNode::components()メソッド(6 コンポーネント差し替え)。trait はreth_node_api/reth_node_builderから来る。何であるか = NodeBuilder 型パラメータ、何をするか = components() で chain 固有部品を差し込む。)
ステップで組み立てる
Step 1: 8 sub-crate を列挙
chainspec / node / evm / payload / consensus / rpc / txpool / hardforks。
Step 2: cargo tree で依存可視化
cargo tree -p reth-optimism-node → 共有 core crate + OP 固有 sibling + Ethereum non-dependency。
Step 3: 5 分背骨を辿れる
NodeBuilder → ChainSpec → Executor/EVM → Payload → Genesis。
Step 4: 初回読書 4 ステップ
README+Cargo.toml → chainspec → node → NodeBuilder 順 + tests。
Step 5: Tempo を予測構造で読む
8 sub-crate 相当を予測 → 実際の repo で検証 → L1 vs L2 観点で違い理解。
答え合わせ
- op と Ethereum が並列関係である構造的理由: NodeBuilder + ChainSpec が「複数 chain を同 SDK で扱う」設計。Ethereum は「mainnet」chain の実装、OP は「Optimism」chain の実装、両者が同 substrate(reth-node-builder / reth-chainspec / reth-evm)を消費。一方が「親」ではない、両方が「兄弟」。
- SDK が骨格を強制する理由: NodeBuilder の API(
.with_types::<ChainNode>().with_components(...))が「6 コンポーネント差し替え」パターンを強制 → 各 chain が同じ場所に同じ種類の crate を置く → 新しい chain repo を 5 分で navigate 可能。 - L1 vs L2 の観点別差分: L1(Tempo)= 独立 consensus + Deposit tx なし + L1 cost なし + L1 block oracle なし。L2(OP)= 親 chain consensus 依存 + Deposit tx あり + L1 cost あり + L1 block oracle あり。両者とも extension モデルだが「何を差し替えるか」が違う。
合格基準
- 8 sub-crate を即答できる。
cargo treeで extension model を確認できる。- 5 分背骨(NodeBuilder → ChainSpec → Executor → Payload → Genesis)を辿れる。
- 初回読書 4 ステップを言える。
- L1 と L2 の観点別差分を 4 つ言える。
まとめ(3行)
- Reth ベース chain は 8 sub-crate 構造(chainspec / node / evm / payload / consensus / rpc / txpool / hardforks)、SDK が骨格を強制。
- 5 分背骨(NodeBuilder → ChainSpec → Executor → Payload → Genesis)+ 初回読書 4 ステップ(README → chainspec → node → NodeBuilder 順 + tests)。
- L1(Tempo)と L2(OP)は extension モデル共通だが Deposit / L1 cost / consensus の有無で差分 — 観点で読めば両方読める。