[EIP2929] 特定のオペコードを使用する時のガスコストを増加させる提案を理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、トランザクション実行時に特定のオペコード（`SLOAD`、`CALL`系、`BALANCE`、`EXT`系、`SELFDESTRUCT`）を初めて使用する時のガスコストを増加させる提案をしている、**EIP2929**についてまとめていきます！

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

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

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

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

# 概要

Ethereumブロックチェーンでは、トランザクションを実行する時にさまざまなオペコードが使用されます。
オペコードとは、ブロックチェーンのスマートコントラクト内で行われる特定の操作を指示するためのコードです。
この提案では、`SLOAD`（ストレージからデータを読み込む操作）、`CALL`系統（他のコントラクトを呼び出す操作）、`BALANCE`（アドレスの残高を取得する操作）、`EXT`系統（外部コントラクトの情報を取得する操作）、`SELFDESTRUCT`（コントラクトを破棄する操作）に焦点を当てています。

通常、これらのオペコードを使用する時には、実行に必要なガス（トランザクションを処理するために必要な計算資源の量）が消費されます。
この提案では、これらのオペコードをトランザクション内で初めて使用する時のガスコストを増加させることで、ネットワークの過負荷を防ぎ、セキュリティを強化することを目指しています。
`SLOAD`は`2100`ガス、`CALL`系統、`BALANCE`、`EXT`系統は`2600`ガスに増加することが提案されています。

ただし、すでにプリコンパイルされている（Ethereumネットワークに組み込まれている特定の関数）アドレスや、同一トランザクション内で既にアクセスされたアドレスやストレージスロットは、これらの増加したガスコストの適用から除外され、代わりに減少したガスコストが適用されます。
これにより、無駄なガスの消費を防ぎつつ、必要な処理には柔軟に対応できるようになります。

さらに、`SSTORE`（ストレージにデータを保存する操作）と`SELFDESTRUCT`のガスメータリングも改革され、これらのオペコードによって隠れた形で行われていた「**ストレージロード**」（データの読み込み）が適切にガスコストに反映されるようになります。
これにより、スマートコントラクトの実行コストがより正確に計算され、ネットワークの効率性が向上します。

# 動機

イーサリアムのオペコードにおけるガスコストは、そのオペコードを処理するために必要な時間の見積もりとして機能します。
目的は、ブロックを処理するために必要な時間に対応する限界をガスリミットで設定することです。
しかし、ストレージにアクセスするオペコード（`SLOAD`や`*CALL`、`BALANCE`、`EXT*`オペコードなど）は、これまで低く設定されていました。
2016年の上海DoS攻撃では、最も深刻なクライアントバグが修正された後、攻撃者が大量のアカウントにアクセスまたは呼び出すトランザクションを送信するという戦略が効果的でした。

> Although by itself, this issue might seem benign, EXTCODESIZE forces the client to search the contract ondisk, resulting in IO heavy transactions. While replaying the Ethereum history on our hardware, the malicious transactions took around 20 to 80 seconds to execute, compared to a few milliseconds for the average transactions

> この問題は一見無害に見えるかもしれませんが、EXTCODESIZEはクライアントにディスク上のコントラクトを検索させ、結果としてIOが重いトランザクションを引き起こします。私たちのハードウェアでイーサリアムの履歴を再生している間、悪意のあるトランザクションを実行するのに約20秒から80秒かかりました。これは、平均的なトランザクションが数ミリ秒で実行されることと比較しています。

この問題に対処するためにガスコストは増加されましたが、最近のデータによると、十分な増加ではなかったことが示唆されています。
具体的には、`EXTCODESIZE`のようなオペコードは、クライアントにディスク上のコントラクトを検索させ、IOが重いトランザクションを引き起こします。
ある研究では、悪意のあるトランザクションを実行するのに`20`秒から`80`秒かかったのに対し、平均的なトランザクションでは数ミリ秒でした。

提案されているEIP（イーサリアム改善提案）では、これらのオペコードのコストを約3倍に増加させ、最悪のケースの処理時間を約`7`秒から`27`秒に減少させることを目指しています。
データベースのレイアウトを改善し、クライアントがマークルツリーを介さずに直接ストレージを読み込むように再設計することでさらに処理時間を短縮できますが、このような技術の完全な展開には長い時間がかかる可能性があり、技術が導入されたとしてもストレージへのアクセスに伴うIOのオーバーヘッドは依然として大きなものとなります。

このEIPの副次的な利点は、イーサリアムにおけるステートレス証明のサイズを受け入れられるものにするために必要な作業の大部分を実行することです。
バイナリトライに切り替えることを前提とすると、コードサイズを除く理論上の最大証明サイズは、現在の`BALANCE`ごとに`700`ガスで`12500000`ガスリミットを使用して約`14.3M`バイトから、このEIP後は約`3.85M`バイトに減少します。
コードアクセスの価格設定は、コードのマークル化が実装されたときに変更される可能性があります。

:::note info
このEIP（イーサリアム改善提案）には、イーサリアムのステートレス（状態を持たない）証明のサイズを小さくし、より扱いやすくするという副次的な利点があります。
ステートレス証明とは、イーサリアムのトランザクションが正当であることを証明するために必要なデータのことを指します。

現在のイーサリアムでは、`BALANCE`というオペコード（アカウントの残高を取得するための命令）を実行するのに`700`ガス（イーサリアムの計算リソースの単位）が必要です。
イーサリアムのブロックにはガスリミットがあり、これはブロック内で実行できる計算の量を制限します。
現在のガスリミットは`12500000`ガスです。

このEIPを適用する前は、バランスの確認などの操作が含まれるステートレス証明のサイズが理論上最大で約`14.3M`バイト（メガバイト）になる可能性があります。
これは、バイナリトライ（データを効率的に格納・検索するためのデータ構造）に切り替えることを前提にしています。

しかし、このEIPによって`BALANCE`オペコードのガスコストが増加すると、同じ量のガスリミットで実行できる`BALANCE`操作の数が減ります。
結果として、ステートレス証明のサイズが理論上約`3.85M`バイトに減少します。
これは、イーサリアムの効率性を大きく改善し、特にステートレスクライアント（状態をローカルに保存しないクライアント）のユーザー体験を向上させる可能性があります。

また、将来的にコードのマークル化（コードを効率的に検証するための技術）が実装された場合、コードアクセスのコストも見直される可能性があります。これは、イーサリアムのさらなる最適化と効率化につながるでしょう。
:::

将来的には、SNARK/STARK証明においても同様の利点があります。
Starkwareの最近のデータによると、消費者向けデスクトップで秒間`10000`のRescueハッシュを証明できるとされています。
マークルブランチごとに25ハッシュを仮定し、ステートアクセスが一杯のブロックを使用する場合、現在では証明の生成に約`44.64`秒かかりますが、このEIP後では約`12.5`秒に減少し、一般的なデスクトップコンピュータでどんな状況でも時間内に証明を生成できるようになります。
STARK証明の将来的な改善は、より高価で堅牢なハッシュ関数の使用や、証明時間のさらなる短縮に使用でき、これによりステートレスクライアントが依存する証明の遅延が減少し、ユーザー体験が向上します。

:::note info
SNARKやSTARKといった技術は、ブロックチェーン上でのトランザクションやスマートコントラクトの動作を証明するために使われる高度な暗号技術です。
これらの証明は、ブロックチェーンのセキュリティと効率を高めるのに役立ちます。

Starkwareは、この分野での先進的な研究と技術開発を行っている企業の一つです。
彼らのデータによると、一般的な消費者向けデスクトップコンピュータを使用して、秒間に`10000`個のRescueハッシュ（特定の暗号技術で使われる計算方法）を証明することが可能です。

マークルブランチとは、ブロックチェーンのデータ構造の一部で、特定の情報が正しいことを効率的に証明するために使われます。
ここでは、各マークルブランチが`25`ハッシュを含むと仮定しています。

このEIPが実装される前は、ステート（アカウント情報など）にアクセスするための証明を生成するのに約`44.64`秒かかっていました。
これは、ブロック内で多くのステートアクセスが必要な場合の計算です。
しかし、このEIPによってガスコストが調整されると、同じ作業を約`12.5`秒で完了できるようになります。
これは、証明生成に必要な計算量が減少するためです。

この改善により、一般的なデスクトップコンピュータでも、どんな状況下でも迅速に証明を生成できるようになり、イーサリアムの効率性と利便性が大幅に向上します。
これは、ブロックチェーンの処理速度を高め、ユーザー体験を改善することに貢献するでしょう。
:::

# 仕様

## パラメータ

トランザクション実行時にアクセスされるアドレスとストレージキーを追跡する新しいルールが導入されることについて述べています。

まず、このEIPが適用されるブロック番号（`FORK_BLOCK`）と、さまざまな操作に関連する新しいガスコストの値が設定されています。

| パラメータ                    | 値       |
|-------------------------|---------|
| FORK_BLOCK（フォークブロック） | `12244000` |
| COLD_SLOAD_COST（コールドSLOADコスト）       | `2100`    |
| COLD_ACCOUNT_ACCESS_COST（コールドアカウントアクセスコスト） | `2600`    |
| WARM_STORAGE_READ_COST（ウォームストレージ読み取りコスト）  | `100`     |

これらの変更は、ブロック番号が`FORK_BLOCK`以上の場合に適用されます。
トランザクション実行時には、`accessed_addresses`（アクセスされたアドレスのセット）と`accessed_storage_keys`（アクセスされたストレージキーのセット）を保持する必要があります。
これらのセットはトランザクション全体にわたって存在し、他のトランザクションスコープの構造（自己破壊リストやグローバル払い戻しカウンターなど）と同様に実装されます。
特に、スコープが`revert`（取り消し）された場合、アクセスリストはそのスコープに入る前の状態に戻ります。

トランザクション実行が開始されると、`accessed_storage_keys`は空で初期化され、`accessed_addresses`は以下を含むように初期化されます。

- トランザクションの送信者（`tx.sender`）
- トランザクションの受取人（`tx.to`）、またはコントラクト作成トランザクションの場合は作成されるアドレス
- すべてのプリコンパイル（あらかじめ定義された特定の関数やアドレス）

このルールの目的は、トランザクションが実行される時に、どのアドレスとストレージキーにアクセスされたかを明確に追跡することにより、効率性を高め、セキュリティを強化することです。

## ストレージの読み取りと変更

イーサリアムにおけるストレージ読み込みの変更について説明しています。
特定のオペコードを使ってアドレスにアクセスする時のガスコストの計算方法が変更される内容です。

- **COLD_ACCOUNT_ACCESS_COST**と**WARM_STORAGE_READ_COST**は、アドレスへのアクセスやストレージの読み込みに関連するガスコストです。
- アドレスが`EXTCODESIZE (0x3B)`、`EXTCODECOPY (0x3C)`、`EXTCODEHASH (0x3F)`、`BALANCE (0x31)`、`CALL (0xF1)`、`CALLCODE (0xF2)`、`DELEGATECALL (0xF4)`、`STATICCALL (0xFA)`のいずれかのオペコードの対象である場合、以下のようにガスコストが計算されます。

1. 対象のアドレスが`accessed_addresses`にまだ含まれていない場合、**COLD_ACCOUNT_ACCESS_COST**ガスを請求し、そのアドレスを`accessed_addresses`に追加します。
2. 既に`accessed_addresses`に含まれている場合は、**WARM_STORAGE_READ_COST**ガスを請求します。

- このガスコストは、オペコードが呼び出された時点で請求され、マップが更新されます。
- `CREATE`または`CREATE2`オペコードが呼び出されると、そのアドレスが未使用であるかどうかを確認する前に、即座に作成されるアドレスを`accessed_addresses`に追加しますが、`CREATE`と`CREATE2`のガスコストは変わりません。
- `SLOAD`については、(`address`, `storage_key`)ペア（ここでの`address`はストレージが読み取られているコントラクトのアドレス）がまだ`accessed_storage_keys`に含まれていない場合、**COLD_SLOAD_COST**ガスを請求し、そのペアを`accessed_storage_keys`に追加します。
- ペアが既に`accessed_storage_keys`に含まれている場合は、**WARM_STORAGE_READ_COST**ガスを請求します。

注意点として、`CALL`のようなオペコードでは、`100/2600`のコストが直ちに（このEIP以前に`700`が請求されていたのと同様に）適用され、`CALL`に入るための63/64の計算前に適用されます。

:::note info
イーサリアムでは、スマートコントラクトが他のコントラクトを呼び出す（`CALL`）時にガスコストが発生します。
このEIPの導入前は、`CALL`オペコードの実行に`700`ガスが必要でした。
しかし、このEIPによって導入される変更では、`CALL`のようなオペコードを使用する時に、即座に`100`ガスまたは`2600`ガスのいずれかが請求されます。
このコストは、オペコードの実行が完了する前、具体的には`CALL`の内部に入るために利用可能なガス量（通常は全体の63/64）を計算する前に適用されます。

ここでの`100/2600`という表記は、アドレスが既にアクセスされたもの（"warm"）である場合は`100`ガスが、まだアクセスされていない（"cold"）場合は`2600`ガスが適用されることを意味しています。
つまり、アドレスへのアクセスが初めてであれば高いコストが、既にアクセス済みであれば低いコストが適用されるということです。

この変更により、イーサリアムのネットワーク効率とセキュリティが向上し、特定のオペコードの使用におけるガスコストの計算方法がより精密になります。
また、この変更は、スマートコントラクトの開発者がコントラクトのガス消費をより詳細に理解し、最適化するのに役立ちます。
:::

また、このEIPの時点で「**cold account**」上での「**cold sload read/write**」を実行する方法はありません。
スロットを読み書きするためには、実行が既にアカウント内にある必要があるためです。
そのため、cold account上のcold storageの読み書きの振る舞いは、このEIPにおいて未定義です。
将来的に「**リモート読み書き**」を追加することを提案するEIPがあれば、その変更の価格設定の振る舞いを定義する必要があります。

:::note info
### Cold account
イーサリアムのコンテキストで、最近アクセスされていないアカウントを指します。
この概念は、特にガスコストの計算やネットワークのリソース使用に関連するイーサリアムの改善提案（EIP）で取り上げられます。

イーサリアムでは、トランザクションの実行に伴う計算リソースの使用量に応じてガスコストがかかります。
アクセスパターンに基づいて、アカウント（およびそれに関連するストレージ）には「**cold**」または「**warm**」という属性が与えられることがあります。

- **Cold Access**
    - アクセスされるアカウントまたはストレージが、トランザクションのコンテキスト（または最近のブロック）で以前にアクセスされていない場合、そのアクセスは「**cold**」と見なされます。
    - Cold accessは、データを読み込むために追加の作業（例えば、ディスクからのデータの読み込みなど）を要するため、より高いガスコストがかかります。
- **Warm Access**
    - 逆に、アカウントやストレージが最近アクセスされたり、トランザクションのコンテキストで既にアクセスされている場合、それは「**warm**」と見なされます。
    - Warm accessは比較的少ないリソースを消費するため、ガスコストが低くなります。

この区分は、イーサリアムネットワークの効率性とセキュリティを向上させることを目的としています。
Cold accessにより高いガスコストを課すことで、悪意のあるアクターが大量のデータを無差別にアクセスすることによるネットワークの過負荷やDoS攻撃（サービス妨害攻撃）を防ぐことができます。
同時に、**warm access**の低いコストは、効率的なスマートコントラクトの設計を促進します。
:::

## SSTOREの変更

イーサリアムのストレージ書き込み（`SSTORE`）操作に関する変更について説明しています。
`SSTORE`オペコードは、イーサリアムのスマートコントラクトが状態（ストレージ）を更新する時に使用されます。
この改善提案（EIP）により、`SSTORE`を呼び出す時のガスコストの計算方法が変更されます。

`SSTORE`を呼び出す時には、(`address`, `storage_key`)ペアが`accessed_storage_keys`に含まれているかどうかを確認します。
もし含まれていなければ、追加で**COLD_SLOAD_COST**ガスを請求し、そのペアを`accessed_storage_keys`に追加します。

また、**EIP2200**で定義されているパラメータも以下のように変更されます。

| パラメータ            | 旧値  | 新値                         |
|-------------------|-----|----------------------------|
| SLOAD_GAS         | 800 | = WARM_STORAGE_READ_COST    |
| SSTORE_RESET_GAS  | 5000| 5000 - COLD_SLOAD_COST      |

**EIP2200**で定義されている他のパラメータは変更されません。
`SLOAD_GAS`は**EIP2200**のいくつかの箇所で使用されています（例：`SSTORE_SET_GAS - SLOAD_GAS`）。
複合定義を使用している実装では、これらの定義も更新する必要があります。

これらの変更により、ストレージへのアクセスが最初のアクセスである場合（**cold**アクセスと呼ばれる）に追加のガスコストが発生し、既にアクセスされているキー（**warm**アクセスと呼ばれる）には低いガスコストが適用されるようになります。
これは、イーサリアムのネットワーク効率を高め、DoS攻撃に対する耐性を強化することを目的としています。

## SELFDESTRUCTの変更

`SELFDESTRUCT`はイーサリアムのスマートコントラクトが自身を破壊し、残余のETHを指定したアドレスに送るために使用されるオペコードです。
この変更により、`SELFDESTRUCT`を使用してETHを送る時のガスコストの計算方法に特定のルールが追加されます。

- もし`SELFDESTRUCT`によってETHが送られる受取人のアドレスが`accessed_addresses`に含まれていない場合（送られるETHの量がゼロであっても）、既存のガスコストに加えて追加の**COLD_ACCOUNT_ACCESS_COST**が請求されます。
- そして、そのETH受取人のアドレスを`accessed_addresses`セットに追加します。

ここで注目すべき点は、受取人のアドレスが既に「**warm**」（つまり、トランザクションのコンテキスト内で既にアクセスされている）である場合でも、`SELFDESTRUCT`は`WARM_STORAGE_READ_COST`を請求しないということです。
これは他の呼び出しオペコード（`CALL`や`SSTORE`など）とは異なる振る舞いです。

この決定の背景には、変更を最小限に抑えるという意図があります。
`SELFDESTRUCT`は既に`5,000`ガスのコストがかかり、一度以上呼び出された場合には何も操作を行わない（no-op）ため、受取人が「**warm**」である場合に追加コストを請求しないことで、その影響を軽減しています。
これにより、スマートコントラクトの開発者は`SELFDESTRUCT`を使用する時のコストをより予測しやすくなります。

# 補足

イーサリアムのガスコストに関する変更とその理由について説明しています。

## オペコードコスト vs 証明データのバイトごとの課金
ガスコストを証明データのサイズに反映させるための自然な代替手段は、証明データのバイトごとに課金することです。
しかし、これを実装するには時間がかかり、短期的なセキュリティ対策の目標を妨げる可能性があります。
この方法を忠実に追求すると、コントラクトコードに触れるトランザクションのガスコストが非常に高くなります。
なぜなら、`24,576`バイトのコントラクトコード全てに対して課金する必要があるからです。
これは開発者にとって受け入れがたいほどの負担になります。
コードのマークル化が始まってから、コードの個々のチャンクにアクセスするガスコストを適切に計算し始める方がよいでしょう。
短期的なDoS攻撃防止の観点からは、ディスクから`24kB`をアクセスするコストは`32`バイトをアクセスするコストと大差ないため、コードサイズについて心配する必要はありません。

## `accessed_addresses` / `accessed_storage_keys` セットの追加
既にアクセスされたアカウントとストレージスロットのセットは、キャッシュ可能なものに無駄にガス代を支払うことを避けるために追加されます（すべてのパフォーマンスの良い実装で既にキャッシュされています）。
また、自己呼び出しやプリコンパイルを呼び出すことが不必要に高価である現状を取り除き、一部のストレージキーを事前にフェッチすることにより、将来の実行が予想されるガス量で行えるようにする契約違反の緩和を可能にします。

## SSTOREのガスコスト変更
`SSTORE`の変更は、ランダムに選ばれたゼロのストレージスロットを「ポーク」し、`800`ガスのコストで`0`から`0`に変更するが、実質的にストレージロードを要求するDoS攻撃の可能性を避けるために必要です。
`SSTORE_RESET_GAS`の削減は、`SSTORE`の総コスト（現在は`COLD_SLOAD_COST`を支払う必要がある）を変更しないようにするためです。
さらに、`SLOAD`に続いて`SSTORE`を行うアプリケーション（例えば、`storage_variable += x`）は実際にはより安くなるでしょう！

:::note info
`SSTORE`オペコードに関するイーサリアムの変更点を説明しています。
`SSTORE`はスマートコントラクトのストレージを更新する時に使用されるオペコードです。
変更の目的は、DoS（サービス拒否）攻撃の可能性を減らすことにあります。

DoS攻撃者は、イーサリアムネットワークを過負荷にすることを目的として、コントラクトのストレージを無駄に読み書きすることがあります。
具体的には、攻撃者は`SSTORE`を使用して、値が`0`のストレージスロット（コントラクトの保存領域内の位置）をランダムに選び、それを再び`0`に設定することがあります。
この操作は表面上は何も変更しませんが（`0`から`0`への変更）、実際にはストレージの読み込みを強制し、ネットワークリソースを消費します。

このような攻撃は、非常に少ないガスコスト（この場合は`800`ガス）で大量のリソースを消費させることが可能で、ネットワークのパフォーマンスに悪影響を与える可能性があります。

変更により、もし`SSTORE`が`0`の値を持つストレージスロットを「**ポーク**」（変更しようと）する場合、そのストレージスロットが初めてアクセスされる（**cold**アクセスと見なされる）場合には、追加のガスコスト（`COLD_SLOAD_COST`）が発生します。
これにより、攻撃者がランダムにストレージスロットを無駄に操作するコストが増加し、DoS攻撃のインセンティブが減少します。

結果的に、この変更はイーサリアムネットワークのセキュリティを強化し、無駄なストレージアクセスによるリソースの浪費を防ぐことを目的としています。
:::

## SSTOREの会計変更を最小限に抑える
`SSTORE`のガスコストは、Wei Tangのオリジナルの新しいアプローチを使用し続けます。
これは、ストレージの変更の実際のコストを正しく計算するためです。
実際のコストは現在の値と最終値のみを考慮し、中間値は考慮しません。

## この提案の下で平均的なアプリケーションのガス消費はどのように増加しますか？
証明サイズからの粗い分析によると、平均的なブロックは証明サイズが約`1000kB`で、そのうち約`750kB`がマークル証明でありコードではありません。
マークルブランチあたりの保守的な`2000`バイトを仮定すると、これはブロックあたり約`375`アクセスを意味します（`SLOAD`はガス増加とバイト比率が似ているため、別途分析する必要はありません）。

:::note info
マークルブランチは、イーサリアムブロックチェーンのデータ構造の一部で、トランザクションやその他のデータの有効性を証明するために使用されます。

ここでは、マークルブランチ1つあたりのサイズが約`2000`バイト（これは保守的な推定です）と仮定しています。
この推定に基づくと、平均的なイーサリアムブロック内で約`375`回のアクセスがあることになります。
これは、ブロック全体の証明サイズが約`1000kB`であり、そのうち約`750kB`がマークル証明（コードではない部分）であるというデータから導き出されています。

`SLOAD`はスマートコントラクトのストレージからデータを読み込む時に使用されるオペコードです。
`SLOAD`の使用によるガス消費の増加と、マークルブランチのバイト数によるガス消費の増加の比率が似ているため、`SLOAD`については別途分析する必要がないとされています。
つまり、マークルブランチのアクセスに関するこの分析は、`SLOAD`オペコードの使用によるガス消費の増加にも大まかに当てはまると考えられます。

この情報は、イーサリアムブロックの処理におけるガス消費の平均的な増加を理解するのに役立ちます。
また、ブロックの証明サイズやトランザクションデータの構造がガス消費にどのように影響するかを把握するのにも有用です。
:::

Etherscanからのトランザクションとブロックあたりのデータによると、ブロックあたり約`160`トランザクションがあります。
これは、これらのアクセスの大部分がガスコストの増加から除外される`tx.sender`と`tx.to`であることを意味しますが、重複するアドレスのために`320`未満である可能性が高いです。

したがって、ブロックあたりの課金可能なアクセスは約`50`〜`375`であり、各アクセスは`1900`のガスコスト増加を被ります。
これはガスリミットを約`1`〜`6`%引き上げる必要があることを意味します。
ただし、この分析は、(i) 複数のトランザクションでアクセスされるアカウント/ストレージキーが証明では一度だけ現れるが、ガスコストの増加では二度現れる場合、(ii) 同一トランザクション内で複数回アクセスされるアカウント/ストレージキーがガスコストの減少につながる場合、といった点でさらに複雑になる可能性があります。

## Goerli分析
より正確な分析は、Martin Swendeによって行われたGoerliトランザクションのスキャンによって見つけることができます。
結論としては、平均的にガスコストは約`2.36%`増加します。ガスコストを削減する主な要因の一つは、多くのコントラクトが同じストレージスロットを非効率的に複数回読み込むことで、このEIPがいくつかのトランザクションに`10%`以上のガスコスト節約をもたらすことです。

# 互換性

このテキストは、イーサリアムのガスコストの増加が、固定ガスコストに依存するスマートコントラクトに潜在的な影響を与える可能性について言及しています。
イーサリアムでのトランザクション実行やスマートコントラクトの呼び出しにはガスが消費されますが、このガスコストはネットワークの負荷や改善提案（EIP）によって変動することがあります。

ガスコストの増加により、一部のスマートコントラクトは想定されていたよりも多くのガスを必要とするようになるかもしれません。
これにより、特に固定ガスコストを前提として設計されたコントラクトでは、機能しなくなる（「**ブレイク**」する）リスクがあります。
例えば、ある関数が常に一定量のガスを消費することを期待しているコントラクトがあるとします。
ガスコストが予期せず増加した場合、その関数の実行に必要なガスが不足し、トランザクションが失敗する可能性があります。

しかしながら、セキュリティに関する検討セクションでは、このようなリスクが低いと予想される理由や、必要に応じてこれらのリスクをさらに低減する方法についての議論が提供されています。
これには、開発者がコントラクトをより柔軟に設計し、固定ガスコストに依存しないようにする、あるいはイーサリアムの改善提案に適応するためのガイドラインが含まれるかもしれません。
全体として、この変更はイーサリアムネットワークのセキュリティと効率を向上させるためのものであり、潜在的なリスクは管理可能であると考えられています。

# テスト

イーサリアムのスマートコントラクトのガスコストに関連する変更をテストするために、理想的なテストケースのセットが提案されています。
これらのテストケースは、変更が実際のスマートコントラクトの動作にどのように影響するかを理解するのに役立ちます。

1. **SLOAD**
    - 同じストレージスロットを{1, 2, 3}回読み込む。
    - `SLOAD`は、スマートコントラクトのストレージからデータを読み込むために使用されるオペコードです。

2. **CALL**
    - 同じアドレスに{1, 2, 3}回コールする。
    - `CALL`は、他のコントラクトの関数を呼び出すために使用されるオペコードです。

3. **SLOADとCALLの組み合わせ**
    - サブコール内で`SLOAD`と`CALL`を実行し、`revert`（取り消し）した後、同じ（ストレージスロット・アドレス）に再度`SLOAD`と`CALL`を実行する。

4. **サブコールとSLOAD**
    - サブコールを行い、`SLOAD`を実行し、もう一度サブコールを行い、内側のサブコールを`revert`し、同じストレージスロットに対して再度`SLOAD`を実行する。

5. **SSTORE**
    - 同じストレージスロットに{1, 2, 3}回書き込む。
    - 元の値と設定される値の両方にゼロ/非ゼロのすべての組み合わせを使用する。
    - `SSTORE`は、スマートコントラクトのストレージにデータを書き込むために使用されるオペコードです。

6. **SSTORE後にSLOAD**
    - 同じストレージスロットに書き込んだ後、それを読み込む。

7. **OP_1とOP_2**
    - 同じアドレスに対して`OP_1`と`OP_2`を実行する。
    - ここで`OP_1`と`OP_2`は、(*CALL, EXT*, SELFDESTRUCT)のすべての組み合わせです。

8. **CALLの失敗モード**
    - アドレスに`CALL`を試みるが、すべての可能な失敗モード（十分なガスがない、十分なETHがないなど）で失敗し、その後そのアドレスに対して成功するために（`CALL`、`EXT*`）を再度実行する。

これらのテストケースは、新しいガスコストの変更がさまざまな条件下でスマートコントラクトにどのように影響するかを評価するために設計されています。
これにより、開発者は変更がコントラクトの動作や効率に与える影響を理解し、必要に応じて調整を行うことができます。

# セキュリティ

イーサリアムのガスコストを増加させる改善提案（EIP）がアプリケーションに与える可能性のある影響について説明しています。
ガスコストが増加すると、一部のアプリケーションやスマートコントラクトが正常に機能しなくなるリスクがあります
具体的には、次の3つのケースが考えられます。

### コントラクト内のサブコールに固定ガスリミットを設定している場合
スマートコントラクトが他のコントラクトを呼び出す時に、呼び出し先に割り当てるガス量を固定値で設定している場合、ガスコストの増加によってその量が不足し、コールが失敗する可能性があります。

### 全ガスリミットをほぼ使用するコントラクトコールに依存しているアプリケーション
トランザクションがブロックのガスリミットに非常に近い量のガスを消費するように設計されたアプリケーションは、ガスコストの増加によってトランザクションが完了できなくなる可能性があります。

### ETHを転送するコールによって受信者に与えられる2300のベースリミット
ETHを送る時にコントラクトが受け取る最小限のガス量（`2300`ガス）がある場合、これらのガスだけで実行できる操作が限られており、ガスコストの増加によってさらに制約が増える可能性があります。

これらのリスクは、以前のガスコスト増加のEIP、特に**EIP1884**の文脈で既に検討されています。
Martin SwendeとHubert Ritzdorfによる分析は、上記の(1)と(3)に焦点を当てています。
一方で、(2)に関してはそれほど詳細な分析は行われていませんが、トランザクションで利用可能なガスリミットのほとんどを使用するアプリケーションは非常に稀であり、また最近ガスリミットが1000万から1250万に増加したことから、このリスクは非常に低いと主張できます。
実際、**EIP1884**は一部のコントラクトがこの理由で機能しなくなるという小さな数のケースを引き起こしました。

これらのリスクを考慮するにあたり、2つの視点があります。
まず、開発者は長年にわたって警告を受けてきたという点です。
ストレージアクセスオペコードのガスコスト増加については長い間議論されており、このような変更の可能性について主要なdapp開発者を含む多くの声明がなされてきました。
**EIP1884**自体が重要な警鐘となりました。したがって、今回のリスクは**EIP1884**よりも大幅に低いと主張できます。

## コントラクト破棄の緩和

ガスコストの増加によって発生する潜在的なコントラクトの破損を軽減する方法についての説明です。
具体的には、次のような対策が提案されています。

### `accessed_addresses` と `accessed_storage_keys` マップの活用
このEIPには、`accessed_addresses`と`accessed_storage_keys`のマップが導入されています（**EIP1884**にはない）。
これにより、コントラクトAが別のアドレスBに資金を送る必要がある場合など、一部の状況を回復可能にします。
Bが任意のソースからの資金を受け入れ、ストレージ依存のログを残す場合、まずBに別のコールを送ってキャッシュに入れ、その後Aを呼び出すことで回復できます。
これにより、AによってトリガーされたBの実行が`SLOAD`あたり`100`ガスのみを請求することになります。
この方法はすべての状況を修正するわけではありませんが、リスクを大幅に減少させることができます。

:::note info
`accessed_addresses` と `accessed_storage_keys` という新しいマップの導入による、ガスコストの増加に関するEIPの一部の機能について説明しています。
これらのマップは、特定のEIPによって導入され、イーサリアムのスマートコントラクトが実行中にアクセスするアドレスとストレージキーを追跡します。
**EIP1884**ではこの機能が欠けていました。

この新しい機能の主な目的は、ガスコストの増加によって引き起こされる潜在的な問題を軽減することです。
例えば、コントラクトAが他のアドレスBに資金を送る必要がある場合、Bがその資金を受け入れてストレージ依存のログを残す場合、まずBに対して別のコールを送信してキャッシュに取り込むことができます。
これにより、Bがキャッシュに存在するときにAからトリガーされる実行は、`SLOAD`操作ごとにわずか`100`ガスしか請求されなくなります。

このアプローチは、アドレスやストレージスロットに対する最初のアクセスが「**cold**」アクセスと見なされ、より高いガスコストがかかるのに対し、一度アクセスされた後のアクセスは「**warm**」アクセスと見なされ、より低いガスコストで済むという考え方に基づいています。
この方法はすべての問題を解決するわけではありませんが、多くの場合でリスクを軽減し、ガスコストの増加による潜在的なコントラクトの破損を防ぐのに役立ちます。
:::

### `POKE` プリコンパイルの追加
アドレスとストレージキーを入力として取り、トランザクションがアクセスするすべてのストレージスロットを事前に「**ポーク（プリフェッチ）**」することで「**スタックした**」コントラクトを「**救出**」しようとするトランザクションを可能にします。
これは、アドレスがコントラクトからのトランザクションのみを受け入れる場合でも機能し、現在のガスリミットで多くのコンテキストで機能します。
この方法が機能しない唯一のケースは、外部所有アカウント（EOA）から特定のコントラクトに直接トランザクションコールが行われ、そのコントラクトが別のコントラクトにサブコールする場合です。

:::note info
**ポーク（プリフェッチ）の定義**
あらかじめアドレスとストレージキーを指定して、トランザクションがアクセスする予定のストレージスロットにあらかじめアクセス（プリフェッチ）することです。
これにより、実際のトランザクション実行時には、これらのストレージスロットが「**warm**」状態になり、アクセスコストが下がります。

**「スタックした」コントラクトの救出**
ガスコストの増加によって動作が停止してしまった、または正常に機能しなくなったコントラクトを、ポーク操作によって「**救出**」します。
ポーク操作によって、コントラクトが必要とするストレージアクセスのコストを下げ、コントラクトが再び正常に機能するようにすることができます。

**適用可能なシナリオ**
この方法は、特にアドレスがコントラクトからのトランザクションのみを受け入れる場合など、多くの場合に有効です。
現在のガスリミットの範囲内で、多くのコンテキストでこの方法を使用できます。

**機能しないケース**
外部所有アカウント（EOA）から特定のコントラクトに直接トランザクションコールが行われ、そのコントラクトがさらに別のコントラクトにサブコールを行うような場合には、このポーク方法は機能しません。
これは、EOAからの直接コールが特定のコントラクトの動作を直接トリガーするため、事前にポークすることができないためです。

このアプローチは、ガスコストの増加による影響を軽減し、スマートコントラクトの開発者がコントラクトを安定して動作させるための戦略として考えることができます。
:::

### EIP-2930の利用
**EIP2930**は`POKE`と似た効果を持ちますが、より一般的です。
EOA -> コントラクト -> コントラクトのケースにも対応し、ガスコストの増加による既知のすべての破損ケースに対応するはずです。
このオプションはより複雑ですが、アクセスリストを他のユースケース（リジェネシス、アカウント抽象化、SSAなど）で使用するためのステップとして考えられます。

:::note info
**EIP2930**はイーサリアムの改善提案の一つで、トランザクションに「**アクセスリスト**」という新しい概念を導入します。
このアクセスリストには、トランザクション実行中にアクセスされるアドレスとそれらのアドレスのストレージキーが含まれます。
**EIP2930**の目的は、ガスコストの増加によって発生する可能性のある問題を軽減し、トランザクションの実行効率を向上させることです。

### EIP-2930の特徴と利点

**一般性**
**EIP2930**は`POKE`と似た効果を持ちますが、より一般的な解決策を提供します。
トランザクションが直接または間接的にアクセスするアドレスとストレージキーを事前に宣言することで、それらのアクセスが「**warm**」と見なされ、ガスコストが削減されます。

**広範な対応**
この提案は、外部所有アカウント（EOA）からコントラクトを経由して別のコントラクトにアクセスする場合など、さまざまなケースに対応しています。
これにより、ガスコストの増加によるほとんどの既知の問題を解決することが期待されます。

**複雑性と将来性**
**EIP2930**は`POKE`よりも複雑な解決策ですが、アクセスリストを使用することで、より多くのユースケースに対応する可能性があります。
例えば、ブロックチェーンの状態を最適化する「**リジェネシス**」、ユーザーの操作を簡素化する「**アカウント抽象化**」、よりセキュアなスマートコントラクトの実行を可能にする「**SSA（Stateless Smart Contracts）**」など、将来的なイーサリアムの改善に役立つ可能性があります。

### まとめ

**EIP2930**は、イーサリアムのトランザクションにアクセスリストを導入することで、ガスコストの増加に伴う問題を軽減し、トランザクションの実行効率を向上させる提案です。
その一般性と広範な対応能力により、イーサリアムの将来的な改善と発展に貢献する可能性があります。
:::

これらの対策は、スマートコントラクトの開発者がガスコストの増加による潜在的な問題に対処し、コントラクトの機能性を維持するための方法を提供します。

# 引用

Vitalik Buterin (@vbuterin), Martin Swende (@holiman), "EIP-2929: Gas cost increases for state access opcodes," Ethereum Improvement Proposals, no. 2929, September 2020. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-2929.

# 最後に

今回は「トランザクション実行時に特定のオペコード（`SLOAD`、`CALL`系、`BALANCE`、`EXT`系、`SELFDESTRUCT`）を初めて使用する時のガスコストを増加させる提案をしている、**EIP2929**」についてまとめてきました！
いかがだったでしょうか？

質問などがある方は以下の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