# [EIP4399] DIFFICULTYオペコードをPREVRANDAOオペコードに置き換える提案を理解しよう！

> このEIP（Ethereum Improvement Proposal：イーサリアム改善提案）は、既存のDIFFICULTY（0x44）オペコードの戻り値の意味を変更し、オペコードの名前をPREVRANDAO（0x44）に変更するものです。

- URL: https://cardene.dev/articles/121949e0763872786a01
- 公開日: 2024-02-21
- 更新日: 2024-02-21
- トピック: Blockchain
- タグ: ethereum, solidity, smartcontract, ブロックチェーン

## はじめに

初めまして。
**CryptoGames**というブロックチェーンゲーム企業でエンジニアをしている **cardene（かるでね）** です！
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームは**クリプトスペルズ**というブロックチェーンゲームです。

https://cryptospells.jp/

今回は、PoSへの移行に伴い、`DIFFICULTY`オペコードの戻り値は意味を持たなくなり、代わりに`PREVRANDAOが`ランダムネスを渡す提案している**EIP4399**についてまとめていきます！

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

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

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

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

## 概要

このEIP（Ethereum Improvement Proposal：イーサリアム改善提案）は、既存の`DIFFICULTY`（`0x44`）オペコードの戻り値の意味を変更し、オペコードの名前を`PREVRANDAO`（`0x44`）に変更するものです。

EIPとは、イーサリアムのプロトコルを改善するための提案であり、新しい機能の追加や既存の仕様の変更などが含まれます。

#### オペコードの名前の変更
`DIFFICULTY`というオペコードの名前が`PREVRANDAO`に変更されます。
オペコードとは、イーサリアムのバーチャルマシン（EVM）が実行する命令のことです。
この名前の変更は、オペコードの機能が変更されることを反映しています。

:::message
オペコードについては以下の記事を参考にしてください。
:::

https://zenn.dev/heku/books/aef33b86ded3c0

#### 戻り値の変更
変更前は、`DIFFICULTY`オペコードは現在のブロックの難易度を返すものでした。
しかし、このEIPによって、`PREVRANDAO`（元の`DIFFICULTY`）オペコードの戻り値は、ビーコンチェーンによって提供されるランダムネスビーコン（乱数発生器）の出力になります。

ビーコンチェーンとは、イーサリアム2.0で導入された新しいコンセプトの1つで、より高速で効率的なネットワークの運用を目指しています。
ランダムネスビーコンは、分散型アプリケーション（dApps）やスマートコントラクトが公平で予測不可能な乱数を必要とする場合に使用されます。

この変更により、スマートコントラクトの開発者は、以前はブロックの難易度にアクセスしていた同じオペコードを使用して、信頼性の高い乱数にアクセスできるようになります。
これにより、ゲーム、抽選、その他のランダム性を必要とするアプリケーションのセキュリティと信頼性が向上します。

## 動機

イーサリアムのProof-of-Stake（PoS：プルーフ・オブ・ステーク）への移行と、それに伴う既存の`DIFFICULTY`オペコードの使い方に関する改善提案（EIP）について説明しています。

#### ビーコンチェーンによるランダムネスの利用
アプリケーションはビーコンチェーンが蓄積するランダムネスを利用することで利益を得られます。
そのため、ビーコンチェーンが生成するランダムネスはEVM（イーサリアム仮想マシン）内でアクセス可能であるべきです。

#### PoSアップグレードと難易度フィールド
**EIP3675**で説明されているProof-of-Stakeへの移行時、`TRANSITION_BLOCK`が設定されると、ブロックの難易度フィールドは`0`に設定されなければなりません。
これは、PoW（プルーフ・オブ・ワーク）によるブロックの検証がなくなるためです。
これにより、`DIFFICULTY`オペコードは以前の意味を失い、返すべき値もなくなります。

#### 既存スマートコントラクトの後方互換性
過去の分析によると、スマートコントラクトはランダムネスを得るために`DIFFICULTY`から返される値を他の値と混合することが一般的です。
ビーコンチェーンのRANDAO実装から出力される値を返す`DIFFICULTY`と同じ番号の命令を用意することで、PoSへのアップグレードが既存のスマートコントラクトに対して後方互換性を持つようになります。

#### PoSへのアップグレードの検出
このEIPによる変更により、スマートコントラクトはPoSへのアップグレードが既に行われたかどうかを判断できるようになります。
これは、`DIFFICULTY`命令の戻り値を分析することで行えます。
戻り値が2**64より大きい場合、そのトランザクションはPoSブロック内で実行されていることを示します。
デコンパイラーや他の類似ツールも、このトリックを使用して、対象のトランザクションを含むブロックのデータが利用可能な場合に命令の新しい意味を識別することができます。

:::message
このEIPはイーサリアムがPoSへ移行する際のランダムネスの取得方法を変更し、既存のスマートコントラクトが影響を受けないようにするための提案です。
これにより、スマートコントラクト開発者はPoSアップグレード後も問題なくランダムネスを利用できるようになります。
:::

## 仕様

イーサリアムのProof-of-Stake（PoS）への移行を支援するための変更に関連しています。
特に、ブロック構造、イーサリアム仮想マシン（EVM）の動作、および特定のフィールドとオペコードの名称変更について説明しています。

#### TRANSITION_BLOCKの定義
`TRANSITION_BLOCK`は、**EIP3675**で定義されているブロックで、イーサリアムがProof-of-Work（PoW）からPoSへの移行を行う際の特定のブロックを指します。

#### ブロック構造の変更
`TRANSITION_BLOCK`以降、クライアントソフトウェアはブロックヘッダーの13番目（0から数える）のフィールドである`mixHash`の値を、前のブロックのポストビーコン状態の最新のRANDAOミックスに設定しなければなりません。
これにより、ブロックヘッダーにランダムネスの情報が含まれるようになります。

#### EVMの変更
`TRANSITION_BLOCK`以降、`DIFFICULTY`（`0x44`）命令は`mixHash`フィールドの値を返さなければなりません。
これは、PoS移行後に`DIFFICULTY`命令が持つべき意味を変更するもので、ブロックの難易度ではなく、ランダムネスに関連した値を提供するようになります。
`DIFFICULTY`命令のガスコストは変わりません。

#### 名称の変更
`mixHash`フィールドは`prevRandao`に名称変更されるべきです。
これは、フィールドの内容がRANDAOの出力であることをより明確に反映します。
`DIFFICULTY`（`0x44`）オペコードは`PREVRANDAO`（`0x44`）に名称変更されるべきです。
これは、命令の新しい機能と目的をより適切に表すものです。

:::message
これらの変更はイーサリアムのPoSへの移行に伴い、ブロック構造とEVMの動作に影響を与え、特定のフィールドとオペコードの名称をランダムネス生成に関連するものに変更することを目的としています。
:::

## 補足

### ブロックヘッダにRANDAO出力を含める

イーサリアムのブロックヘッダーにRANDAO（乱数発生器）の出力を含めることの利点について説明しています。

#### EVMからのアクセスの容易さ
ブロックヘッダーにRANDAOの出力を含めることで、EVM（イーサリアム仮想マシン）内部から簡単にアクセスできるようになります。
EVMは既にブロックヘッダーのデータにアクセスできるため、これによりRANDAOの出力も直接利用可能になります。

#### 実行層の独立性の確保
RANDAOの出力をブロックヘッダーに含めることで、実行層（スマートコントラクトなどが動作するレイヤー）を、PoS（Proof-of-Stake：プルーフ・オブ・ステーク）コンセンサス層からの追加入力なしで完全に実行できるようになります。
つまり、ブロック単体で全ての情報が完結し、外部からのデータを必要としません。

#### ブロックハッシュの一意性への寄与
RANDAOのランダムネスをブロックヘッダーに混入させることで、他のフィールドの値が他のブロックのヘッダーと一致している場合でも、ブロックハッシュの一意性に寄与する可能性があります。
ブロックハッシュはブロックを識別するための重要な要素であり、その一意性はブロックチェーンのセキュリティを保つ上で重要です。

:::message
この提案はEVMがRANDAOのランダムネスをより簡単に、かつ効率的に使用できるようにすること、そしてイーサリアムのブロックが自己完結してセキュアであることを目指しています。
これは、イーサリアムがPoSへの移行を進める上での一つのステップです。
:::

### 難易度の代わりにmixHashフィールドを使用
PoSアップグレード後に隠れたフォーク選択バグ（forkchoice bugs）のクラスを避けるために、`difficulty`フィールドの代わりに`mixHash`ヘッダーフィールドが使用されます。
これは、クライアントソフトウェアがPoWフォーク選択ルールの基盤として`difficulty`値に大きく依存しているため、アップグレード時に`difficulty`フィールドを0に設定することで、アップグレード後に`total difficulty`値に関連するバグの発生リスクを減らすことが目的です。

### 既存フィールドの再利用
PoSアップグレードで`mixHash`フィールドは非推奨とされ、その後はゼロバイト配列に設定されます。
既存のフィールドをランダムネス出力の場所として再利用することで、ブロックあたり`32`バイトを節約し、アップグレードによって引き起こされるフィールドの非推奨化を効果的に取り除きます。

### DIFFICULTYオペコードの再利用
新しいオペコードを導入する代わりに`DIFFICULTY`オペコードを再利用する理由については、「**動機**」の章を参照してください。

### フィールドとオペコードの名称変更
フィールドとオペコードの名称は、意味論的に適切であるように変更されるべきです。

### TRANSITION_BLOCKの使用
このEIPで定義されたロジックの変更をトリガーするために`TRANSITION_BLOCK`を使用することで、このEIPは**EIP3675**によって定義されたPoSアップグレードと密接に結びついています。
これにより、ランダムネスのためのこのオペコードの使用に途切れがないことが保証されます。

#### PoSブロックを判断するための2**64の閾値の使用
RANDAO値が0から`2**64`の範囲内に落ちる確率は非常に低いため、PoW難易度値と混合される可能性はほとんどありません。
提案された閾値は、現在のイーサリアムメインネットの難易度値（約`2**54`）から十分な距離がないように見えるかもしれませんが、この閾値を不安定にするためのハッシュレートの千倍の増加は、次のコンセンサスアップグレード前に発生することは不可能と考えられています。

:::message
これらの技術的決定は、イーサリアムのPoSへの移行をスムーズかつ安全に行うために設計されています。
これにより、アップグレード後も既存のシステムとの互換性が保たれ、新しいランダムネスの要件が効率的に満たされます。
:::

## テスト

EIP（Ethereum Improvement Proposal）がイーサリアムの実行とEVM（イーサリアム仮想マシン）の状態遷移の検証に後方互換性のない変更を導入することについて説明しています。

#### 後方互換性のない変更
このEIPによって導入される変更は、既存のEVMの実行と状態遷移の検証に対して後方互換性がありません。
これは、このEIPが`TRANSITION_BLOCK`を利用し、**EIP3675**で導入されるPoS（Proof-of-Stake：プルーフ・オブ・ステーク）アップグレードと密接に結びついているためです。

#### EIP-3675との同時スケジュール
このEIPを採用する場合、**EIP3675**と同時にスケジュールされなければなりません。
これは、両方のEIPがイーサリアムのコンセンサスメカニズムをPoSに移行することに関連しているためです。

#### 影響を受けるアプリケーションのカテゴリ
変更の提案は、次のカテゴリのアプリケーションに対して後方互換性がありません。
`DIFFICULTY`オペコードによって返される値をPoW（Proof-of-Work：プルーフ・オブ・ワーク）の難易度パラメータとして使用するアプリケーション。
`DIFFICULTY`オペコードがフルの`256`ビットフィールドサイズに対して比較的小さい数を返すことを前提とするロジックに依存するアプリケーション。

#### 影響の範囲
最初のカテゴリのアプリケーションは、コンセンサスメカニズムをPoSに切り替えることで既に影響を受けており、この仕様によって追加の変更は導入されません。
二番目のカテゴリのアプリケーションは、`DIFFICULTY`オペコードの戻り値を使用する操作でオーバーフローまたはアンダーフローエラーを引き起こす可能性があるものです。
理論的には、このオペコードが返す可能性のある値の範囲の変更によってセキュリティの脆弱性が生じるアプリケーションを作成することが可能ですが、その可能性は無視できるほど小さいです。

:::message
このEIPはイーサリアムのPoSへの移行に関連する変更を導入し、特定のアプリケーションに影響を与える可能性がありますが、大多数のアプリケーションにとってのセキュリティリスクは非常に低いと考えられます。
:::

## テスト

イーサリアムのブロックとスマートコントラクトの動作に関するテストシナリオを説明しています。
特に、PoS（Proof-of-Stake）への移行を前後して、`DIFFICULTY`（0x44）オペコード（後に`PREVRANDAO`（0x44）に改名）の挙動を検証する方法について説明しています。

#### コントラクトのデプロイ
`TRANSITION_BLOCK`のより前のブロックの1つに、`DIFFICULTY`（`0x44`）オペコードの戻り値を状態に保存するスマートコントラクトをデプロイします。
これにより、PoS移行前の`DIFFICULTY`オペコードが返す値を記録できます。

#### `TRANSITION_BLOCK`の親ブロック内での検証
`TRANSITION_BLOCK`の親ブロック（つまり、移行直前のブロック）で実行されるトランザクション内で`DIFFICULTY`（`0x44`）オペコードを呼び出し、その戻り値がブロックの`difficulty`フィールドの値と等しいことを確認します。
この検証により、移行前の`DIFFICULTY`オペコードが正常に動作していることを保証します。

#### `TRANSITION_BLOCK`内での検証
`TRANSITION_BLOCK`内で実行されるトランザクションで`PREVRANDAO`（`0x44`）（以前の`DIFFICULTY`オペコード）を呼び出し、その戻り値がブロックの`prevRandao`フィールドの値と等しいことを確認します。
この検証により、PoS移行後に`PREVRANDAO`オペコードが新しい機能（ビーコンチェーンからのランダムネスの値を提供する）を正しく実行していることを保証します。

これらの手順は、イーサリアムのPoSへの移行に関連するオペコードの変更が正しく実装され、期待通りに動作することを確認するために重要です。
特に、ランダムネスのソースとして`DIFFICULTY`オペコードから`PREVRANDAO`オペコードへの移行がスムーズに行われることを検証することが目的です。

### バイアサビリティ

Proof-of-Stake（PoS）イーサリアムでの`PREVRANDAO`（`0x44`）オペコードが、Proof-of-Work（PoW）ネットワークの`BLOCKHASH`（`0x40`）や`DIFFICULTY`（`0x44`）オペコードとは異なる性質を持つランダムネスの源であることを説明しています。

#### ランダムネスの源
PoSイーサリアムでは、`PREVRANDAO`オペコードはビーコンチェーンのRANDAO実装に基づいてランダムネスを提供します。
RANDAO（Random Number Distributed Autonomous Organization）は、各参加者がシード値に貢献し、これらの値を組み合わせてブロックごとに新しいランダム値を生成するプロセスです。
これにより、分散型で予測不可能なランダムネスが得られます。

#### `BLOCKHASH`オペコード
PoWイーサリアムでは、`BLOCKHASH`オペコードは直近256ブロックのいずれかのブロックハッシュを提供します。
ブロックハッシュはブロックの内容から計算されるため、ある程度のランダムネスを提供しますが、ブロックの生成者（マイナー）による影響を受ける可能性があります。

#### `DIFFICULTY`オペコード
PoWイーサリアムでは、`DIFFICULTY`オペコードは現在のブロックの難易度を提供します。
これはマイニングの難易度を示す数値で、ネットワークのハッシュレートやブロック生成時間に応じて動的に調整されます。
この値もランダムネスの源として使用されることがありますが、ネットワークの状態に依存するため予測可能性が高まる可能性があります。

:::message
PoSイーサリアムの`PREVRANDAO`オペコードは、ビーコンチェーンのRANDAOプロセスによって生成される新しいタイプのランダムネスを提供します。
これは、マイナーによる潜在的な操作からより自由で、予測不可能なランダムネスを保証することを目的としています。
これにより、スマートコントラクトやdApps（分散型アプリケーション）がより安全で信頼性の高いランダムネスを利用できるようになります。
:::

### 予測可能性

ビーコンチェーンにおけるランダムネスの予測可能性について説明しています。
ビーコンチェーンは、イーサリアムのProof-of-Stake (PoS) コンセンサスメカニズムの一部として機能し、ランダムネスを生成するための重要な役割を担っています。

#### ランダムネスの予測可能性
過去のランダムネスは、分散型オラクルによって提供される場合でも100％予測可能です。
一方、将来明らかにされるランダムネスは限られた範囲でのみ予測可能です。

#### 未来のランダムネスに影響を与える要素
ビーコンチェーンにおける未来のランダムネスに影響を与える要素は以下の通りですが、これに限定されるわけではありません。

##### 蓄積されたランダムネス
エポックNの最後のスロットでビーコンチェーンによって生成されたRANDAOミックスは、エポック`N + MIN_SEED_LOOKAHEAD + 1`の各スロットでのブロック提案者を定義する関数の主要な入力です。
つまり、これは未来のRANDAOリビーラー（ランダムネスを明らかにする者）を定義する主要な要因です。

##### アクティブバリデータの数
エポック全体でのアクティブバリデータの数も、ブロック提案者関数に入力される別の要素です。

##### 有効バランス
他の条件が同じであれば、バリデータの有効バランスが低いほど、そのバリデータがスロットで提案者として指名される可能性は低くなります。

##### 偶発的な提案の見逃し
ネットワークの状況やその他の要因によって偶発的に提案が見逃されることは、RANDAOミックスに影響を与える高品質なエントロピー（ランダムネス）の源です。
メインネットでの見逃された提案の通常の割合は約1％です。

これらの入力は短いスロット範囲では予測可能で操作可能かもしれませんが、予測を試みる期間が長くなるほど、ビーコンチェーンによって蓄積されるエントロピーは増加します。
これにより、ビーコンチェーンが生成するランダムネスの信頼性が高まり、予測が困難になります。

### アプリケーション開発者のためのヒント

アプリケーション開発者が`PREVRANDAO`（`0x44`）によって返されるランダムネスの出力の予測可能性とバイアス可能性を減らすためのヒントを提供しています。

#### 未来のランダムネスに依存する
アプリケーションは、合理的に高い先読み（lookahead）を持つ未来のランダムネスに依存するようにするべきです。
例えば、アプリケーションはエポックKの終わりに入札を受け付けるのを停止し、スロット`K + N + ε`で生成されるRANDAOミックスを使用してサイコロを振ります。
ここで、Nはエポックでの先読みの範囲で、`ε`はエポック`N + 1`の数スロットです。

#### 先読みの結果
少なくとも4エポックの先読みは、次のような結果をもたらします。
- エポック`N + 1`の提案者セットは、エポックKの終わりにはまだ分かっていないため、入札者とサイコロを振る人の間の直接的なリンクが断ち切られます。
- アクティブなバリデータの数は、各エポックの終わりに更新され、次のエポックの提案者セットに影響を与え、アプリケーションがサイコロを振るために使用するRANDAOミックスに影響を与えます。
- メインネットの統計によると、この期間中にネットワークが提案を偶発的に見逃す確率は約100％であり、これによりサイコロを振るために使用されるRANDAOミックスの予測可能性が減少します。

#### εの設定
- `ε`を小さな数値（例えば、2や4スロット）に設定することで、第三者がサイコロを振るために使用される未来のランダムネスに影響力を持つ時間を少ししか与えません。
- この時間は`MIN_SEED_LOOKAHEAD`パラメータによって定義され、メインネットでは約6分です。

#### 入札とサイコロを振る行為の間の距離
入札とサイコロを振る行為の間に合理的に高い距離を設けることで、バリデータの一部を制御する入札者が直接的に影響力を利用する可能性を低くします
最終的に、この可能性はゲームの種類と制御されているバリデータの数に依存します。
たとえば、単一のバリデータが一度きりのゲームに影響を与える可能性は無視できますが、繰り返しゲームシナリオで複数のバリデータが存在する場合、その可能性は大きくなります。

:::message
これらのヒントはアプリケーションがランダムネスをより安全に利用し、潜在的な操作から保護するためのガイドラインを提供します。
:::

## 引用

Mikhail Kalinin (@mkalinin), Danny Ryan (@djrtwo), "EIP-4399: Supplant DIFFICULTY opcode with PREVRANDAO," Ethereum Improvement Proposals, no. 4399, October 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-4399.

## 最後に

今回は「PoSへの移行に伴い、`DIFFICULTY`オペコードの戻り値は意味を持たなくなり、代わりに`PREVRANDAOが`ランダムネスを渡す提案している**EIP4399**」についてまとめてきました！
いかがだったでしょうか？

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

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

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

https://chaldene.net/

https://zenn.dev/heku

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

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