はじめに

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

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

今回は、ガスコスト削減とコードサイズ縮小のために、スタックに定数値0をプッシュする新しいオペコードであるPUSH0を追加する提案をしているEIP3855についてまとめていきます!

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

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

概要

PUSH0(0x5f)命令について説明します。 この命令はプログラミングやコンピューターサイエンスの分野で使われる概念の1つです。 具体的には、スタック型のデータ構造に対して操作を行う命令の1つです。

スタックとは、データを一時的に保存しておくための容器のようなもので、最後に入れたデータを最初に取り出す「後入れ先出し(Last In, First Out; LIFO)」の性質を持っています。 この性質のおかげで、スタックは一時的なデータの保存や逆転、関数の呼び出しといった処理に適しています。

PUSH0命令は、このスタックに「0」という定数値を「プッシュ」する、つまりスタックの一番上に追加する命令です。 0x5fとは、この命令を表すために使われる16進数のコードです。 コンピューターはこのコードを見て、対応する操作(この場合は0をスタックにプッシュすること)を実行します。

この命令の使用例としては、初期化処理や条件分岐の時にスタック上に特定の値を設定したい場合などがあります。 また、0という値は多くのコンテキストで「何もない」や「偽」と解釈されるため、論理演算やフラグ管理においても重宝されます。

PUSH0命令はプログラミングにおいて、スタックというデータ構造の一番上に0という値を追加するための簡単な方法を提供します。 これにより、プログラマーはより効率的にデータを管理し、複雑な操作を簡単に実行できるようになります。

動機

命令とガスのコスト

スマートコントラクトでは、さまざまな命令を使用して処理を行います。 各命令には「ガス」と呼ばれる実行コストがあり、これはリソースの使用量を表します。 ガスのコストは、実行時の計算資源だけでなく、コントラクトのデプロイ(展開)時のデータストレージのコストも含みます。

ゼロ値の使用

ある状況では、ゼロの値をスタックにプッシュする必要があります。 例えば、スマートコントラクトが外部のコントラクトを呼び出し(CALL命令)た時に、戻り値のデータパラメータがゼロに設定される場合があります。 現在、PUSH1 0命令(ゼロをプッシュするために使用される)は、実行時に3ガスのコストがかかり、2バイトでエンコードされるため、デプロイ時には400ガス(1バイトあたり200ガス)のコストがかかります。

問題点

コードサイズの増大

不必要に多くのPUSH1 0命令がコントラクトのコードサイズを不必要に増加させています。

命令の誤用

コントラクト開発者は、ゼロ値をプッシュするために他の命令(例: PC, MSIZEなど)を使用することでガスコストを節約しようとしますが、これらの命令はコンテキストに依存するため、期待通りの動作をしないリスクがあります。

DUP命令の使用

ゼロの値を複製するために、追加のDUP命令が必要になることがあります。 これは、さらなるガスコストを発生させます。

提案された変更

PUSH0 (0x5f) 命令の導入

ゼロの値をスタックにプッシュするための新しい命令。 これにより、実行時とデプロイ時のガスコストが削減され、コードサイズも小さくなります。

効果

コードサイズの削減

PUSH0命令は、ゼロをプッシュするために必要なバイト数を減らすことで、コントラクトのコードサイズを削減します。

ガスコストの節約

PUSH0命令により、ゼロをプッシュするためのガスコストが削減されます。 分析によると、既存のコントラクトで無駄に使われているガスは68,111,466,200ガスにも上ります。

命令の誤用リスクの低減

PUSH0命令を使用することで、他の命令を代替として使用するリスクが減少します。 これにより、将来的にこれらの命令の動作が変更された場合のリスクも減少します。

この変更はスマートコントラクトの効率性と安全性を向上させることが期待されています。

仕様

PUSH0という新しい命令が、0x5fというコードで導入されました。 この命令は、直接データ(即値)を必要とせず、スタックからアイテムを取り除く(ポップする)こともありません。 代わりに、値「0」を持つ単一のアイテムをスタック上に置きます。 この命令の実行には、2ガス(基本ガスコストとも呼ばれます)が必要です。

ここで言う「スタック」とは、データを一時的に保存するための構造で、最後に追加されたデータが最初に取り出される「後入れ先出し」の性質を持っています。 PUSH0命令を使うと、スタックの最上部に「0」という値を追加することができます。

0x5fは、PUSH0命令を表すために使用される16進数コードです。 コンピュータやブロックチェーンの仮想マシンは、このコードを見てPUSH0命令を実行することを理解します。

「2ガス」とは、この命令を実行するために必要な計算資源の量を表し、ブロックチェーン上でのトランザクションやスマートコントラクトの実行に関連するコストを意味します。 ガスは、ブロックチェーンネットワークのリソースを利用する際の手数料のようなものです。

PUSH0命令は非常にシンプルで効率的な方法でスタックに「0」を追加するために設計されており、その実行コストは比較的低い(2ガス)です。 これにより、スマートコントラクトの開発者はゼロ値を必要とする場面でこの命令を使い、リソースの消費を抑えることができます。

補足

ガスコストの根拠

ここで言及されている「基本ガスコスト」とは、スタックに定数値を置くような命令に適用されるガスのコストのことを指します。 ADDRESSやORIGINのような命令がその例です。 これらの命令は、スマートコントラクトの実行中に静的な(変わらない)値をスタックに追加します。 このような命令は、実行に必要な計算量が少ないため、比較的低いガスコストが設定されています。 PUSH0もこのカテゴリーに含まれるため、基本ガスコストが2ガスと設定されています。

オペコードについて

オペコード(操作コード)は、コンピュータや仮想マシンが理解できる命令のことです。 0x5fは、PUSH0命令を表す16進数のコードです。 この命令は、「PUSH」命令群と「連続した」スペース(つまり、命令セットの中で論理的に隣接している場所)に配置されています。 これは、PUSH0が他のPUSH命令(例:PUSH1、PUSH2など)と実装を共有しやすいことを意味します。 つまり、これらのPUSH命令が似たような構造で作られており、コードの再利用やメンテナンスの効率化に貢献する可能性があるということです。

PUSH0命令の導入が、スマートコントラクトのガス消費を最適化し、開発者がより効率的にコードを書くことを可能にするための戦略的な決定であることを示しています。 また、0x5fというオペコードの選択は、既存の命令セットとの整合性と効率的な実装のための考慮から来ていることがわかります。

互換性

このEIPは、以前には存在しなかった新しいオペコードを導入します。 このオペコードを使用している既にデプロイされたコントラクトは、このEIPの後にその動作を変更する可能性があります。

テスト

ここで示されているテストケースは、PUSH0命令(オペコード0x5f)の動作を検証するためのシナリオです。 それぞれのケースは、異なる状況でのPUSH0命令の実行結果を表しています。

5F – 単一のゼロアイテムのスタック

このケースでは、PUSH0命令(0x5f)が1回実行されます。 成功すると、スタックには1つのアイテムが追加され、その値は0に設定されます。 これはPUSH0命令の基本的な動作で、スタックに「0」を追加することを意味します。

5F5F..5F (1024回) – 1024個のゼロアイテムのスタック

このケースでは、PUSH0命令が1024回連続で実行されます。 各命令がスタックに「0」を追加するため、最終的にスタックには1024個の「0」が含まれます。 このケースも成功し、スタックのサイズ制限内であるため問題なく実行されます。

5F5F..5F (1025回) – スタックオーバーフローによる実行中断

最後のケースでは、PUSH0命令が1025回実行されます。 しかし、多くのブロックチェーン環境や仮想マシンでは、スタックに格納できるアイテムの数には上限があります。 Ethereum Virtual Machine(EVM)の場合、この上限は1024アイテムです。 そのため、1025回目のPUSH0命令を実行しようとすると、スタックの最大サイズを超えるため、実行が中断されます(スタックオーバーフロー)。

これらのテストケースは、PUSH0命令の動作を様々な状況で検証するために設計されています。 最初の2つのケースは、命令が想定通りに動作し、スタックに「0」を追加できることを確認します。 最後のケースは、スタックのサイズ制限を超えた場合の動作をテストし、システムの堅牢性を検証するものです。

セキュリティ

PUSH0命令の導入がセキュリティに与える影響について述べたものです。 特に、PUSH0命令が即時データバイト(命令に直接付随するデータ)を持たないため、ジャンプテスト(プログラムの実行フローを制御する命令の分析)には影響を与えない点を指摘しています。

セキュリティへの影響

PUSH0命令の導入がセキュリティに悪影響を与えることはないと考えています。 これは、PUSH0が非常に単純な操作(スタックにゼロを追加するだけ)を行うため、攻撃者が利用できる脆弱性や不正な挙動を導入する余地がほとんどないからです。

即時データバイトの不在

PUSH0命令は即時データバイトを必要としません。 即時データバイトとは、命令が実行される際に追加の情報(例えば、特定の値やアドレス)を提供するために命令コードに直接含まれるデータのことです。 PUSH0は常に同じ値「0」をスタックにプッシュするため、このような追加情報は不要です。

ジャンプテスト解析への影響なし

プログラムの実行フローを制御する命令(ジャンプ命令)の動作を検証するプロセスです。 ジャンプ命令はプログラム内の異なる部分に制御を移すために使用され、正確なジャンプ先のアドレスが重要です。 即時データバイトが含まれる命令は、ジャンプテスト解析に影響を与える可能性がありますが、PUSH0には即時データバイトがないため、この解析に影響を与えることはありません。

PUSH0命令はセキュリティリスクを増加させるような複雑な操作や追加データを必要としないため、スマートコントラクトやその他のプログラムのセキュリティに対して、直接的な悪影響を与えることはないと考えられます。 また、即時データバイトがないため、プログラムの実行フロー解析(ジャンプテスト解析)にも影響を与えません。

引用

Alex Beregszaszi (@axic), Hugo De la cruz (@hugo-dc), Paweł Bylica (@chfast), "EIP-3855: PUSH0 instruction," Ethereum Improvement Proposals, no. 3855, February 2021. [Online serial]. Available: https://eips.ethereum.org/EIPS/eip-3855.

最後に

今回は「スタックに定数値0をプッシュする新しいオペコードであるPUSH0を追加する提案をしているEIP3855」についてまとめてきました! いかがだったでしょうか?

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

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