FABRKNT
P2P ネットワーキング内部 — devp2p からカスタム gossip まで
P2P ネットワーキング
レッスン 2 / 4·CONTENT17 分45 XP
コース
P2P ネットワーキング内部 — devp2p からカスタム gossip まで
レッスンの役割
CONTENT
順序
2 / 4

レッスン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/discv5discv5 実装(Kademlia DHT)
net/eth-wireeth/68 メッセージ wire エンコード / デコード
net/networkトップレベルオーケストレーション
net/network-apiアプリケーション向け公開 API
net/peersPeer 管理、scoring、eviction
net/dnsDNS ベース 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 ループ:

  1. swarm を poll → peer メッセージ
  2. discovery を poll → 新規発見 peer
  3. from_handle_rx を poll → コマンド(「この tx をブロードキャスト」)
  4. 各イベントを 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 速度 / プライバシー / 帯域 / 既知インフラ優先)の戦略的ハンドル。