レッスン1 — Reth の network crate を読む
問い
自分の chain 向けに、カスタムサブプロトコル — 決済 finality hint や MEV bundle gossip など — を追加したい。そのコードを reth ツリーのどこに置き、既存のどのピースにつなぐか? Reth のネットワーク層は crates/net/ にあり、6 つのサブ crate に分散した Rust ~30k 行。
注: 以下のコード断片は構造理解のための概念スニペットです(
...は省略箇所)。そのまま実行する用途ではありません。
原理(最小モデル)
- 6 サブ crate.
net/discv5/net/eth-wire/net/network/net/network-api/net/peers/net/dns。 - 読む順序 5 段. network-api(API 表面)→ network(オーケストレーション)→ eth-wire(プロトコルメッセージ)→ peers(peer 状態機械)→ discv5(DHT)。
- NetworkManager = 中央オーケストレータ. Swarm + NetworkHandle + Discovery + NetworkState を統合、入力 3 本(peer メッセージ + 新 peer + コマンド)→ dispatcher 1 つ。
- Swarm の状態機械. NewConnection → Handshake → Negotiation → Active → Disconnected。peer 上限 25-50 + score ベース eviction policy。
- eth-wire でメッセージ struct + RLP-derive.
#[derive(RlpDecodable, RlpEncodable)]で wire フォーマット自動生成。 - Peer 状態機械の 4 構成. Capability セット + Score(応答時間 / エラー率) + Stats(バイト数 / メッセージ数) + 接続状態。
- カスタムサブプロトコル = chain 固有 gossip の拡張点. NAME + VERSION + MESSAGES_COUNT + on_message で実装、eth/68 と同 RLPx 接続上で並走。
- Peer scoring は戦略的ハンドル. 悪い peer 排除だけでなく 既知インフラを優先、MEV / プライバシー / パフォーマンス chain の戦略的選択。
具体例
6 サブ crate マップ:
| Crate | 役割 |
|---|---|
net/discv5 | discv5 実装(Kademlia DHT) |
net/eth-wire | eth/68 メッセージ wire エンコード / デコード |
net/network | トップレベルオーケストレーション |
net/network-api | アプリケーション向け公開 API |
net/peers | Peer 管理、scoring、eviction |
net/dns | DNS ベース peer discovery(discv5 代替) |
読む順序: network-api → network → eth-wire → peers → discv5。
NetworkManager(crates/net/network/src/manager.rs):
pub struct NetworkManager<C> {
swarm: Swarm<C>, // Peer 接続
handle: NetworkHandle, // 公開 API ハンドル
from_handle_rx: UnboundedReceiver<NetworkHandleMessage>,
discovery: Discovery, // discv5 / DNS
state: NetworkState<C>, // 内部状態
// ...
}
run ループ:
swarmを poll → peer メッセージdiscoveryを poll → 新規発見 peerfrom_handle_rxを poll → コマンド(「この tx をブロードキャスト」)- 各イベントを dispatch
入力 3 本、dispatcher 1 つ = reth ネットワーキングの心臓。
Swarm 状態機械:
NewConnection → Handshake → Negotiation → Active → Disconnected
各遷移の意味:
- NewConnection: TCP 接続確立 or accept
- Handshake: RLPx で認証
- Negotiation: サポートサブプロトコル(eth/68 など)合意
- Active: メッセージ交換
- Disconnected: 正常終了 or エラー
Swarm は peer 数上限(25-50 active)+ eviction policy(score 低 peer を新接続で drop)を強制。
eth-wire メッセージ struct:
#[derive(Debug, RlpDecodable, RlpEncodable)]
pub struct NewBlock {
pub block: Block,
pub total_difficulty: U256,
}
#[derive(Debug, RlpDecodable, RlpEncodable)]
pub struct NewPooledTransactionHashes {
pub types: Vec<u8>,
pub sizes: Vec<u32>,
pub hashes: Vec<TxHash>,
}
Peer 状態機械の 4 構成:
- Capability セット: サポートサブプロトコル
- Score: 応答時間 / エラー率 / banhammer から算出
- Stats: 送受信バイト数、メッセージタイプ別、タイミング
- 接続状態: handshake / negotiation 段階
カスタムサブプロトコル例:
// 自 chain の crate 内
pub struct TempoSubProtocol {
// 状態
}
impl SubProtocol for TempoSubProtocol {
const NAME: &'static [u8] = b"tempo";
const VERSION: u8 = 1;
const MESSAGES_COUNT: u8 = 5;
fn on_message(&mut self, peer: PeerId, msg: Bytes) -> eyre::Result<()> {
let parsed: TempoMessage = decode(&msg)?;
match parsed {
TempoMessage::MerchantAttestation(att) => self.handle_attestation(peer, att),
TempoMessage::PaymentFinalityHint(hint) => self.handle_hint(peer, hint),
// ...
}
}
}
NetworkManager に登録 → eth/68 と同 RLPx 接続上で並走。新 TCP port / 別 discovery 不要、既存 peering 使い回し。
Peer scoring 戦略例:
- MEV 関連 chain: tx 伝播速度で peer scoring
- プライバシー特化 chain: メタデータ漏洩度で peer scoring
- パフォーマンス特化 chain: 帯域・レイテンシで peer scoring
- 決済優先 chain(Tempo): 既知 merchant インフラを汎用 peer より高 score
失敗例(誤解)
「カスタムプロトコル = 別の TCP port + 別 discovery」— 間違い。NetworkManager 登録で eth/68 と同 RLPx 接続上で並走。peer がカスタム NAME をサポートすれば送受信、しなければ無影響。既存 peering をそのまま使う。
「Peer scoring = 悪い peer の排除のみ」— 半分間違い。デフォルトは悪い peer ペナルティだが 戦略的ハンドル にもなる。Sequencer / MEV chain / プライバシー chain で「既知インフラ優先 / MEV 関連トラフィック routing」など chain 固有戦略。
「30k 行のコードを全部読まないと理解できない」— 間違い。読む順序 5 段(network-api → network → eth-wire → peers → discv5)で表面から深層へ。中心は NetworkManager 1 つ、入力 3 本、dispatcher 1 つ。
🛑 予測。 Reth のネットワークは ~6 サブ crate に分かれている。どんな関心事の分離が妥当?(ヒント: discovery / transport / サブプロトコルは分けるのが自然)(答え: ① discovery(discv5 + DNS)= 「peer を見つける」、② transport(network 内 swarm)= 「peer と話す(RLPx 接続管理)」、③ サブプロトコル(eth-wire)= 「何を話すか(メッセージ struct + RLP)」、④ peer 管理(peers)= 「誰と話すか(状態 + score + eviction)」、⑤ 公開 API(network-api)= 「アプリケーション層に何を見せるか」、⑥ オーケストレーション(network)= 「全部を統合する 1 ループ」。関心事分離 + 拡張点が明確 = カスタムサブプロトコルは eth-wire パターン + network 登録だけで足りる。)
ステップで組み立てる
Step 1: 6 サブ crate を即答
discv5 / eth-wire / network / network-api / peers / dns。
Step 2: 読む順序 5 段
network-api → network → eth-wire → peers → discv5。
Step 3: NetworkManager の入出力
入力 3 本(peer msg + 新 peer + cmd)→ dispatcher 1 つ。
Step 4: Swarm 5 状態
NewConnection → Handshake → Negotiation → Active → Disconnected。
Step 5: eth-wire の RLP-derive パターン
#[derive(RlpDecodable, RlpEncodable)] で wire フォーマット自動。全メッセージ RLP(tx / block と同じ)。
Step 6: カスタムサブプロトコルの 4 要素
NAME + VERSION + MESSAGES_COUNT + on_message。
Step 7: Peer scoring を戦略的に使う
悪い排除 + 既知インフラ優先 + chain 固有戦略(MEV / プライバシー / 帯域)。
答え合わせ
- NetworkManager の poll 順序の重要性: 順序が ① swarm(peer message)→ ② discovery(new peer)→ ③ command(broadcast)の場合、peer message を優先処理 → discovery が遅延しても既存接続継続。逆順だと discovery が忙しいときに既存接続のメッセージが詰まる → スループット低下。ホットパス(peer message)を先に処理。
- カスタムプロトコルが既存 peering を使い回せる理由: RLPx は multiplexing 対応(1 接続上で複数論理ストリーム)+ ネゴシエーション段階で双方の capability list を交換 → 双方サポートのプロトコルだけ active。カスタム NAME 追加でも eth/68 と並列、新 port 不要 + 新 handshake 不要 + 新 encryption 不要。
- Peer scoring の戦略的活用例: ① MEV chain で「低レイテンシ peer 優先」→ MEV 機会を先に取れる、② プライバシー chain で「Tor 経由 peer 優先」→ メタデータ漏洩最小化、③ 決済 chain で「既知 merchant ノード優先」→ 決済優先パケットの SLA、④ 帯域 chain で「高帯域 peer 優先」→ 大量データ転送効率化。chain 固有目的に合わせて scoring 重み付け。
合格基準
- 6 サブ crate を即答できる。
- 読む順序 5 段を順に言える。
- NetworkManager の入力 3 本と dispatcher 1 つを言える。
- Swarm 状態機械 5 段を順に言える。
- カスタムサブプロトコル 4 要素(NAME / VERSION / MESSAGES_COUNT / on_message)を即答できる。
まとめ(3行)
- Reth network crate = 6 サブ crate(~30k 行)、中心は NetworkManager(入力 3 本、dispatcher 1 つ)、読む順序は API 表面 → 深層。
- カスタムサブプロトコル = NAME + VERSION + on_message で実装、eth/68 と同 RLPx 接続上で並走、新 port / 新 discovery 不要。
- Peer scoring は「悪い排除」だけでなく「chain 固有戦略」(MEV 速度 / プライバシー / 帯域 / 既知インフラ優先)の戦略的ハンドル。