# [EIP7917] proposerの事前スケジュール仕組みを理解しよう！

> Ethereumのビーコンチェーンでは、各エポック（約 6.4 分）ごとに「ブロック proposer（提案者）」の順番が決定されます。これまでは次のエポックのproposerスケジュールが完全には予測できませんでした。

- URL: https://cardene.dev/articles/d513400abeb56d38fea3
- 公開日: 2025-06-24
- 更新日: 2025-06-24
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

『DApps開発入門』という本や色々記事を書いているかるでねです。

https://amzn.asia/d/gxvJ0Pw

今回は、次に誰がブロックを作るか（proposer）をあらかじめ一覧にして保存しておく仕組みを提案している**EIP7917**についてまとめていきます！

:::message
以下にまとめられているものを翻訳・要約・補足しながらまとめていきます。
:::

https://eips.ethereum.org/EIPS/eip-7917

他にも様々なEIPについてまとめています。

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

## 概要

Ethereumのビーコンチェーンでは、各エポック（約 6.4 分）ごとに「ブロック proposer（提案者）」の順番が決定されます。
これまでは次のエポックのproposerスケジュールが完全には予測できませんでした。
**EIP7917**では、各エポック開始時に次の `MIN_SEED_LOOKAHEAD + 1` エポック分（通常は `2` エポック先まで）のproposerスケジュールをあらかじめ計算し、`beacon_state` に保存します。
これにより「**次のエポックで誰がブロックを提案するか**」がビーコンチェーンの状態だけで決定的に分かるようになります。

## 動機

#### 現状の課題

`RANDAO` シード（ランダム値）は少なくとも `1` エポック先まで決定論的に分かりますが、proposerスケジュールはバリデータの実効残高（Effective Balance, EB）が変動すると不確定になります。

:::message
実効残高（`EB`: Effective Balance）とは、各バリデータの提案・投票における重み付けのために使用される残高です。
これは実際のETH残高とは異なり、システムがバリデータごとの公正性と効率性を保つために丸め処理（通常は `1` ETH 単位）を行った擬似的な数値です。

- 実際のETH残高が `34.25` ETH のバリデータでも、`EB` は `34` ETH になる
- `EB` は投票やproposer選出時にランダム性と重みの要素として使用される
:::

スラッシング（不正行為に対する罰則）やペナルティで `1` ETH 以上 EB が減る、あるいは報酬・デポジット・バリデータ統合で `1` ETH 以上 EB が増えると、次エポックのproposer選出計算に影響が出ます。

:::message
ブロックproposer（提案者）は、各スロットごとに「**アクティブなバリデータの集合**」から `RANDAO` シードを用いた乱択アルゴリズムで選ばれます。
このとき、各バリデータの `EB` が選出の重みに影響を与えます。

したがって、以下のような理由で `EB` が変動すると、同じ `RANDAO` シードであってもproposerの選出結果が変わる可能性があります。

- 罰則によって `EB` が減る（例：スラッシングで -1 ETH）
- デポジットや報酬によって `EB` が増える（例：1 ETH 分報酬蓄積）
- バリデータの統合によって `EB` が合算される

バリデータ統合（validator consolidation）とは、複数のバリデータが持つステークを1つのバリデータに統合する操作のことを指します。
主に以下の目的で行われます。

- ガス代の節約（管理アカウントの統合）
- ステーキングサービスの最適化（例：1人のユーザーが持つ複数ノードの統合）

統合後のバリデータは `EB` が増加するため、次のproposer選出に影響を及ぼす可能性があります。
:::

**EIP7251**（最大 `EB` を `32` ETH → $2^{32} - 1$ ETHまで拡張する提案）によりMaxEB（EB の上限）が `32` ETHを超えて拡大され、報酬加算でEBが増えやすくなったため、この不確定性がさらに大きくなります。

#### based preconfirmationプロトコルへの影響

これらのプロトコルは「**次のエポックのproposerが誰か**」をあらかじめ知っている前提で動作します。
そのため、不確定要素があるとスムーズに機能しません。
proposerスケジュールを決定論的に固定することで、アプリケーション層はビーコンルート＋簡単なMerkle証明だけで次のproposerを取得でき、実装が大幅に簡易化されます。

#### セキュリティ面の改善

`EB` を操作してproposer順を有利に変える「**グラインディング攻撃**」を封じます。

:::message
グラインディング攻撃（grinding attack）とは、ブロックチェーンがランダム性や擬似乱数に基づいて意思決定を行う部分に対して、攻撃者（多くの場合バリデータ）が自分に有利な結果が出るまで試行錯誤を繰り返すことでシステムを操作しようとする手法を指します。
Ethereumのビーコンチェーンでは、以下のような形で発生する可能性があります。

- ブロックproposerに選ばれる頻度を高めて報酬を得る
- 投票（アテステーション）の影響力を増やして合意形成を左右する
- MEV（最大実行可能価値）を獲得しやすいスロットを引き当てる
:::

これによりセキュリティ解析も単純化され、クライアント実装は次のproposerを事前に把握できるため運用も容易になります。

#### 設計上の是正

Danny Ryanが以前指摘していた「**次エポックproposerが非決定的である**」という設計上の欠点を解消します。

![lookahead-comment.png](/images/qiita-6b4cd99b-1c26-455f-8f95-57487780d38b.webp)

## 仕様

### `proposer_lookahead` の導入

ビーコンチェーンにおいて、各スロットでどのバリデータがブロック提案（proposer）を担当するかを事前に決定しておくため、`BeaconState` に新しく `proposer_lookahead` フィールドが追加されます。

このフィールドは、現在のエポックの先頭スロットから `MIN_SEED_LOOKAHEAD` エポック分先までのproposerをあらかじめ決定して格納するベクトルです。

```python
class BeaconState:
    ...
    proposer_lookahead: Vector[ValidatorIndex, (MIN_SEED_LOOKAHEAD + 1) * SLOTS_PER_EPOCH]
```

例えば、以下のようにスロットとproposerの関係が決定論的に記録されます。

* `proposer_lookahead[0]` は現在のエポックの最初のproposerのインデックス
* `proposer_lookahead[SLOTS_PER_EPOCH + 4]` は次のエポックで5番目のproposerに相当します。

### proposerの取得方法の変更

従来は各スロットごとにproposerを動的に計算していましたが、今後は `proposer_lookahead` を用いて高速に取得できるようになります。
これによりproposer選出の決定性とパフォーマンスが向上します。

```python
def get_beacon_proposer_index(state: BeaconState) -> ValidatorIndex:
    return state.proposer_lookahead[state.slot % SLOTS_PER_EPOCH]
```

ここでは、現在のスロット番号に応じて `proposer_lookahead` の対応する要素を参照するだけでproposerを得られます。

### `proposer_lookahead` の更新処理

新しいエポックが始まるたびに、`proposer_lookahead` を以下のように更新します。

1. **現在のエポック分の proposer を削除（シフト）**
2. **`MIN_SEED_LOOKAHEAD` 先のエポックのproposerを計算して追加**

この処理は `process_epoch` 関数内で呼ばれます。

```python
def process_epoch(state: BeaconState) -> None:
    ...
    process_proposer_lookahead(state)
```

具体的な更新処理は以下のようになります。

```python
def process_proposer_lookahead(state: BeaconState) -> None:
    last_epoch_start = len(state.proposer_lookahead) - SLOTS_PER_EPOCH

    # 過去分（現在のエポック）を前に詰める
    state.proposer_lookahead[:last_epoch_start] = state.proposer_lookahead[SLOTS_PER_EPOCH:]

    # 新しい proposer を計算して末尾に追加
    last_epoch_proposers = compute_proposer_indices(
        state,
        Epoch(get_current_epoch(state) + MIN_SEED_LOOKAHEAD)
    )
    state.proposer_lookahead[last_epoch_start:] = last_epoch_proposers
```

このように、常に現在から先読み範囲のproposer一覧が `proposer_lookahead` に保持される構造になっています。

### フォーク後の初期化処理

この仕様が有効になるフォーク直後の最初のブロックでは、
`MIN_SEED_LOOKAHEAD + 1` エポック分のproposerを一括で計算し、`proposer_lookahead` を初期化します。
これにより新しい仕様に即座に適応可能な状態となります。

### 実装の位置付け

この変更はビーコンチェーンのコンセンサス仕様に組み込まれ、各クライアント実装に反映されます。
`proposer_lookahead` を導入することで、ベースドプロトコルやブロック提案戦略における実装が簡素化され、セキュリティ解析も明確になります。

## 補足

### 採用されなかった代替案

ある代替案として、「**エポックNの開始時点の `EB` をキャッシュしておき、`N + MIN_SEED_LOOKAHEAD` のproposer選出に使う**」という方法が検討されました。
この方法であれば、proposerスケジュールの非決定性を避けられます。

しかし、この方法には以下の欠点があります。

* **`beacon_state` に追加の記憶領域が必要**になる
* キャッシュされた `EB` に基づいて計算されるproposerスケジュールは、アプリケーション層やスマートコントラクトから直接参照できない（beacon root を経由できない）

そのため、**EIP7917**ではこの方法は採用せず、`proposer_lookahead` フィールドの導入という現在の仕様が選ばれました。

### SSLE（Single Secret Leader Election）との互換性

将来的に単一の秘密リーダー選出（SSLE）が導入される可能性があります。
これは、ブロックproposerが誰かをスロット開始前に誰も知らないようにする方式で、DDoS対策として有効です。

ただし、現在検討されているSSLEの設計でも、暗号化されたproposerスケジュール（lookahead）を前提としています。
そのため、以下のように `proposer_lookahead` は将来のSSLE導入においても支障にはなりません。

* 現行の `proposer_lookahead` フィールドは、`List[EncryptedValidatorIndex]` のような型に変えることで再利用可能
* 仮に完全に `lookahead` を廃止する設計が登場しても、`proposer_lookahead` を空リストにすれば対応可能

なお、より高度なproposerセパレーション（Attester Proposer Separation, APS）設計が進めば、SSLEの必要性自体が下がる可能性もあります。

### エポック境界での計算負荷の増加

**EIP7917**の適用前は、各スロットで現在のproposerを1件ずつ動的に計算すれば済んでいました。

一方、**EIP7917**導入後は、エポックの開始時にそのエポック全体のproposerスケジュール（約32件）を一括で計算する必要があります。

ただし、proposer選出自体は負荷の軽い処理です。
具体的には、有効な `EB を持つバリデータが見つかるまで、ランダムにバリデータをサンプリングするだけです。
理論上の計算量は増えますが、実際のパフォーマンス上の問題がないかは今後の実装と検証で確認する必要があります。

## セキュリティ

### proposerスケジュールの改ざん防止

ブロックproposerの選出において重要なのは、バリデータがproposerスケジュール（`lookahead`）を不正に操作して自分に有利な立場を得ることを防ぐことです。

**EIP7917**（`proposer_lookahead` の導入）は、この攻撃のリスクを増加させることはありません。
なぜなら、以下の点が現在の仕様と変わらないためです。

* proposerスケジュールを決定する乱数の元（**RANDAO**）は、依然として `epoch N - MIN_SEED_LOOKAHEAD - 1` であり、
  `epoch N - MIN_SEED_LOOKAHEAD` の開始時点でしか決まりません。

つまり、proposerが選ばれる時点で使用されるランダム性（`RANDAO`）はバリデータにとって操作不能なタイミングで固定されます。

### 実効残高の参照タイミングの変更

唯一の違いは、有効残高（Effective Balance, EB）をいつのタイミングで参照するかです。

* 旧仕様
    * `epoch N` のproposerを決めるとき、`epoch N` の開始時点の `EB` を使用
* 新仕様
    * `epoch N` のproposerを決めるとき、`epoch N - MIN_SEED_LOOKAHEAD` の `EB` を使用

これにより、バリデータが `RANDAO` を見た後に `EB` を変動させてproposerスケジュールに影響を与えるといった攻撃が不可能になります。

### 攻撃実例はまだないが、理論的リスクを排除

これまでに `EB` グラインディングを利用してproposerを操作する攻撃が実際に報告されたわけではありませんが、理論的には攻撃が成立する可能性があると指摘されてきました。

この提案により、`RANDAO` と `EB` の参照タイミングが一致し、proposerスケジュールの計算が完全に決定論的に固定されることで、この攻撃経路自体が排除されてセキュリティ分析がより単純になります。

## 引用

Lin Oshitani (@linoscope) <lin@nethermind.io>, Justin Drake (@JustinDrake) <justin@ethereum.org>, "EIP-7917: Deterministic proposer lookahead [DRAFT]," Ethereum Improvement Proposals, no. 7917, March 2025. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-7917.

## 最後に

今回は「次に誰がブロックを作るか（proposer）をあらかじめ一覧にして保存しておく仕組みを提案している**EIP7917**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下のTwitterのDMなどからお気軽に質問してください！

[Twitter @cardene777](https://twitter.com/cardene777)

他の媒体でも情報発信しているのでぜひ他も見ていってください！

https://chaldene.net/

https://zenn.dev/heku

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4
