# [EIP214] コントラクト呼び出し時に状態の変更を禁止するSTATICCALLの仕組みを理解しよう！

> この提案では、スマートコントラクトの安全性を高めるために新しいオペコードを導入することが提案されています。

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

## はじめに

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

https://cryptogames.co.jp/

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

https://cryptospells.jp/

今回は、スマートコントラクトが呼び出し中に状態変更を行うことを禁止する、新しいオペコードである `STATICCALL` を提案している**EIP214**についてまとめていきます！

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

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

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

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

この記事ではオペコードがいくつか出てくるので、各オペコードについて気になった方は以下の記事を参考にしてください。

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

## 概要

この提案では、スマートコントラクトの安全性を高めるために新しいオペコードを導入することが提案されています。
この新オペコードは、他のコントラクトやコントラクト内の機能を呼び出す時に、そのプロセス全体で状態（コントラクトの保持しているデータや資産など）を変更することを禁止します。
つまり、このオペコードを使用して呼び出されたコントラクトやそのサブコール（別のコントラクトを呼び出すこと）は、読み取り専用となり、状態を変更する試みがあった場合、通常その変更が実行される代わりにエラーが発生し処理が停止されます。
これにより、意図しない状態の変更を防ぎ、スマートコントラクトのセキュリティを向上させることができます。

## 動機

現在のスマートコントラクトのシステムでは、呼び出されたコントラクトがどのような操作を行うかについての制限はほとんどありません。
この開放性は柔軟性を提供しますが、同時にセキュリティ上の懸念も生じます。
特に、呼び出し元のコントラクトは、呼び出されたコントラクトがどのような変更を加えるかを事前に知ることができないため、予期しない状態の変更につながる可能性があります。

この問題に対処するために提案されているEIPは、コントラクト間の呼び出しを行う時に、呼び出されたコントラクトが実行できる操作を厳しく制限する新しい方法を導入します。
この提案により、呼び出しを行った時に、コントラクトの状態が読み取り専用になり、状態を変更することができなくなります。
これにより、スマートコントラクトの開発者は、コントラクトの呼び出し後も全てのアカウントの状態が変わらないことを確信することができ、セキュリティの向上につながります。
このシンプルなアプローチは、コントラクト間の相互作用をより予測可能で信頼性の高いものにすることを目的としています。

## 仕様

この提案では、イーサリアムの仮想マシンに「`STATIC`」フラグという新しい概念を導入しています。
このフラグはデフォルトで「`false`」として設定されており、サブコール（他のコントラクトを呼び出す時の処理）で自動的に引き継がれます。
ただし、新しいオペコード「`0xfa`」、すなわち「`STATICCALL`」を使用する場合に限りこの挙動は例外となります。

「`STATICCALL`」オペコードは、通常の「`CALL`」オペコードと似ていますが、いくつかの違いがあります。
最も顕著な違いは、送金額を示す「`value`」引数が取り除かれていることで、`STATICCALL`では`0`として扱われます。
また、このオペコードを使用して呼び出されたコントラクト（子コントラクト）は、「`STATIC`」フラグが「`true`」に設定された状態で実行されます。
これにより、そのコントラクトは状態を変更する操作を行うことができなくなり、読み取り専用のコールが可能になります。
コールが完了すると、「`STATIC`」フラグは元の「`false`」にリセットされます。

`STATIC`フラグが`true`に設定されている間に状態を変更しようとする操作（例：スマートコントラクトの作成: `CREATE`、`CREATE2`、ログの生成: `LOG0`、`LOG1`、`LOG2`、`LOG3`、`LOG4`、ストレージの更新: `SSTORE`、自己破壊: `SELFDESTRUCT`）は、実行される代わりに例外を発生させます。
これにより、コントラクトのセキュリティが強化され、予期しない状態の変更を防ぐことができます。
ただし、「`CALLCODE`」は、他のコントラクトのコードを現在のコントラクトのコンテキストで実行する特殊なケースであり、非ゼロの値を伴っても状態変更操作とは見なされません。

## 補足

この仕組みを取り入れることで、コントラクトが状態変更を伴わない呼び出しを明確に実行できるようになります。
れは開発者やコードレビュアーに対し、特定のコールがリエントランシーバグ（re-entrancy bugs）やその他のセキュリティ関連の問題を引き起こすことがないという確信を与えます。
リエントランシーバグは、外部のコントラクトが予期しない方法で現在のコントラクトに再び入り込むことを可能にするセキュリティ上の脆弱性です。
しかし、この機能により、コントラクトのコールは純粋な関数のように振る舞い、ただ単に出力を返すだけで、コントラクトの状態に何の変更も加えません。

このアプローチは、純粋に機能的なプログラミングを採用している高級言語（HLL）の実装を容易にする可能性があります。
純粋機能的言語は副作用を排除し、関数の出力がその入力のみに依存することを保証することに重点を置いています。
これにより、コードの予測可能性と安全性が向上し、スマートコントラクトの開発においても同様の利点が得られることが期待されます。

:::message
リエントランシー攻撃については以下の記事を参考にしてください。
:::

https://chaldene.net/solidity-reentrancy-attack

## 互換性

この提案により導入される新しいオペコードは、イーサリアムの仮想マシン（EVM）に新たな機能を追加するものです。
しかし、この変更は既存のオペコードの動作には影響を与えません。
これは、新しいオペコードを採用していない古いコントラクトや、この新しいオペコードを使用して呼び出されない古いコントラクトが、変更後も従来通りに動作することを意味します。
このような設計により、システムの全体的な互換性を保ちながら新機能を導入することができます。
これにより、新旧のコントラクトが同じプラットフォーム上で共存し、新しいオペコードを利用したい開発者だけがそれを使用することができ、他の開発者は自分のコントラクトに影響を与えることなく従来の方法を続けることができます。

## 引用

Vitalik Buterin <vitalik@ethereum.org>, Christian Reitwiessner <chris@ethereum.org>, "EIP-214: New opcode STATICCALL," Ethereum Improvement Proposals, no. 214, February 2017. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-214.

## 最後に

今回は「スマートコントラクトが呼び出し中に状態変更を行うことを禁止する、新しいオペコードである `STATICCALL` を提案している**EIP214**」についてまとめてきました！
いかがだったでしょうか？

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