はじめに

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

今回は、Ethereumのストレージ書き込み命令(SSTORE)が2300ガス以下では実行できないようにすることで、古いスマートコントラクトの再入可能性リスクを防ぐ仕組みを提案しているEIP1706についてまとめていきます!

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

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

概要

EIP1706は、すでに稼働している多くのスマートコントラクトに影響を与えるEthereumネットワークの仕様変更に対して、安全性を維持するための対策を目的としています。 EIP1283では、ストレージに値を書き込む際のガスコストが大幅に削減されました。 これ自体はガス効率の改善として有益ですが、その一方で、すでにデプロイされている多くのコントラクトに対して新たなセキュリティリスク、特に「再入可能性(reentrancy)」攻撃の可能性を生じさせるという重大な懸念が発生しました。

EIP1283については以下の記事を参考にしてください。

EIP1706は、既存のコントラクトがEIP1283による変更の影響を受けたとしても、以前と同様のセキュリティ特性を保持できるようにし、過去の設計に基づく安全性の前提条件(assumptions)を維持することを目的としています。 これにより、すでに広く利用されているコントラクトコードの大規模な修正や再検証が不要となります。

動機

EIP1283は、SSTORE命令によるストレージ書き込みのガスコストを動的に計算する新しいスキームを導入し、実際のストレージのステート変化に応じて柔軟なガス課金が可能となりました。 これにより、多くのコントラクトにおいてトランザクションのガス代が削減されるという利点があります。

しかし、Ethereumにおいて最も基本的な安全設計の1つは「2300ガスのstipend(付与量)」です。 これは、Solidityのtransfer()やsend()といった関数で呼び出される外部コールに対して、自動的に割り当てられる非常に限られたガス量であり、再入可能性攻撃を防止する1つの仕組みとして機能しています。

ところが、EIP1283のガスコスト削減により、たとえ2300ガスしか与えられていない状況であっても、ストレージへの書き込みが実行可能になってしまいました。 これは、従来では安全だと考えられていたコントラクトが、想定外の挙動を引き起こす余地を生み出すということを意味します。

この脆弱性は、実際にEthereumコミュニティでも問題視され、Redditの投稿でも警告が発せられました。 特に、既存のコントラクトに互換性を持たせたまま、安全性を確保するには低ガス状態でのSSTOREを許可しないというルールを追加することが有効とされました。

EIP1706は、そのようなリスクに対処しつつ、Ethereumのアップグレードによって既存のコントラクトが破壊されないようにするための、現実的かつ安全な対応策を示しています。 結果として、Ethereumネットワーク全体のセキュリティ基準を維持し、信頼性を損なうことなく仕様の進化を図ることができます。

仕様

EIP1706では、EVMのSSTORE命令に対して新たな制限条件を追加することで、セキュリティ強化を図ります。 具体的には、EVMがSSTORE命令を実行する際に、残りのガス(gasleft)が2300ガス以下であった場合、その操作を許可せず、「ガス不足(out of gas)」として即座に現在のコールフレームを失敗させるという提案です。

この仕様変更により、低ガスステートでのストレージ書き込みが抑制されます。 これは、Solidityが外部へのETH送金(transferやsend)時に2300ガスを制限付きで送る仕様と密接に関係しており、悪意のあるコントラクトが受け取り側としてその2300ガスを悪用し、再入可能性攻撃を仕掛けるリスクを封じることができます。

Ethereumでは、コントラクトが外部アドレスにETHを送金する際、通常はセキュリティ確保のため、送金先に渡されるガスを最大2300に制限します。 これは「stipend(付与ガス)」と呼ばれ、相手コントラクトのコード実行を最小限に抑えるための重要な制御です。 例えば、ログ記録やイベント発行などの軽微な処理のみを許容し、意図しない外部呼び出しやステート変更を防ぐ効果があります。

しかし、EIP1283によって導入された動的ガス課金方式では、SSTORE命令の実行コストが状況によって大きく下がる場合があり、理論上は2300ガス以下でもストレージ書き込みが可能になることがあります。 これが新たな脆弱性を生み出す原因となりました。

EIP1706による修正では、SSTORE命令の直前にgasleftを確認し、その値が2300以下であれば、EVMは「out of gas」という例外を発生させ、そのコールスタックを終了させます。 これにより、2300ガスのstipendしか与えられていない状況下では、どのような場合であってもストレージの変更が不可能になります。 したがって、既存のコントラクトが2300ガス制限を安全設計の前提としていたとしても、その安全性が将来のネットワークアップグレード後も維持されるようになります。

このように、仕様の追加は非常にシンプルながらも、過去との互換性を壊すことなく、Ethereumネットワーク全体のセキュリティを強化する効果を持つ重要な変更といえます。

補足

EIP1283の導入により、SSTORE命令によるストレージの更新コストが柔軟かつ低くなったことは、Ethereumにとってガス効率の改善という利点をもたらしました。 しかし、その結果として、既存の多くのコントラクトが暗黙的に依存していた「2300ガスのstipend(ガス付与)」による再入可能性(reentrancy)防止策が、もはや完全には機能しない状況が生まれてしまいました。

そのため、提案された解決策では、「残りガスが2300以下の場合にSSTOREを実行できないようにする」というシンプルな制約を導入することで、既存コントラクトの安全性を維持しつつ、EIP1283の利点を活かすという両立を目指しています。

他に検討された対案とその課題

この問題を解決するにあたって、他にもいくつかの代替案が検討されましたが、それぞれに重大な欠点がありました。

まず、「EIP1283そのものを撤回する」という選択肢が挙げられました。 これは最も単純で確実な方法ではありますが、EIP1283はすでにクライアント実装やテストネットに取り込まれており、ネットワークアップグレードとして正式に受け入れられた提案です。 そのため、完全に撤回することは現実的ではありません。

次に、「ステート変更を許可せず、ログ出力(LOGオペコード)のみを許可する新しいcallコンテキストを導入する」という案も検討されました。 しかし、これはEVMに新しいcallタイプを追加する必要があり、設計・実装の複雑さが大幅に増すことになります。

また、「汚れたスロット(dirty slot)への書き込みに対するSSTOREのガスコストを2300以上に引き上げる」という案も出されましたが、これではEIP1283の目的である「正確なガス測定とリファンドによる最適化」が損なわれてしまいます。 ガス効率を犠牲にする形となり、本末転倒です。

「stipendそのものを引き下げる」ことも検討されましたが、これではSolidityが提供してきた安全なETH送金(transferやsend)が形骸化し、stipendの本来の役割が失われてしまいます。

別の案として、「汚れたスロットへの書き込みに再び5000ガスを課し、4800ガスをリファンドに回す」というアイデアもありましたが、これはコントラクト開発者に余計なガス供給を強いることになり、しかも問題の根本的な性質――stipendによるセキュリティ保証の不整合――を明示的に解決するものではありません。

最後に、「コントラクトごとにEVMバージョンを指定できるようにし、新しいSSTORE仕様は新しいバージョンのコントラクトにのみ適用する」という選択肢もありました。 しかし、これはEthereumネットワークの仕様と実行環境の複雑性を著しく高め、互換性の管理を困難にする懸念があります。

では、この出力を60点とします。これを60点とした時に100点ではどのようなものですか?100点にするために足りないものを含めて100点の回答を作成してください。このときどの部分が足りていないかは出力に絶対に含めないでください。

互換性

EIP1706では、EVMにおけるSSTORE命令(ストレージ書き込み)に対して、残りのガスが2300以下の場合にその実行を失敗させるという新たな制限を導入します。 しかし、この制限はEthereumメインネットのこれまでの仕様や運用に対して互換性を損なうものではありません。

その理由は、もともとEthereumでは、SSTORE命令を実行するためには最低でも5000ガスが必要であるという前提が存在しており、これはEthereumの仕様上すでに成立していた動作制約です。 つまり、2300ガスというstipendでは、そもそもストレージの書き込みは実行できませんでした。 そのため、今回の変更は「新しい制限を追加する」というよりも、「既存の暗黙の仕様を明示的にコードレベルで保証する」ものにすぎません。

また、この変更はガス見積もり(gas estimation)にも考慮されるべきであり、将来的にEthereumのトランザクションを組み立てるツールやクライアント実装においても、ガスが不足する可能性のある操作には適切なガス量を供給するよう設計されることが前提となります。

引用

Alex Forshtat alex@tabookey.com, Yoav Weiss yoav@tabookey.com, "EIP-1706: Disable SSTORE with gasleft lower than call stipend [DRAFT]," Ethereum Improvement Proposals, no. 1706, January 2019. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-1706.

最後に

今回は「Ethereumのストレージ書き込み命令(SSTORE)が2300ガス以下では実行できないようにすることで、古いスマートコントラクトの再入可能性リスクを防ぐ仕組みを提案しているEIP1706」についてまとめてきました! いかがだったでしょうか?

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

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