レッスン4 — Reth の Consensus trait を読む
問い
Reth のソースを開く。「PoS」で検索する。ほとんど何も出てこない — なぜなら Reth は PoS も BFT もまったく実装していないから。その仕事は consensus client(Lighthouse、Prysm、自前エンジン)側にある。では「Hyperliquid は Reth で動く」「Berachain は PoL のために Reth を fork した」と言うとき、実際に触っているコンセンサスの接合面は何か?
原理(最小モデル)
- 役割分担: head 選択(CL) vs ブロック検証(EL = Reth). Reth の
Consensustrait は chain head を選ばない。受け取ったブロックを 検証する だけ。 - 3 フェーズの検証.
validate_block_pre_execution(安いチェック、EVM 不要)→validate_body_against_header(暗号的整合性)→validate_block_post_execution(state root、ガス、receipt — コンセンサスクリティカル)。 - HeaderValidator が親 trait. Header の検証は body の検証から分離されている — header は先に到着、body なしで検証可能、ライトクライアントは header だけでよい。
- BFT 固有のチェックは HeaderValidator に入る. 「この proposer はこの slot の選出リーダーか?」「proposer 署名は valid か?」など。
具体例
crates/consensus/consensus/src/lib.rs の中核 trait:
#[auto_impl::auto_impl(&, Arc)]
pub trait Consensus<B: Block>: HeaderValidator<B::Header> {
type Error;
fn validate_body_against_header(
&self,
body: &B::Body,
header: &SealedHeader<B::Header>,
) -> Result<(), Self::Error>;
fn validate_block_pre_execution(
&self,
block: &SealedBlock<B>,
) -> Result<(), Self::Error>;
}
pub trait FullConsensus<N: NodePrimitives>: Consensus<N::Block> {
fn validate_block_post_execution(
&self,
block: &RecoveredBlock<N::Block>,
result: &BlockExecutionResult<N::Receipt>,
) -> Result<(), ConsensusError>;
}
HeaderValidator:
pub trait HeaderValidator<H>: Send + Sync + Debug {
fn validate_header(&self, header: &SealedHeader<H>) -> Result<(), ConsensusError>;
fn validate_header_against_parent(
&self,
header: &SealedHeader<H>,
parent: &SealedHeader<H>,
) -> Result<(), ConsensusError>;
fn validate_header_with_total_difficulty(
&self,
header: &H,
total_difficulty: U256,
) -> Result<(), ConsensusError>;
}
3 フェーズ × 各フェーズで見るもの:
| フェーズ | チェック内容 | コスト |
|---|---|---|
| pre_execution | tx root / receipt root / block hash / size / timestamp | <1ms |
| body_against_header | transactions root == merkle(tx)、withdrawals root | 暗号的、明確 |
| post_execution | gas used / state root / receipts root / logs bloom | コンセンサスクリティカル |
失敗例(誤解)
「Reth は PoS を実装している」— 間違い。Reth は EL(execution layer)。PoS(投票、attestation、proposer 選出)は CL(consensus client)の仕事。Reth は受け取ったブロックを検証するだけで、誰が head かを選ばない。
「state root チェックは pre-execution で十分」— 間違い。post-execution が知っている = pre-execution が知らない = 「実際に EVM を回した結果の post-state」。state root は post-execution でしか検証できない。
🛑 予測。 Reth はコンセンサスレイヤから来るブロックを検証する必要がある。EVM が tx を実行する前に、どんなチェックが走るべきか? 4 つ列挙。(答え: ① 暗号的 = tx root / receipt root が header と一致、② 構造的 = block hash が well-formed、③ 時間的 = timestamp が未来に行き過ぎていない、④ コンセンサス固有 = proposer がアクティブな validator set にいるか、署名は有効か、round 番号は正しいか。)
ステップで組み立てる
Step 1: 3 フェーズを実行順で覚える
pre_execution → body_against_header → post_execution。trait の宣言順ではなく ランタイムで走る順序。
Step 2: デフォルト実装 EthBeaconConsensus を読む
crates/ethereum/consensus を開く。チェック内容:
- ブロックが正しい形であること
- 実行後の state root が一致すること
- Gas limit が parent の ±1/1024 以内(EIP-1559 弾性境界)
- BaseFee が EIP-1559 公式に従うこと
- Timestamp が単調増加すること
PoS の検証はしない — それは CL の仕事。
Step 3: BFT 用のカスタム override 箇所
| Override 箇所 | 理由 |
|---|---|
| HeaderValidator | proposer 署名、validator set 包含、view/round 番号 |
| validate_block_post_execution | コンセンサス固有 post-state(HyperEVM の orderbook 状態など) |
| Slashing 関連フィールド | header に slashing 証拠が含まれる場合の暗号検証 |
trait を書き直すわけではない — 異なる実装を提供して NodeBuilder に配線する。
Step 4: リポで実物を読む
git clone https://github.com/paradigmxyz/reth
cd reth
crates/consensus/consensus/src/lib.rsを開いてConsensustrait の全体を読むcrates/ethereum/consensus/src/lib.rsを開いて実装を見つける- 数える:
EthBeaconConsensusは何個のメソッドを override し、いくつをデフォルトのまま使っているか? validate_block_post_executionが呼び出される唯一の場所を見つける(メソッド名で検索)
答え合わせ
- head 選択 vs ブロック検証の境界: head 選択 = consensus client(Lighthouse / Prysm / 自前)、ブロック検証 = Reth の
Consensus実装。 - state root を post に置く理由: state root は EVM 実行の結果。pre には実行結果がない(post になって初めて分かる)。
- BFT カスタム L1 で override すべき 3 箇所: HeaderValidator(proposer 署名 + validator set)、validate_block_post_execution(コンセンサス固有 post-state)、slashing 関連フィールドの暗号検証。
合格基準
- 3 検証フェーズを実行順で言える。
- 「Reth は head を選ばない」「CL が head を選ぶ」を即答できる。
- HeaderValidator がなぜ Consensus trait の親なのか言える。
- リポを clone して
ConsensusとEthBeaconConsensusの関係を辿れる。
まとめ(3行)
- Reth の
Consensustrait は ブロック検証 のみを担う — head 選択は consensus client の仕事。 - 検証は 3 フェーズ(pre / body↔header / post)、post-execution が state root / gas / receipt のコンセンサスクリティカルチェック。
- BFT カスタム L1 は trait を書き直さず HeaderValidator + validate_block_post_execution に 異なる実装を提供 して NodeBuilder に配線する。