[EIP150] オペコードのガスコストを増加させる提案を理解しよう！

# はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、オペコードのガスコストを増加して攻撃のハードルを上げる仕組みを提案している**EIP150**についてまとめていきます！

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

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

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

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

# パラメータ

| **FORK_BLKNUM** | **CHAIN_ID** | **CHAIN_NAME** |
| :-------------: | :----------: | :------------: |
| `2,463,000` | `1` | `Main net`

# 仕様

イーサリアムのようなブロックチェーンネットワークでのトランザクション処理に関わる変更点について説明しています。
これらの変更は、特定のブロック番号（`FORK_BLKNUM`）を超えた後に適用されることが想定されています。

- `EXTCODESIZE`（コントラクトのコードサイズを取得する）のガスコストを`20`から`700`に増加。
- `EXTCODECOPY`（コントラクトのコードをコピーする）の基本ガスコストを`20`から`700`に増加。
- `BALANCE`（アカウントの残高を取得する）のガスコストを`20`から`400`に増加。
- `SLOAD`（ストレージからデータを読み出す）のガスコストを`50`から`200`に増加。
- `CALL`、`DELEGATECALL`、`CALLCODE`（他のコントラクトを呼び出す）のガスコストを`40`から`700`に増加。

:::note info
`EXTCODESIZE`、`EXTCODECOPY`、`BALANCE`、`SLOAD`、`CALL`系のオペレーションに対するガスコストの増加は、これらのオペレーションがネットワークに与える負荷をより適切に反映するためのものです。
これにより、ネットワークの過負荷を防ぎ、セキュリティを向上させることが目的です。
:::

- `SELFDESTRUCT`（コントラクトを破棄する）のガスコストを`0`から`5000`に増加。
    - さらに、新しく作成されたアカウントに対して`SELFDESTRUCT`を実行する場合、追加で`25000`のガスコストがかかる。

:::note info
`SELFDESTRUCT`のガスコストを導入することで、コントラクトの破棄が軽率に行われることを防ぎ、ネットワークの整合性を保つことを意図しています。
:::

- 推奨されるガスリミット（トランザクションで使用できる最大ガス量）を`550`万に増加。

:::note info
ガスリミットを550万に増加させることで、ネットワークの処理能力を高め、より多くのトランザクションを同時に処理できるようにすることが目指されています。
:::

- $N - floor(N / 64)$ を定義し、これを使って、特定のガス量を要求するコールが許容される最大量を超えた場合の処理方法を変更。
    - 具体的には、要求されたガス量が最大許容量の「**64分の63**」を超える場合、その量までガスを割り当てる。
- `CREATE`（新しいコントラクトを作成する）は、親のガスから「**64分の63**」を子コールに提供する。

:::note info
「**64分の63**」の定義は、特定のガス要求に対して、実際に必要な量をより適切に割り当てるためのものです。
これにより、過剰なガス消費を防ぎ、効率的なネットワーク運用を支援します。
:::


以下のコードは、ブロックチェーン（特にイーサリアムのようなスマートコントラクトプラットフォーム）におけるガス計算の一部を示しています
このコードの主な機能は、トランザクションやコントラクトの実行におけるガス消費を計算して処理することです。

```python
extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \
    (value > 0) * opcodes.GCALLVALUETRANSFER
if compustate.gas < gas + extra_gas:
    return vm_exception('OUT OF GAS', needed=gas+extra_gas)
submsg_gas = gas + opcodes.GSTIPEND * (value > 0)
```

- `extra_gas`
    - これは追加のガスコストを計算するための変数です。
    - 計算は二つの条件に基づいています。
    - `(not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT`
        - この部分は、指定されたアカウント（`to`）が存在しない場合、新しいアカウントを作成するための追加ガスコスト（`opcodes.GCALLNEWACCOUNT`）を計算します。
    - `(value > 0) * opcodes.GCALLVALUETRANSFER`
        - この部分は、トランザクションに`value`（Etherの送金など）が含まれる場合、その送金に必要な追加ガスコスト（`opcodes.GCALLVALUETRANSFER`）を計算します。

- `if compustate.gas < gas + extra_gas`
    - この条件文は、現在のコンピューテーションステート（`compustate`）における利用可能なガスが、必要なガス（`gas`）と追加ガス（`extra_gas`）の合計より少ない場合にチェックします。
    - もし足りなければ、ガス不足（**OUT OF GAS**）の例外を発生させます。

- `submsg_gas = gas + opcodes.GSTIPEND * (value > 0)`
    - この行は、サブメッセージ（別のコントラクトを呼び出す時など）のためのガス量を計算します。
    - `value`（Etherの送金など）がある場合、`opcodes.GSTIPEND`（固定のガス量）が追加されます。

以下のコードは、ブロックチェーン（特にイーサリアムのスマートコントラクト）におけるガス消費の計算と管理に関するものです。
このコードは、トランザクションやコントラクトの実行に必要なガス量を計算し、適切に管理するためのロジックを含んでいます。

```python
def max_call_gas(gas):
    return gas - (gas // 64)

extra_gas = (not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT + \
    (value > 0) * opcodes.GCALLVALUETRANSFER
if compustate.gas < extra_gas:
    return vm_exception('OUT OF GAS', needed=extra_gas)
if compustate.gas < gas + extra_gas:
    gas = min(gas, max_call_gas(compustate.gas - extra_gas))
submsg_gas = gas + opcodes.GSTIPEND * (value > 0)
```

- `max_call_gas(gas)`
    - この関数は、与えられたガス量からその64分の1を引いた値を返します。
    - これは、呼び出しに使用できる最大ガス量を計算するために使われます。

- `extra_gas`の計算
    - `(not ext.account_exists(to)) * opcodes.GCALLNEWACCOUNT`
        - 対象アカウントが存在しない場合に新しいアカウントを作成するための追加ガスコストを計算します。
    - `(value > 0) * opcodes.GCALLVALUETRANSFER`
        - トランザクションに`value`（Etherなど）が含まれている場合の追加ガスコストを計算します。

- `if compustate.gas < extra_gas`
    - 利用可能なガスが`extra_gas`より少ない場合、ガス不足（**OUT OF GAS**）の例外を発生させます。

- `if compustate.gas < gas + extra_gas`
    - 利用可能なガスが必要なガス（`gas`）と追加ガス（`extra_gas`）の合計より少ない場合、`gas`の量を最大許容量（`max_call_gas`を使用）に調整します。

- `submsg_gas = gas + opcodes.GSTIPEND * (value > 0)`
    - サブメッセージ（他のコントラクト呼び出し）のためのガス量を計算します。
    - `value`（Etherの送金など）がある場合、追加のガス（`opcodes.GSTIPEND`）が加算されます。

これらのコードの目的は、スマートコントラクトの実行中に適切なガス消費を保証し、ガス不足による例外状況を適切に処理することです。
これにより、ネットワークの安全性と効率性が向上します。

# 補足

このEIPは、イーサリアムネットワークにおけるガスコストの見直しと調整に焦点を当てています。
DoS攻撃により、状態ツリーを読み込むオペコードが他のオペコードと比較して低く評価されていることが明らかになりました。
これらのオペコードは、ネットワークに大きな負荷をかけるため、攻撃者がネットワークのパフォーマンスを低下させるために利用しやすい手段となっています。

特に問題となっているのは、ディスクからのデータ読み出しに時間がかかることと、これが将来のシャーディング技術に影響を与える可能性があることです。
シャーディングはブロックチェーンのスケーラビリティを向上させるための技術で、データの分割と並列処理を行いますが、大量のデータを要求するトランザクションが発生すると、このプロセスが複雑化し、効率が低下します。

このEIPでは、ストレージ読み込みに関連するオペコードのガスコストを増加させることで、この問題に対処しようとしています。
ガスコストの計算は、以前に使用された計算表を基にアップデートされており、ブロック処理に必要なデータ読み込み量を`8`MBに制限することを目指しています。
さらに、コードロードのコストを考慮して、一律`300`ガスの追加ペナルティが設定されています。

**EIP90**と**EIP114**は、コントラクトの呼び出しコストを高くし、より予測しにくくすることでガスベースの制限を導入し、コールスタックの深さの攻撃を防ぐことを目指しています。
これにより、コントラクト開発者はコールスタックの深さの攻撃に対する懸念を減らし、コントラクトの安全性を高めることができます。

最後に、ガスリミットの増加は、これらの変更によって影響を受ける可能性のあるネットワークのトランザクション処理能力を維持するために提案されています。
これは、ネットワークの効率とスケーラビリティを保つための重要なステップです。

# 参考

- [EIP-90](https://github.com/ethereum/EIPs/issues/90)
- [EIP-114](https://github.com/ethereum/EIPs/issues/114)

# 引用

Vitalik Buterin (@vbuterin), "EIP-150: Gas cost changes for IO-heavy operations," Ethereum Improvement Proposals, no. 150, September 2016. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-150.

# 最後に

今回は「オペコードのガスコストを増加して攻撃のハードルを上げる仕組みを提案している**EIP150**」についてまとめてきました！
いかがだったでしょうか？

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