# スマートコントラクト開発におけるGas費用最適化戦略イーサリアムメインネットのGas費用の問題は、開発者とユーザーの関心の焦点であり、特にネットワークが混雑している時に一層顕著です。取引のピーク時には、ユーザーはしばしば高額な費用を支払う必要があります。したがって、スマートコントラクトの開発段階でGas費用の最適化を行うことが特に重要です。Gas消費の最適化は、取引コストを効果的に削減するだけでなく、取引効率を向上させ、ユーザーにとってより経済的で効率的なブロックチェーンの利用体験を提供します。本文では、Ethereum仮想マシン(EVM)のGas費用メカニズム、関連するコア概念、およびスマートコントラクトを開発する際のGas費用最適化のベストプラクティスについて概説します。これらの内容が開発者にとってのインスピレーションや実用的な助けとなり、同時に一般ユーザーがEVMのGas費用の運用方法をよりよく理解する手助けとなり、ブロックチェーンエコシステムの課題に共同で対処できることを願っています。## EVMのGas費メカニズム紹介EVM互換ネットワークでは、Gasは特定の操作を実行するために必要な計算能力の単位です。EVMの構造レイアウトでは、Gas消費は主に3つの部分に分かれています:操作実行、外部メッセージ呼び出し、そしてメモリとストレージの読み書き。各取引の実行には計算リソースが必要なため、無限ループやサービス拒否(DoS)攻撃を防ぐために一定の手数料が徴収されます。取引を完了するために必要な手数料はGas費と呼ばれます。EIP-1559(のロンドンハードフォーク)が発効して以来、Gas費は以下の公式で計算されます:ガス料金 = 使用されたガスの単位 * (ベース料金 + プライオリティ料金)基礎手数料は消却され、優先手数料はインセンティブとして機能し、バリデーターが取引をブロックチェーンに追加することを促します。取引を送信する際に優先手数料を高く設定すると、次のブロックに取引が含まれる可能性が高まります。### EVM でのガス最適化の理解Solidityでスマートコントラクトをコンパイルすると、コントラクトは一連の操作コード(opcodes)に変換されます。あらゆる操作コード(、例えば契約の作成、メッセージの呼び出し、アカウントストレージへのアクセス、そして仮想マシン上での操作の実行)には、認識されたガス消費コストがあり、これらのコストはイーサリアムのホワイトペーパーに記録されています。複数回のEIPの修正を経て、一部のオペコードのGasコストが調整されており、黄皮書の内容と異なる可能性があります。### ガス最適化の基本概念Gas最適化の核心理念は、EVMブロックチェーン上でコスト効率の高い操作を優先的に選択し、Gasコストが高い操作を避けることです。EVMでは、以下の操作はコストが低いです:- メモリ変数の読み書き- 定数と不変の変数を読み取る- ローカル変数の読み書き- calldata 配列や構造体などの calldata 変数を読み取る- 内部関数呼び出しコストの高い操作には次のものが含まれます:- スマートコントラクトのストレージに保存されている状態変数を読み書きする- 外部関数呼び出し- ループ操作## EVMガス費用最適化のベストプラクティス上述の基本概念に基づき、私たちは開発者コミュニティのためにGas費の最適化に関するベストプラクティスリストを整理しました。これらのプラクティスに従うことで、開発者はスマートコントラクトのGas費消費を削減し、取引コストを低減し、より効率的でユーザーフレンドリーなアプリケーションを構築できます。### 1. ストレージの使用をできるだけ減らすSolidityにおいて、Storage(のストレージ)は限られたリソースであり、そのGas消費はMemory(のメモリ)よりもはるかに高いです。スマートコントラクトがストレージからデータを読み書きするたびに、高額なGasコストが発生します。イーサリアムのホワイトペーパーの定義によれば、ストレージ操作のコストはメモリ操作の100倍以上高い。例えば、OPcodeのmloadとmstore命令はわずか3ガス単位を消費しますが、ストレージ操作のsloadとsstoreは最も理想的な状況でもコストが少なくとも100単位必要です。制限ストレージ使用の方法には以下が含まれます:- 一時的なデータをメモリに保存する- ストレージの変更回数を減らす: 中間結果をメモリに保存し、すべての計算が完了した後に結果をストレージ変数に割り当てる。### 2. 変数パッケージスマートコントラクト中使用のStorage slot(ストレージスロット)の数および開発者がデータを表示する方法は、Gas費の消費に大きな影響を与えます。Solidityコンパイラは、コンパイルプロセス中に連続したストレージ変数をパッケージ化し、32バイトのストレージスロットを変数ストレージの基本単位として使用します。変数のパッケージ化とは、変数を合理的に配置することで、複数の変数が単一のストレージスロットに適合できるようにすることを指します。この詳細な調整により、開発者は20,000ガス単位を節約できます。未使用のストレージスロットを保存するには20,000ガス(が必要です。各ストレージスロットはGasを消費するため、変数のパッキングは必要なストレージスロットの数を減らすことでGasの使用を最適化します。![イーサリアムスマートコントラクトのGas最適化のトップ10ベストプラクティス])https://img-cdn.gateio.im/social/moments-30f0bc370a7b9ca65f3d623c31262b76() 3. データ型の最適化変数は複数のデータ型で表すことができますが、異なるデータ型に対応する操作コストも異なります。適切なデータ型を選択することで、Gasの使用を最適化することができます。例えば、Solidityでは、整数は異なるサイズに細分化できます:uint8、uint16、uint32など。EVMは256ビット単位で操作を実行するため、uint8を使用するとEVMは最初にそれをuint256に変換する必要があり、この変換には追加のガスが消費されます。単独で見ると、uint256を使用する方がuint8よりも安価です。しかし、変数をパックして最適化する場合は異なります。もし開発者が4つのuint8変数を1つのストレージスロットにパックできるなら、それらを反復処理する総コストは4つのuint256変数よりも低くなります。こうすることで、スマートコントラクトは1回のストレージスロットの読み書きを行い、1回の操作で4つのuint8変数をメモリ/ストレージに配置することができます。![イーサリアムスマートコントラクトのGas最適化の10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-995905cb414526d4d991899d0c2e6443() 4. 動的変数の代わりに固定サイズの変数を使用するデータが32バイト以内に収まる場合は、bytesまたはstringsの代わりにbytes32データ型を使用することをお勧めします。一般的に、固定サイズの変数は可変サイズの変数よりもガス消費が少ないです。バイトの長さを制限できる場合は、できるだけbytes1からbytes32の最小長を選択してください。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-55fcdb765912ef9cd238c46b1d248cff() 5. マッピングと配列Solidityのデータリストは、2つのデータ型で表すことができます: 配列###Arrays(とマッピング)Mappings(ですが、それらの構文と構造は全く異なります。マッピングはほとんどの場合、効率が高くコストが低いですが、配列はイテラブルでデータ型のパッキングをサポートしています。したがって、データリストを管理する場合はマッピングを優先して使用することをお勧めします。ただし、イテレーションが必要な場合やデータ型のパッキングによってガス消費を最適化できる場合を除きます。![イーサリアムスマートコントラクトのGas最適化のための10のベストプラクティス])https://img-cdn.gateio.im/social/moments-5f3d7e103e47c886f50599cffe35c707() 6. メモリの代わりに calldata を使用する関数のパラメータで宣言された変数は、calldataまたはmemoryに格納できます。両者の主な違いは、memoryは関数によって変更できるのに対し、calldataは不変であることです。この原則を覚えておいてください: 関数の引数が読み取り専用である場合は、memoryではなくcalldataを優先的に使用すべきです。これにより、関数のcalldataからmemoryへの不要なコピー操作を避けることができます。![イーサリアムスマートコントラクトのGas最適化に関するトップ10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-9c566626ab499ef65d6f5089a2876ad3() 7. 可能な限り Constant/Immutable キーワードを使用してくださいConstant/Immutable変数は、契約のストレージに保存されません。これらの変数はコンパイル時に計算され、契約のバイトコードに保存されます。したがって、ストレージと比較して、それらのアクセスコストははるかに低くなります。可能な限りConstantまたはImmutableキーワードを使用することをお勧めします。![イーサリアムスマートコントラクトのGas最適化のトップ10ベストプラクティス]###https://img-cdn.gateio.im/social/moments-c0701f9e09280a1667495d54e262dd2f() 8. オーバーフロー/アンダーフローが発生しないことを確認してUncheckedを使用する開発者が算術演算がオーバーフローまたはアンダーフローを引き起こさないことを確認できる場合、Solidity v0.8.0で導入されたuncheckedキーワードを使用して、余分なオーバーフローまたはアンダーフローのチェックを回避し、Gasコストを節約できます。さらに、0.8.0以上のバージョンのコンパイラでは、SafeMathライブラリを使用する必要がなくなりました。なぜなら、コンパイラ自体にオーバーフローとアンダーフローの保護機能が組み込まれているからです。![イーサリアムのスマートコントラクトのGas最適化に関する10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-a823fb7761aafa6529a6c45304e0314b() 9. オプティマイザ修正器のコードは修正された関数に埋め込まれ、修正器を使用するたびにそのコードがコピーされます。これによりバイトコードのサイズが増加し、Gasの消費が増えます。内部関数にロジックを再構築することで、修飾子内でその内部関数を再利用でき、バイトコードのサイズを減少させ、ガスコストを削減できます。![イーサリアムスマートコントラクトのGas最適化トップ10ベストプラクティス]###https://img-cdn.gateio.im/social/moments-839b91e2f02389949aa698d460a497d8() 10. ショートサーキット最適化||および&&演算子に対して、論理演算はショートサーキット評価が行われます。つまり、最初の条件が論理式の結果を決定できる場合、二つ目の条件は評価されません。Gas消費を最適化するために、計算コストが低い条件を前に置くべきです。そうすることで、高コストの計算をスキップする可能性があります。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-a141884dcdcdc56faff12eee2601b7b7(## その他の一般的な推奨事項) 1. 不要なコードを削除する契約に未使用の関数や変数が存在する場合は、それを削除することをお勧めします。これは、契約のデプロイコストを削減し、契約のサイズを小さく保つ最も直接的な方法です。以下は幾つかの実用的なアドバイスです:- 最も効率的なアルゴリズムを使用して計算します。契約内で特定の計算結果を直接使用する場合は、これらの冗長な計算プロセスを削除する必要があります。本質的に、使用されていない計算はすべて削除されるべきです。- イーサリアムでは、開発者はストレージスペースを解放することでGas報酬を得ることができます。不要になった変数は、deleteキーワードを使用して削除するか、デフォルト値に設定する必要があります。- ループ最適化: 高コストのループ操作を避け、可能な限りループを統合し、繰り返し計算をループ本体の外に移動します。### 2. プリコンパイルされたスマートコントラクトを使用するプリコンパイルされたコントラクトは、暗号化やハッシュ操作などの複雑なライブラリ関数を提供します。コードはEVM上ではなく、クライアントノードのローカルで実行されるため、必要なGasが少なくなります。プリコンパイルされたコントラクトを使用することで、スマートコントラクトの実行に必要な計算作業量を減らすことでGasを節約できます。プリコンパイルされたコントラクトの例には、楕円曲線デジタル署名アルゴリズム###ECDSA(とSHA2-256ハッシュアルゴリズムが含まれます。スマートコントラクト内でこれらのプリコンパイルされたコントラクトを使用することにより、開発者はガスコストを削減し、アプリケーションの実行効率を向上させることができます。) 3. インラインアセンブリコードを使用するインラインアセンブリ###in-line assembly(は、開発者がEVMによって直接実行される低レベルでありながら効率的なコードを記述できるようにし、高価なSolidityオペコードを使用する必要がありません。インラインアセンブリは、メモリとストレージの使用をより正確に制御できるため、Gas費用をさらに削減します。また、インラインアセンブリは、Solidityだけでは実現が難しいいくつかの複雑な操作を実行でき、Gas消費の最適化に対する柔軟性を提供します。しかし、インラインアセンブリを使用することはリスクを伴う可能性があり、エラーが発生しやすいです。したがって、慎重に使用し、経験豊富な開発者の操作に限定するべきです。) 4. Layer 2ソリューションの使用使節
イーサリアムスマートコントラクトGas費最適化戦略とベストプラクティス
スマートコントラクト開発におけるGas費用最適化戦略
イーサリアムメインネットのGas費用の問題は、開発者とユーザーの関心の焦点であり、特にネットワークが混雑している時に一層顕著です。取引のピーク時には、ユーザーはしばしば高額な費用を支払う必要があります。したがって、スマートコントラクトの開発段階でGas費用の最適化を行うことが特に重要です。Gas消費の最適化は、取引コストを効果的に削減するだけでなく、取引効率を向上させ、ユーザーにとってより経済的で効率的なブロックチェーンの利用体験を提供します。
本文では、Ethereum仮想マシン(EVM)のGas費用メカニズム、関連するコア概念、およびスマートコントラクトを開発する際のGas費用最適化のベストプラクティスについて概説します。これらの内容が開発者にとってのインスピレーションや実用的な助けとなり、同時に一般ユーザーがEVMのGas費用の運用方法をよりよく理解する手助けとなり、ブロックチェーンエコシステムの課題に共同で対処できることを願っています。
EVMのGas費メカニズム紹介
EVM互換ネットワークでは、Gasは特定の操作を実行するために必要な計算能力の単位です。
EVMの構造レイアウトでは、Gas消費は主に3つの部分に分かれています:操作実行、外部メッセージ呼び出し、そしてメモリとストレージの読み書き。
各取引の実行には計算リソースが必要なため、無限ループやサービス拒否(DoS)攻撃を防ぐために一定の手数料が徴収されます。取引を完了するために必要な手数料はGas費と呼ばれます。
EIP-1559(のロンドンハードフォーク)が発効して以来、Gas費は以下の公式で計算されます:
ガス料金 = 使用されたガスの単位 * (ベース料金 + プライオリティ料金)
基礎手数料は消却され、優先手数料はインセンティブとして機能し、バリデーターが取引をブロックチェーンに追加することを促します。取引を送信する際に優先手数料を高く設定すると、次のブロックに取引が含まれる可能性が高まります。
EVM でのガス最適化の理解
Solidityでスマートコントラクトをコンパイルすると、コントラクトは一連の操作コード(opcodes)に変換されます。
あらゆる操作コード(、例えば契約の作成、メッセージの呼び出し、アカウントストレージへのアクセス、そして仮想マシン上での操作の実行)には、認識されたガス消費コストがあり、これらのコストはイーサリアムのホワイトペーパーに記録されています。
複数回のEIPの修正を経て、一部のオペコードのGasコストが調整されており、黄皮書の内容と異なる可能性があります。
ガス最適化の基本概念
Gas最適化の核心理念は、EVMブロックチェーン上でコスト効率の高い操作を優先的に選択し、Gasコストが高い操作を避けることです。
EVMでは、以下の操作はコストが低いです:
コストの高い操作には次のものが含まれます:
EVMガス費用最適化のベストプラクティス
上述の基本概念に基づき、私たちは開発者コミュニティのためにGas費の最適化に関するベストプラクティスリストを整理しました。これらのプラクティスに従うことで、開発者はスマートコントラクトのGas費消費を削減し、取引コストを低減し、より効率的でユーザーフレンドリーなアプリケーションを構築できます。
1. ストレージの使用をできるだけ減らす
Solidityにおいて、Storage(のストレージ)は限られたリソースであり、そのGas消費はMemory(のメモリ)よりもはるかに高いです。スマートコントラクトがストレージからデータを読み書きするたびに、高額なGasコストが発生します。
イーサリアムのホワイトペーパーの定義によれば、ストレージ操作のコストはメモリ操作の100倍以上高い。例えば、OPcodeのmloadとmstore命令はわずか3ガス単位を消費しますが、ストレージ操作のsloadとsstoreは最も理想的な状況でもコストが少なくとも100単位必要です。
制限ストレージ使用の方法には以下が含まれます:
2. 変数パッケージ
スマートコントラクト中使用のStorage slot(ストレージスロット)の数および開発者がデータを表示する方法は、Gas費の消費に大きな影響を与えます。
Solidityコンパイラは、コンパイルプロセス中に連続したストレージ変数をパッケージ化し、32バイトのストレージスロットを変数ストレージの基本単位として使用します。変数のパッケージ化とは、変数を合理的に配置することで、複数の変数が単一のストレージスロットに適合できるようにすることを指します。
この詳細な調整により、開発者は20,000ガス単位を節約できます。未使用のストレージスロットを保存するには20,000ガス(が必要です。
各ストレージスロットはGasを消費するため、変数のパッキングは必要なストレージスロットの数を減らすことでGasの使用を最適化します。
![イーサリアムスマートコントラクトのGas最適化のトップ10ベストプラクティス])https://img-cdn.gateio.im/webp-social/moments-30f0bc370a7b9ca65f3d623c31262b76.webp(
) 3. データ型の最適化
変数は複数のデータ型で表すことができますが、異なるデータ型に対応する操作コストも異なります。適切なデータ型を選択することで、Gasの使用を最適化することができます。
例えば、Solidityでは、整数は異なるサイズに細分化できます:uint8、uint16、uint32など。EVMは256ビット単位で操作を実行するため、uint8を使用するとEVMは最初にそれをuint256に変換する必要があり、この変換には追加のガスが消費されます。
単独で見ると、uint256を使用する方がuint8よりも安価です。しかし、変数をパックして最適化する場合は異なります。もし開発者が4つのuint8変数を1つのストレージスロットにパックできるなら、それらを反復処理する総コストは4つのuint256変数よりも低くなります。こうすることで、スマートコントラクトは1回のストレージスロットの読み書きを行い、1回の操作で4つのuint8変数をメモリ/ストレージに配置することができます。
![イーサリアムスマートコントラクトのGas最適化の10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-995905cb414526d4d991899d0c2e6443.webp(
) 4. 動的変数の代わりに固定サイズの変数を使用する
データが32バイト以内に収まる場合は、bytesまたはstringsの代わりにbytes32データ型を使用することをお勧めします。一般的に、固定サイズの変数は可変サイズの変数よりもガス消費が少ないです。バイトの長さを制限できる場合は、できるだけbytes1からbytes32の最小長を選択してください。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-55fcdb765912ef9cd238c46b1d248cff.webp(
) 5. マッピングと配列
Solidityのデータリストは、2つのデータ型で表すことができます: 配列###Arrays(とマッピング)Mappings(ですが、それらの構文と構造は全く異なります。
マッピングはほとんどの場合、効率が高くコストが低いですが、配列はイテラブルでデータ型のパッキングをサポートしています。したがって、データリストを管理する場合はマッピングを優先して使用することをお勧めします。ただし、イテレーションが必要な場合やデータ型のパッキングによってガス消費を最適化できる場合を除きます。
![イーサリアムスマートコントラクトのGas最適化のための10のベストプラクティス])https://img-cdn.gateio.im/webp-social/moments-5f3d7e103e47c886f50599cffe35c707.webp(
) 6. メモリの代わりに calldata を使用する
関数のパラメータで宣言された変数は、calldataまたはmemoryに格納できます。両者の主な違いは、memoryは関数によって変更できるのに対し、calldataは不変であることです。
この原則を覚えておいてください: 関数の引数が読み取り専用である場合は、memoryではなくcalldataを優先的に使用すべきです。これにより、関数のcalldataからmemoryへの不要なコピー操作を避けることができます。
![イーサリアムスマートコントラクトのGas最適化に関するトップ10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-9c566626ab499ef65d6f5089a2876ad3.webp(
) 7. 可能な限り Constant/Immutable キーワードを使用してください
Constant/Immutable変数は、契約のストレージに保存されません。これらの変数はコンパイル時に計算され、契約のバイトコードに保存されます。したがって、ストレージと比較して、それらのアクセスコストははるかに低くなります。可能な限りConstantまたはImmutableキーワードを使用することをお勧めします。
![イーサリアムスマートコントラクトのGas最適化のトップ10ベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-c0701f9e09280a1667495d54e262dd2f.webp(
) 8. オーバーフロー/アンダーフローが発生しないことを確認してUncheckedを使用する
開発者が算術演算がオーバーフローまたはアンダーフローを引き起こさないことを確認できる場合、Solidity v0.8.0で導入されたuncheckedキーワードを使用して、余分なオーバーフローまたはアンダーフローのチェックを回避し、Gasコストを節約できます。
さらに、0.8.0以上のバージョンのコンパイラでは、SafeMathライブラリを使用する必要がなくなりました。なぜなら、コンパイラ自体にオーバーフローとアンダーフローの保護機能が組み込まれているからです。
![イーサリアムのスマートコントラクトのGas最適化に関する10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-a823fb7761aafa6529a6c45304e0314b.webp(
) 9. オプティマイザ
修正器のコードは修正された関数に埋め込まれ、修正器を使用するたびにそのコードがコピーされます。これによりバイトコードのサイズが増加し、Gasの消費が増えます。
内部関数にロジックを再構築することで、修飾子内でその内部関数を再利用でき、バイトコードのサイズを減少させ、ガスコストを削減できます。
![イーサリアムスマートコントラクトのGas最適化トップ10ベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-839b91e2f02389949aa698d460a497d8.webp(
) 10. ショートサーキット最適化
||および&&演算子に対して、論理演算はショートサーキット評価が行われます。つまり、最初の条件が論理式の結果を決定できる場合、二つ目の条件は評価されません。
Gas消費を最適化するために、計算コストが低い条件を前に置くべきです。そうすることで、高コストの計算をスキップする可能性があります。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-a141884dcdcdc56faff12eee2601b7b7.webp(
その他の一般的な推奨事項
) 1. 不要なコードを削除する
契約に未使用の関数や変数が存在する場合は、それを削除することをお勧めします。これは、契約のデプロイコストを削減し、契約のサイズを小さく保つ最も直接的な方法です。
以下は幾つかの実用的なアドバイスです:
最も効率的なアルゴリズムを使用して計算します。契約内で特定の計算結果を直接使用する場合は、これらの冗長な計算プロセスを削除する必要があります。本質的に、使用されていない計算はすべて削除されるべきです。
イーサリアムでは、開発者はストレージスペースを解放することでGas報酬を得ることができます。不要になった変数は、deleteキーワードを使用して削除するか、デフォルト値に設定する必要があります。
ループ最適化: 高コストのループ操作を避け、可能な限りループを統合し、繰り返し計算をループ本体の外に移動します。
2. プリコンパイルされたスマートコントラクトを使用する
プリコンパイルされたコントラクトは、暗号化やハッシュ操作などの複雑なライブラリ関数を提供します。コードはEVM上ではなく、クライアントノードのローカルで実行されるため、必要なGasが少なくなります。プリコンパイルされたコントラクトを使用することで、スマートコントラクトの実行に必要な計算作業量を減らすことでGasを節約できます。
プリコンパイルされたコントラクトの例には、楕円曲線デジタル署名アルゴリズム###ECDSA(とSHA2-256ハッシュアルゴリズムが含まれます。スマートコントラクト内でこれらのプリコンパイルされたコントラクトを使用することにより、開発者はガスコストを削減し、アプリケーションの実行効率を向上させることができます。
) 3. インラインアセンブリコードを使用する
インラインアセンブリ###in-line assembly(は、開発者がEVMによって直接実行される低レベルでありながら効率的なコードを記述できるようにし、高価なSolidityオペコードを使用する必要がありません。インラインアセンブリは、メモリとストレージの使用をより正確に制御できるため、Gas費用をさらに削減します。また、インラインアセンブリは、Solidityだけでは実現が難しいいくつかの複雑な操作を実行でき、Gas消費の最適化に対する柔軟性を提供します。
しかし、インラインアセンブリを使用することはリスクを伴う可能性があり、エラーが発生しやすいです。したがって、慎重に使用し、経験豊富な開発者の操作に限定するべきです。
) 4. Layer 2ソリューションの使用
使節