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