# イーサリアムスマートコントラクトのGas最適化ベストプラクティスイーサリアムメインネットの Gas 料金は常に厄介な問題であり、特にネットワークが混雑しているときにそれが顕著です。ピーク時には、ユーザーはしばしば高額な取引手数料を支払う必要があります。したがって、スマートコントラクト開発段階における Gas 料金の最適化は非常に重要です。Gas 消費を最適化することで、取引コストを効果的に削減できるだけでなく、取引効率も向上し、ユーザーにとってより経済的で効率的なブロックチェーン使用体験を提供します。本文では、イーサリアム仮想マシン(EVM)のGas費用メカニズム、Gas費用最適化に関するコア概念、及びスマートコントラクト開発時のGas費用最適化のベストプラクティスを概説します。これらの内容を通じて、開発者にインスピレーションと実用的な助けを提供し、一般ユーザーがEVMのGas費用の運用方法をよりよく理解できるよう支援し、ブロックチェーンエコシステムの課題に共に取り組むことを願っています。## EVMのガス料金メカニズムの紹介EVM 対応ネットワークでは、「ガス」は特定の操作を実行するために必要な計算能力を測定する単位を指します。EVMの構造レイアウトでは、Gas消費は3つの部分に分かれています: 操作実行、外部メッセージ呼び出し、そしてメモリとストレージの読み書き。各取引の実行には計算リソースが必要なため、無限ループや拒否サービス(DoS)攻撃を防ぐために一定の手数料が徴収されます。取引を完了するために必要な手数料は「ガス料金」と呼ばれます。EIP-1559が施行されて以来、Gas料金は以下の公式で計算されています:ガス料金 = 使用したガスの単位 * (ベース料金 + プライオリティ料金)基本料金は破棄され、優先料金はインセンティブとして機能し、バリデーターが取引をブロックチェーンに追加することを奨励します。取引を送信する際により高い優先料金を設定すると、次のブロックに取引が含まれる可能性が高まります。これは、ユーザーがバリデーターに対して支払う「チップ」のようなものです。### 1. EVM における Gas の最適化を理解するSolidityでスマートコントラクトをコンパイルすると、コントラクトは一連の"オペコード"、すなわちopcodesに変換されます。任意のオペコード(、例えば契約の作成、メッセージ呼び出しの実行、アカウントストレージへのアクセス、及び仮想マシン上での操作の実行)には、認められたガス消費コストがあります。これらのコストはイーサリアムのホワイトペーパーに記録されています。複数回のEIPの修正を経て、一部のオペコードのGasコストが調整されており、黄皮書とは異なる可能性があります。### 2.ガスの最適化の基本概念Gasの最適化の核心理念は、EVMブロックチェーン上でコスト効率の高い操作を優先し、Gasコストの高い操作を避けることです。EVM の中で、以下の操作コストは低い:- メモリ変数の読み書き- 定数および不変変数を読み取る- ローカル変数の読み書き- calldata 配列や構造体などの calldata 変数を読み取る- 内部関数呼び出しコストが高い操作には、- コントラクトストレージに保存された状態変数の読み書き- 外部関数呼び出し- ループ操作! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス](https://img-cdn.gateio.im/social/moments-187da99010b8fe26c21280bf193d1373)## EVM ガス費用最適化ベストプラクティス上述の基本概念に基づき、私たちは開発者コミュニティのためにガス料金最適化のベストプラクティスリストを整理しました。これらのプラクティスに従うことで、開発者はスマートコントラクトのガス料金消費を削減し、取引コストを低減し、より効率的でユーザーフレンドリーなアプリケーションを構築することができます。### 1.ストレージの使用をできるだけ減らすSolidityにおいて、Storage(ストレージ)は有限な資源であり、そのGas消費はMemory(メモリ)よりもはるかに高いです。スマートコントラクトがストレージからデータを読み書きするたびに、高額なGasコストが発生します。イーサリアムのホワイトペーパーの定義によれば、ストレージ操作のコストはメモリ操作の100倍以上高い。例えば、OPcodesmloadとmstore命令はわずか3ガス単位しか消費しないが、ストレージ操作であるsloadとsstoreは、最も理想的な状況でもコストが少なくとも100単位必要である。制限されたストレージ使用方法には次のものが含まれます:- 非永続的なデータをメモリに保存する- ストレージの変更回数を減らす: 中間結果をメモリに保存し、すべての計算が完了した後に結果をストレージ変数に割り当てる。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス](https://img-cdn.gateio.im/social/moments-b237228ebe933741fb60f2e8bcb384050192837465674839201) 2. 変数パッケージスマートコントラクト中に使用される Storage slot###ストレージスロット(の数および開発者がデータを表示する方法は、Gas 代の消費に大きく影響します。Solidity コンパイラはコンパイルプロセスで連続したストレージ変数をパッケージ化し、32 バイトのストレージスロットを変数のストレージの基本単位として使用します。変数のパッケージ化とは、合理的に変数を配置することによって、複数の変数が単一のストレージスロットに適合できるようにすることを指します。この詳細の調整により、開発者は20,000 Gas単位を節約できます)未使用のストレージスロットを保存するには20,000 Gas(を消費する必要がありますが、現在はわずか2つのストレージスロットしか必要ありません。各ストレージスロットがGasを消費するため、変数のパッケージ化は必要なストレージスロットの数を減らすことによってGasの使用を最適化します。![イーサリアムスマートコントラクトのGas最適化トップ10のベストプラクティス])https://img-cdn.gateio.im/social/moments-30f0bc370a7b9ca65f3d623c31262b76() 3. データタイプの最適化変数はさまざまなデータ型で表現できますが、異なるデータ型に対応する操作コストも異なります。適切なデータ型を選択することで、Gasの使用を最適化するのに役立ちます。例えば、Solidityでは、整数は異なるサイズに細分化できます:uint8、uint16、uint32など。EVMは256ビット単位で操作を実行するため、uint8を使用するとEVMは最初にそれをuint256に変換しなければならず、この変換は追加のGasを消費します。単独で見ると、ここで 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(ですが、それらの構文と構造はまったく異なります。マッピングはほとんどの場合、効率が高くコストが低いですが、配列はイテラブルであり、データ型のパッキングをサポートしています。そのため、データリストを管理する際には、イテレーションが必要な場合やデータ型のパッキングでガス消費を最適化できる場合を除いて、マッピングを優先して使用することをお勧めします。! [イーサリアムスマートコントラクトのガス最適化のためのトップ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 キーワードを使用することをお勧めします。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-c0701f9e09280a1667495d54e262dd2f() 8. オーバーフロー/アンダーフローが発生しないことを確認して Unchecked を使用する開発者が算術演算がオーバーフローやアンダーフローを引き起こさないと確信できる場合、Solidity v0.8.0で導入されたuncheckedキーワードを使用して、余分なオーバーフローやアンダーフローのチェックを避け、Gasコストを節約できます。さらに、0.8.0 以上のバージョンのコンパイラでは、SafeMath ライブラリを使用する必要がなくなりました。なぜなら、コンパイラ自体にオーバーフローおよびアンダーフロー保護機能が組み込まれているからです。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-a823fb7761aafa6529a6c45304e0314b() 9. 最適化モディファイア修飾子のコードは修正された関数に埋め込まれ、修飾子を使用するたびにそのコードがコピーされます。これによりバイトコードのサイズが増加し、ガス消費が増加します。内部関数_checkOwner###(にロジックを再構築することにより、修飾子内でこの内部関数を繰り返し使用できるようになり、バイトコードのサイズを削減し、Gasコストを低減できます。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス])https://img-cdn.gateio.im/social/moments-839b91e2f02389949aa698d460a497d8() 10. ショートサーキット最適化||および&&演算子の場合、論理演算はショートサーキット評価が行われます。つまり、最初の条件が論理式の結果を決定できる場合、2番目の条件は評価されません。Gas 消費を最適化するために、計算コストが低い条件を前に置くべきです。そうすることで、コストの高い計算をスキップできる可能性があります。! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/social/moments-a141884dcdcdc56faff12eee2601b7b7(## 一般的なアドバイスの追加) 1. 無駄なコードを削除する契約内に未使用の関数または変数が存在する場合は、それを削除することをお勧めします。これは契約のデプロイコストを削減し、契約のサイズを小さく保つ最も直接的な方法です。以下は幾つかの実用的なアドバイスです:最も効率的なアルゴリズムを使用して計算を行います。契約内で直接特定の計算結果を使用する場合は、これらの冗長な計算プロセスを排除する必要があります。本質的に、使用されていない計算は削除されるべきです。イーサリアムでは、開発者はストレージスペースを解放することでGas報酬を得ることができます。不要になった変数は、deleteキーワードを使用して削除するか、デフォルト値に設定するべきです。ループ最適化: 高コストのループ操作を避け、可能な限りループを統合し、重複計算をループ本体の外に移動します。### 2. プレコンパイルコントラクトを使用するプリコンパイルされたコントラクトは、暗号化やハッシュ操作などの複雑なライブラリ関数を提供します。コードはEVM上ではなく、クライアントノードのローカルで実行されるため、必要なガスが少なくなります。プリコンパイルコントラクトを使用すると、スマートコントラクトの実行に必要な計算作業量を減らすことでガスを節約できます。プレコンパイルされたコントラクトの例には、楕円曲線デジタル署名アルゴリズム###ECDSA(とSHA2-256ハッシュアルゴリズムが含まれます。スマートコントラクト内でこれらのプレコンパイルされたコントラクトを使用することにより、開発者はガスコストを削減し、アプリケーションの実行効率を向上させることができます。
イーサリアムスマートコントラクトGas費最適化ガイド: 十のベストプラクティスとテクニック
イーサリアムスマートコントラクトのGas最適化ベストプラクティス
イーサリアムメインネットの Gas 料金は常に厄介な問題であり、特にネットワークが混雑しているときにそれが顕著です。ピーク時には、ユーザーはしばしば高額な取引手数料を支払う必要があります。したがって、スマートコントラクト開発段階における Gas 料金の最適化は非常に重要です。Gas 消費を最適化することで、取引コストを効果的に削減できるだけでなく、取引効率も向上し、ユーザーにとってより経済的で効率的なブロックチェーン使用体験を提供します。
本文では、イーサリアム仮想マシン(EVM)のGas費用メカニズム、Gas費用最適化に関するコア概念、及びスマートコントラクト開発時のGas費用最適化のベストプラクティスを概説します。これらの内容を通じて、開発者にインスピレーションと実用的な助けを提供し、一般ユーザーがEVMのGas費用の運用方法をよりよく理解できるよう支援し、ブロックチェーンエコシステムの課題に共に取り組むことを願っています。
EVMのガス料金メカニズムの紹介
EVM 対応ネットワークでは、「ガス」は特定の操作を実行するために必要な計算能力を測定する単位を指します。
EVMの構造レイアウトでは、Gas消費は3つの部分に分かれています: 操作実行、外部メッセージ呼び出し、そしてメモリとストレージの読み書き。
各取引の実行には計算リソースが必要なため、無限ループや拒否サービス(DoS)攻撃を防ぐために一定の手数料が徴収されます。取引を完了するために必要な手数料は「ガス料金」と呼ばれます。
EIP-1559が施行されて以来、Gas料金は以下の公式で計算されています:
ガス料金 = 使用したガスの単位 * (ベース料金 + プライオリティ料金)
基本料金は破棄され、優先料金はインセンティブとして機能し、バリデーターが取引をブロックチェーンに追加することを奨励します。取引を送信する際により高い優先料金を設定すると、次のブロックに取引が含まれる可能性が高まります。これは、ユーザーがバリデーターに対して支払う「チップ」のようなものです。
1. EVM における Gas の最適化を理解する
Solidityでスマートコントラクトをコンパイルすると、コントラクトは一連の"オペコード"、すなわちopcodesに変換されます。
任意のオペコード(、例えば契約の作成、メッセージ呼び出しの実行、アカウントストレージへのアクセス、及び仮想マシン上での操作の実行)には、認められたガス消費コストがあります。これらのコストはイーサリアムのホワイトペーパーに記録されています。
複数回のEIPの修正を経て、一部のオペコードのGasコストが調整されており、黄皮書とは異なる可能性があります。
2.ガスの最適化の基本概念
Gasの最適化の核心理念は、EVMブロックチェーン上でコスト効率の高い操作を優先し、Gasコストの高い操作を避けることです。
EVM の中で、以下の操作コストは低い:
コストが高い操作には、
! イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス
EVM ガス費用最適化ベストプラクティス
上述の基本概念に基づき、私たちは開発者コミュニティのためにガス料金最適化のベストプラクティスリストを整理しました。これらのプラクティスに従うことで、開発者はスマートコントラクトのガス料金消費を削減し、取引コストを低減し、より効率的でユーザーフレンドリーなアプリケーションを構築することができます。
1.ストレージの使用をできるだけ減らす
Solidityにおいて、Storage(ストレージ)は有限な資源であり、そのGas消費はMemory(メモリ)よりもはるかに高いです。スマートコントラクトがストレージからデータを読み書きするたびに、高額なGasコストが発生します。
イーサリアムのホワイトペーパーの定義によれば、ストレージ操作のコストはメモリ操作の100倍以上高い。例えば、OPcodesmloadとmstore命令はわずか3ガス単位しか消費しないが、ストレージ操作であるsloadとsstoreは、最も理想的な状況でもコストが少なくとも100単位必要である。
制限されたストレージ使用方法には次のものが含まれます:
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス](https://img-cdn.gateio.im/webp-social/moments-b237228ebe933741fb60f2e8bcb38405.webp0192837465674839201
) 2. 変数パッケージ
スマートコントラクト中に使用される Storage slot###ストレージスロット(の数および開発者がデータを表示する方法は、Gas 代の消費に大きく影響します。
Solidity コンパイラはコンパイルプロセスで連続したストレージ変数をパッケージ化し、32 バイトのストレージスロットを変数のストレージの基本単位として使用します。変数のパッケージ化とは、合理的に変数を配置することによって、複数の変数が単一のストレージスロットに適合できるようにすることを指します。
この詳細の調整により、開発者は20,000 Gas単位を節約できます)未使用のストレージスロットを保存するには20,000 Gas(を消費する必要がありますが、現在はわずか2つのストレージスロットしか必要ありません。
各ストレージスロットが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に変換しなければならず、この変換は追加のGasを消費します。
単独で見ると、ここで 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(ですが、それらの構文と構造はまったく異なります。
マッピングはほとんどの場合、効率が高くコストが低いですが、配列はイテラブルであり、データ型のパッキングをサポートしています。そのため、データリストを管理する際には、イテレーションが必要な場合やデータ型のパッキングでガス消費を最適化できる場合を除いて、マッピングを優先して使用することをお勧めします。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ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 キーワードを使用することをお勧めします。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-c0701f9e09280a1667495d54e262dd2f.webp(
) 8. オーバーフロー/アンダーフローが発生しないことを確認して Unchecked を使用する
開発者が算術演算がオーバーフローやアンダーフローを引き起こさないと確信できる場合、Solidity v0.8.0で導入されたuncheckedキーワードを使用して、余分なオーバーフローやアンダーフローのチェックを避け、Gasコストを節約できます。
さらに、0.8.0 以上のバージョンのコンパイラでは、SafeMath ライブラリを使用する必要がなくなりました。なぜなら、コンパイラ自体にオーバーフローおよびアンダーフロー保護機能が組み込まれているからです。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-a823fb7761aafa6529a6c45304e0314b.webp(
) 9. 最適化モディファイア
修飾子のコードは修正された関数に埋め込まれ、修飾子を使用するたびにそのコードがコピーされます。これによりバイトコードのサイズが増加し、ガス消費が増加します。
内部関数_checkOwner###(にロジックを再構築することにより、修飾子内でこの内部関数を繰り返し使用できるようになり、バイトコードのサイズを削減し、Gasコストを低減できます。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス])https://img-cdn.gateio.im/webp-social/moments-839b91e2f02389949aa698d460a497d8.webp(
) 10. ショートサーキット最適化
||および&&演算子の場合、論理演算はショートサーキット評価が行われます。つまり、最初の条件が論理式の結果を決定できる場合、2番目の条件は評価されません。
Gas 消費を最適化するために、計算コストが低い条件を前に置くべきです。そうすることで、コストの高い計算をスキップできる可能性があります。
! [イーサリアムスマートコントラクトのガス最適化のためのトップ10のベストプラクティス]###https://img-cdn.gateio.im/webp-social/moments-a141884dcdcdc56faff12eee2601b7b7.webp(
一般的なアドバイスの追加
) 1. 無駄なコードを削除する
契約内に未使用の関数または変数が存在する場合は、それを削除することをお勧めします。これは契約のデプロイコストを削減し、契約のサイズを小さく保つ最も直接的な方法です。
以下は幾つかの実用的なアドバイスです:
最も効率的なアルゴリズムを使用して計算を行います。契約内で直接特定の計算結果を使用する場合は、これらの冗長な計算プロセスを排除する必要があります。本質的に、使用されていない計算は削除されるべきです。
イーサリアムでは、開発者はストレージスペースを解放することでGas報酬を得ることができます。不要になった変数は、deleteキーワードを使用して削除するか、デフォルト値に設定するべきです。
ループ最適化: 高コストのループ操作を避け、可能な限りループを統合し、重複計算をループ本体の外に移動します。
2. プレコンパイルコントラクトを使用する
プリコンパイルされたコントラクトは、暗号化やハッシュ操作などの複雑なライブラリ関数を提供します。コードはEVM上ではなく、クライアントノードのローカルで実行されるため、必要なガスが少なくなります。プリコンパイルコントラクトを使用すると、スマートコントラクトの実行に必要な計算作業量を減らすことでガスを節約できます。
プレコンパイルされたコントラクトの例には、楕円曲線デジタル署名アルゴリズム###ECDSA(とSHA2-256ハッシュアルゴリズムが含まれます。スマートコントラクト内でこれらのプレコンパイルされたコントラクトを使用することにより、開発者はガスコストを削減し、アプリケーションの実行効率を向上させることができます。