はじめに

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

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

今回は、コントラクトでエラーが起きた時、実行を中止して原因を返す仕組みを提案している規格であるEIP140についてまとめていきます!

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

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

要約

REVERT命令は、すべてのガスを消費することなく実行を停止し、状態変更を戻してエラーの原因を返すことができます。

概要

「REVERT」は主にイーサリアムのスマートコントラクトで使用される機能です。 スマートコントラクトは、ブロックチェーン上で自動的に実行されるプログラムのことを指します。 REVERT命令の役割は、スマートコントラクトの実行中に何らかのエラーが発生した場合、それまでに行われたすべての状態変更を元に戻し(ロールバックし)、エラーコードやメッセージを指すメモリ領域へのポインタを提供することです。

REVERT命令が実行されると、スマートコントラクトの実行は中断され、それまでのトランザクションによって変更されたすべてのデータが元の状態に戻されます。 しかし、このプロセスで重要なのは、全てのガス(トランザクションを実行するために必要な手数料のようなもの)が消費されないという点です。 つまり、REVERT命令はエラーが発生した時に、一部のガスを節約しつつトランザクションの失敗を扱う方法を提供します。

この機能は、スマートコントラクトの安全性を高め、不必要なガスの消費を防ぐために非常に重要です。 例えば、ERC20やERC721などの標準規格を実装するスマートコントラクトでよく使用されます。

ERC20については以下を参考にしてください。

ERC721については以下を参考にしてください。

動機

現在のイーサリアムのスマートコントラクトでは、コントラクト内からトランザクションを元に戻す(revertする)ことは基本的に不可能です(この規格が提案された当時は)。 トランザクションをリバートする実用的な方法は二つありますが、どちらも全ての残りのガスを消費します。

ガス切れ

トランザクションの実行中にガス(トランザクションを実行するための手数料)が尽きることです。 ガスが尽きると、トランザクションは自動的にリバートされます。

無効な命令の実行

コントラクトが無効またはエラーを含む命令を実行すると、トランザクションはリバートされます。

さらに、イーサリアム仮想マシン(EVM)の実行をリバートすると、すべての変更(ログを含む)が失われます。 その結果、EVM実行を中止する原因を伝える方法がありません。

これは、特にERC20やERC721などの標準規格を使用するコントラクトにおいて重要です。 これらのコントラクトではセキュリティと効率が非常に重視されるため、実行のリバートが難しいという特性を理解することが重要です。

仕様

イーサリアムのBYZANTIUM_FORK_BLKNUM以降のブロックでは、新しい命令REVERTが導入されました。 このREVERT命令は、スマートコントラクトの実行を中止するために使用されます。 具体的には、スタックの上から二つの要素、memory_offsetとmemory_lengthを必要とします。 これらは、エラーメッセージを指定するために使われます。

REVERT命令は以下のように動作します。

実行の中止とロールバック

実行が停止され、それまでの状態変更(データの更新など)が元に戻されます(ロールバックされます)。

エラーメッセージの提供

指定されたメモリ領域からエラーメッセージが取得され、呼び出し元に渡されます。 これはRETURN命令と同様の方法で処理されます。

コスト

REVERT命令のコストはRETURN命令と同じで、ロールバック自体は全ガスを消費しません。 コントラクトはメモリの使用に対してのみ料金を支払います。

ガス不足の場合

十分なガスがないか、スタックアンダーフローが発生した場合、REVERT命令は通常のガス切れ例外と同じように全ガスを消費します。

CREATEやCREATE2の文脈での使用

REVERTがCREATEやCREATE2コマンドと一緒に使われる場合、コードはデプロイされず、スタックには0が置かれ、エラーメッセージは利用可能です。

なお、提供されるメモリセクションの内容については、このEIP(Ethereum Improvement Proposal)では定義されていませんが、将来的に別のEIPで扱われる可能性があります。 これは、ERC20やERC721などの標準規格に基づくコントラクトの安全性と効率を高めるために重要な機能です。

後方互換性

この変更は、0xfdを命令として含まない限り、過去に作成されたコントラクトには影響しません。

テスト

text
6c726576657274656420646174616000557f726576657274206d657373616765000000000000000000000000000000000000600052600e6000fd

上記のコードはイーサリアムのスマートコントラクトで使用されるバイトコードの一部です。

REVERTデータの返却

このコードはREVERT命令を使用しています。 REVERTは実行を中止し、特定のエラーメッセージを返します。 この場合、返されるべきエラーメッセージは0x726576657274206d657373616765です。 これは、バイトコード内の指定された位置にあるデータを意味します。

ストレージの未設定

このコードの実行により、ストレージのキー0x0の位置にあるデータは変更されず、未設定のまま残ります。 これはREVERT命令が状態変更をロールバックするためです。

ガスの消費量

このコードの実行には合計で20024ガスが必要です。 ガスは、イーサリアムネットワーク上でコントラクトを実行するために必要な手数料のようなものです。

このバイトコードは、ERC20やERC721などのスマートコントラクト標準に基づいているかもしれませんが、それ自体で特定の標準に属しているわけではありません。 これは、コントラクトの動作を定義する低レベルのコードの一例です。

引用

Alex Beregszaszi (@axic), Nikolai Mushegian nikolai@nexusdev.us, "EIP-140: REVERT instruction," Ethereum Improvement Proposals, no. 140, February 2017. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-140.

最後に

今回は「コントラクトでエラーが起きた時、実行を中止して原因を返す仕組みを提案している規格であるEIP140」についてまとめてきました! いかがだったでしょうか?

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

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