FABRKNT
Inside Alloy — Rust Ethereum ライブラリを読む
Alloyの内側
レッスン 7 / 15·CONTENT10 分25 XP
コース
Inside Alloy — Rust Ethereum ライブラリを読む
レッスンの役割
CONTENT
順序
7 / 15

レッスン5 — 本物の Network トレイト + Ethereum / Optimism 実装を読む

問い

10 関連型 + トレイト境界を組み立ててきた。本物のソースで関連型ごとのトレイト境界、alloy の Ethereum 実装、Optimism 実装の並列比較、TransactionBuilder ヘルパートレイトを確認。一貫性の性質は具体的にどう働くか?

原理(最小モデル)

  • Network 自身の境界 6 種. Debug + Clone + Copy + Send + Sync + Sized + 'static。Copy = ゼロサイズマーカー型として値で気軽渡し。
  • マーカー struct パターン. struct Ethereum; は 1 バイト(Copy 可能)。チェーン設定(chain_id / hardfork)は別の場所、Network は「型ファミリの選択」のみ。
  • TxType: Into<u8> + TryFrom<u8>. EIP-2718 型付きエンベロープ仕様、高位 enum とワイヤ 1 バイトのマッピング。Optimism の 0x7E (Deposit) で拡張。
  • type TxEnvelope: TransactionEnvelope<Self>. 関連型ごしに揃ったヘルパートレイト、Self でパラメータ化。
  • Ethereum 実装. alloy_consensus(コンセンサス形)+ alloy_rpc_types_eth(RPC 形)の 2 クレートにまたがる。クレート境界 = 概念境界。
  • Optimism は 10 中 8 がオーバーライド. Tx 5 スロット + Receipt 2 スロット + BlockResponse がオーバーライド、Header と HeaderResponse のみ共有。
  • TransactionBuilder<N> ヘルパートレイト. 流暢な .with_to(addr).with_value(eth(1)) を chain-agnostic に。
  • AnyNetwork = 寛容な逃げ道. 任意フィールド受け入れる serde 風型、ブロックエクスプローラ / マルチチェーンインデクサ向け。

具体例

トレイト全境界:

pub trait Network: Debug + Clone + Copy + Send + Sync + Sized + 'static {
    // トランザクション側
    type TxType: Into<u8> + PartialEq + Eq + TryFrom<u8> + Send + Sync + 'static;
    type TxEnvelope: TransactionEnvelope<Self> + ...;
    type UnsignedTx: From<Self::TxEnvelope> + ...;
    type TransactionRequest: TransactionBuilder<Self> + ...;
    type TransactionResponse: Transaction<Self> + ...;

    // レシート側
    type ReceiptEnvelope: ReceiptEnvelope<Self> + ...;
    type ReceiptResponse: ReceiptResponse + ...;

    // ヘッダー / ブロック側
    type Header: BlockHeader + ...;
    type HeaderResponse: HeaderResponse + ...;
    type BlockResponse: BlockResponse<Self> + ...;
}

Ethereum 実装:

#[derive(Debug, Clone, Copy)]
pub struct Ethereum;

impl Network for Ethereum {
    type TxType = alloy_consensus::TxType;
    type TxEnvelope = alloy_consensus::TxEnvelope;
    type UnsignedTx = alloy_consensus::TypedTransaction;
    type ReceiptEnvelope = alloy_consensus::ReceiptEnvelope;
    type Header = alloy_consensus::Header;

    type TransactionRequest = alloy_rpc_types_eth::TransactionRequest;
    type TransactionResponse = alloy_rpc_types_eth::Transaction;
    type ReceiptResponse = alloy_rpc_types_eth::TransactionReceipt;
    type HeaderResponse = alloy_rpc_types_eth::Header;
    type BlockResponse = alloy_rpc_types_eth::Block;
}

注目点 2 つ:

  1. クレート境界 = 概念境界: コンセンサス形(alloy-consensus)vs RPC 形(alloy-rpc-types-eth
  2. UnsignedTx = TypedTransaction: EIP-2718 型付き tx バリアントのいずれか、完全埋まり署名直前

Optimism 実装:

#[derive(Debug, Clone, Copy)]
pub struct Optimism;

impl Network for Optimism {
    type TxType = op_alloy_consensus::OpTxType;          // ← 異なる (Deposit 追加)
    type TxEnvelope = op_alloy_consensus::OpTxEnvelope;  // ← 異なる
    type UnsignedTx = op_alloy_consensus::OpTypedTransaction;  // ← 異なる
    type ReceiptEnvelope = op_alloy_consensus::OpReceiptEnvelope; // ← 異なる (l1_fee フィールド)

    type Header = alloy_consensus::Header;  // ← Ethereum から再利用
    type HeaderResponse = alloy_rpc_types_eth::Header;  // ← 再利用

    type TransactionRequest = op_alloy_rpc_types::TransactionRequest;  // ← 異なる (mint フィールド)
    type TransactionResponse = op_alloy_rpc_types::Transaction;  // ← 異なる
    type ReceiptResponse = op_alloy_rpc_types::OpTransactionReceipt;  // ← 異なる
    type BlockResponse = op_alloy_rpc_types::Block;  // ← 異なる (OP tx を運ぶ)
}

10 スロット中 8 がオーバーライド、2 が共有:

  • 5 Tx 関連スロット(TxType、TxEnvelope、UnsignedTx、TransactionRequest、TransactionResponse)すべて違う = Optimism deposit-tx バリアントが波及
  • 2 Receipt 関連(ReceiptEnvelope、ReceiptResponse)違う = L1 ガス / L1 ブロック フィールド波及
  • Header と HeaderResponse 共有 = OP は コンセンサスヘッダレベルで EVM 互換
  • BlockResponse 違う = ブロックの tx リストに OP 型が含まれる

TransactionBuilder<N> ヘルパートレイト:

pub trait TransactionBuilder<N: Network>: ... {
    fn input(&self) -> Option<&Bytes>;
    fn set_input(&mut self, input: Bytes);
    fn with_input(mut self, input: Bytes) -> Self { ... }

    fn from(&self) -> Option<Address>;
    fn set_from(&mut self, from: Address);
    fn with_from(mut self, from: Address) -> Self { ... }

    fn to(&self) -> Option<Address>;
    fn set_to(&mut self, to: Address);
    fn with_to(mut self, to: Address) -> Self { ... }

    // ...with_value、with_gas_price、with_chain_id、with_nonce 等
}

chain-agnostic ジェネリック関数:

fn build_request<N: Network>() -> N::TransactionRequest {
    <N::TransactionRequest>::default()
        .with_to(Address::ZERO)
        .with_value(U256::from(1_000))
}

Ethereum / Optimism / AnyNetwork / カスタム L2 すべてで動く。

AnyNetwork(寛容な逃げ道):

impl Network for AnyNetwork {
    type TxType = WithOtherFields<...>;
    type TxEnvelope = AnyTxEnvelope;
    type TransactionResponse = AnyRpcTransaction;
    // ...
}

ブロックエクスプローラ / マルチチェーンインデクサ / 汎用 RPC プロキシ向け。代償 = チェーン固有フィールドの静的型付けを失い、.other() で取り出し。

失敗例(誤解)

Network はチェーン設定 struct」— 間違いゼロサイズマーカー型、チェーン設定(chain_id / hardfork)は別の場所。Network の問いは「どの型ファミリ を使うか」 — 静的・型レベル。

「Optimism は Ethereum 型を全部オーバーライド」— 間違い。10 中 8 オーバーライド、Header と HeaderResponse は 共有(OP コンセンサスヘッダレベルで EVM 互換)。一貫性の性質が共有を許す。

TransactionBuilder メソッドを関連型に直接置く」— 間違い別トレイトにすることで N 上ジェネリック関数が書ける(Ethereum / Optimism / AnyNetwork 横断で動く)、メソッドを関連型に置くと chain-agnostic コード書けない。

ステップで組み立てる

Step 1: Network 自身の 6 境界

Debug + Clone + Copy + Send + Sync + Sized + 'static。Copy = ゼロサイズマーカー型。

Step 2: TxType: Into<u8> + TryFrom<u8>

EIP-2718 wire-byte ↔ enum mapping、Optimism 0x7E で拡張。

Step 3: 関連型ごしのヘルパートレイト

type TxEnvelope: TransactionEnvelope<Self> パターン、Self でパラメータ化、chain-agnostic ヘルパー。

Step 4: Ethereum 実装の 2 クレート構造

alloy-consensus + alloy-rpc-types-eth = コンセンサス vs RPC の概念境界。

Step 5: Optimism vs Ethereum を 10 スロット並列比較

8 オーバーライド + 2 共有(Header / HeaderResponse)。

Step 6: TransactionBuilder<N> 別トレイトの利点

chain-agnostic ジェネリック関数書ける。

Step 7: AnyNetwork の使い分け

アプリ = 具体的 Network(Ethereum / Optimism)/ ツール = AnyNetwork。

答え合わせ

  • NetworkCopy を要求する理由: ゼロサイズマーカー型(struct Ethereum; は 1 バイト or 0)→ ライフタイムを気にせず値で気軽渡し可能。Clone だけだと借用が必要、Copy で関数引数 / フィールドに直接書ける。
  • Header が共有で BlockResponse が違う理由: Optimism コンセンサスヘッダは EVM 互換(同じ Merkle ルート構造)→ Header / HeaderResponse 共有 OK。BlockResponse は ブロックの tx リストに OP 型が含まれる → Ethereum の Block を再利用すると OP deposit が Ethereum 型 tx として誤シリアライズ → 別物必須。tx リスト含むものは波及、ヘッダレベルは共有可能
  • TransactionBuilder が別トレイトである利点: 同じビルダーメソッドが Ethereum / Optimism / カスタム L2 で動く + N 上ジェネリック関数(fn build_request<N: Network>() -> N::TransactionRequest)が書ける = 型レベル辞書 + ヘルパートレイト = チェーン横断で移植可能なコード

合格基準

  • Network 6 境界(Debug + Clone + Copy + Send + Sync + Sized + 'static)を即答できる。
  • マーカー struct パターンと Copy の意味を 1 文で説明できる。
  • Ethereum 実装の 2 クレート構造を言える。
  • Optimism vs Ethereum の 10 スロット並列比較(8 違 + 2 同)を即答できる。
  • TransactionBuilder<N> 別トレイトの利点を 1 文で説明できる。
  • AnyNetwork を使う場面を言える。

まとめ(3行)

  • Network 全境界 Debug + Clone + Copy + Send + Sync + Sized + 'static、関連型ごしのヘルパートレイト(type TxEnvelope: TransactionEnvelope<Self>)+ TxType の EIP-2718 マッピング。
  • Ethereum vs Optimism 並列 = 10 中 8 オーバーライド + 2 共有(Header / HeaderResponse)、コンセンサス(alloy-consensus)と RPC(alloy-rpc-types-eth)のクレート境界 = 概念境界。
  • TransactionBuilder<N> 別トレイト = chain-agnostic ジェネリック関数、AnyNetwork = 任意チェーン扱うツール向けの寛容な逃げ道。