ETH坊スマートコントラクトのGas最適化の10のベストプラクティス

ETH坊メインネットのガス料金は、常に大きな問題であり、特にネットワークの混雑時には顕著です。ピーク時には、ユーザーは非常に高い取引手数料を支払う必要があります。そのため、スマートコントラクトの開発段階でガスの消費を最適化することは非常に重要です。ガスの最適化は、取引のコストを効果的に削減するだけでなく、取引効率を向上させ、ユーザーに経済的かつ効率的なブロックチェーンの使用体験をもたらします。

この文書では、ETH坊仮想マシン(EVM)のガス料金メカニズム、ガス料金の最適化に関連する核心的な概念、およびスマートコントラクトの開発時におけるガス料金の最適化のベストプラクティスについて概説します。これらの内容を通じて、開発者に洞察と実用的な支援を提供し、一般ユーザーがEVMのガス料金の動作方法をより良く理解し、ブロックチェーンエコシステムの課題に共に取り組むことを目指します。

EVM のガス料金メカニズムの概要

EVM 互換ネットワークでは、「Gas」とは特定の操作を実行するために必要な計算能力を測定するための単位です。

下図はEVMの構造レイアウトを示しています。図中、Gas消費は3つの部分に分かれています:操作実行、外部メッセージの呼び出し、メモリとストレージの読み書き。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

出典:イーサリアム公式サイト[1]

1つのトランザクションの実行には計算リソースが必要であるため、無限ループやサービス拒否(DoS)攻撃を防止するために一定の手数料がかかります。トランザクションを完了するために必要な費用は「ガス料」と呼ばれています。

EIP-1559(ロンドンハードフォーク)の実装以降、Gas料金は以下の式で計算されます:

ガス料金=ガス使用量の単位*(基本料金+優先料金)

基本料金は破棄され、優先料金はインセンティブとして機能し、検証者に取引をブロックチェーンに追加するよう奨励します。取引時により高い優先料金を設定すると、次のブロックに取引が含まれる可能性が高まります。これはユーザーが検証者に支払う一種の「チップ」のようなものです。

1.EVMにおけるガス最適化の理解

Solidityを使用してスマートコントラクトをコンパイルすると、契約は一連の「オペコード」、つまりオペコードに変換されます。

任意の操作コード(例えば契約の作成、メッセージの呼び出し、アカウントストレージへのアクセス、および仮想マシンでの実行)には、公認のガス消費コストがあり、これらのコストはETHブロックチェーンイエローペーパー[2]に記録されています。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

複数のEIPの修正後、一部のオペコードのガスコストが調整され、イエローペーパーと異なる場合があります。オペコードの最新コストの詳細については、こちら[3]を参照してください。

2.ガス最適化の基本概念

Gasの最適化の核心的な理念は、EVMブロックチェーンでコスト効率の高い操作を優先し、コストの高いGas操作を避けることです。

EVM内では、以下の操作はコストが低くなります:

  • メモリ変数の読み書き *定数と不変変数の読み取り
  • ローカル変数の読み書き
  • calldata 配列や構造体などの calldata 変数を読み取る *内部関数呼び出し

コストの高い操作には、次のものが含まれます:

  • コントラクトストレージに格納されている状態変数の読み書き
  • 外部関数呼び出し
  • ループ操作

EVMガス料金の最適化のベストプラクティス

上記の基本概念に基づいて、開発者コミュニティ向けにGas料金の最適化ベストプラクティスリストをまとめました。これらのプラクティスに従うことで、開発者はスマートコントラクトのGas料金消費を低減し、取引コストを削減し、より効率的でユーザーフレンドリーなアプリケーションを構築することができます。

1.できるだけストレージ使用を減らす

Solidityでは、ストレージは有限なリソースであり、ガス消費量はメモリよりもはるかに高いです。スマートコントラクトがストレージからデータを読み取ったり書き込んだりするたびに、高額のガスコストが発生します。

イーサリアム黄皮書によると、ストレージ操作のコストはメモリ操作の100倍以上です。例えば、OPcodesmloadとmstore命令はわずか3ガス単位を消費しますが、sloadとsstoreなどのストレージ操作は、最も理想的な状況でも少なくとも100単位のコストがかかります。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

制限されたストレージの使用方法には、次のものが含まれます:

  • 非永続的なデータをメモリに保存する
  • ストレージの変更回数を減らす:中間結果をメモリに保存し、すべての計算が完了した後に結果をストレージ変数に割り当てます。

2. 変数のパッキング

スマートコントラクト中で使用されるStorage slot(ストレージスロット)の数と、開発者がデータを表現する方法は、Gas料金の消費に大きく影響します。

Solidityコンパイラは、コンパイルプロセス中に連続するストレージ変数をパッキングし、32バイトのストレージスロットを変数の基本単位として使用します。変数のパッキングとは、変数を適切に配置することにより、複数の変数を単一のストレージスロットに適応させることを指します。

左側は効率が低い実装方法で、3つのストレージスロットが消費されます。右側はより効率的な実装方法です。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

この微調整により、開発者は20,000のガス単位を節約できます(未使用のストレージスロットを保存するには20,000ガスが必要です)、しかし現在は2つのストレージスロットだけが必要です。

各ストレージスロットはガスを消費するため、変数パッキングは必要なストレージスロットの数を減らすことでガスの使用を最適化します。

3. データ型の最適化

1つの変数は複数のデータ型で表すことができますが、異なるデータ型には異なる操作コストがかかります。適切なデータ型を選択することで、Gasの使用を最適化するのに役立ちます。

例えば、Solidityでは整数をさまざまなサイズに細分することができます:uint8、uint16、uint32など。EVMは256ビット単位で操作を実行するため、uint8を使用すると、EVMはまずuint256に変換する必要がありますが、この変換には追加のガスがかかります。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

uint8とuint256のガスコストを比較するために、コード内のUseUint()関数は120,382のガスを消費し、UseUInt8()関数は166,111のガスを消費します。

単独で見ると、ここでは uint256 を使用する方が uint8 よりも安価です。ただし、私たちが以前提案した変数のパッキング最適化を使用する場合は異なります。開発者が4つの uint8 変数を1つのストレージスロットにパックできる場合、それらを反復処理する合計コストは4つの uint256 変数よりも低くなります。これにより、スマートコントラクトは1回のストレージスロットの読み書きを行い、4つの uint8 変数を1回の操作でメモリ/ストレージに配置することができます。

4. 固定サイズの変数を使用して可変サイズの変数を置き換える

もしデータが32バイト以内で制御できるなら、bytesまたはstringsの代わりにbytes32データ型を使用することをお勧めします。一般的に、固定サイズの変数の方が可変サイズの変数よりもガスを消費しません。バイト長を制限できる場合は、できるだけbytes1からbytes32までの最小長さを選択してください。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

5. マッピングと配列

Solidityのデータリストは、配列(Arrays)とマッピング(Mappings)の2つのデータタイプで表現できますが、それらの文法と構造はまったく異なります。

ほとんどの場合、マッピングは効率が高くコストが低くなりますが、配列は反復可能でデータ型のパッキングもサポートしています。したがって、データリストを管理する場合は、反復が必要ないか、データ型のパッキングによるガス消費を最適化できる場合を除いて、マッピングを優先して使用することをお勧めします。

6. メモリの代わりに calldata を使用する

関数のパラメータで宣言された変数は、calldataまたはmemoryに格納できます。両者の主な違いは、memoryは関数によって変更可能であり、calldataは不変です。

この原則を覚えておいてください:関数の引数が読み取り専用の場合は、memoryではなくcalldataを優先して使用する必要があります。これにより、calldataからmemoryへの不要なコピー操作を回避することができます。

例 1: メモリの使用

​! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

memory キーワードを使用すると、配列の値は ABI デコードプロセス中に、コーディングされた calldata から memory にコピーされます。このコードブロックの実行コストは 3,694 ガス単位です。

例 2: calldata の使用

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

直接calldataから値を読み取る場合、memory操作をスキップします。この最適化により、実行コストはわずか2,413ガスユニットに低減し、ガス効率が35%向上しました。

7. 可能な限り Constant/Immutable キーワードを使用する

Constant/Immutable変数は契約のストレージに保存されません。これらの変数はコンパイル時に計算され、契約のバイトコードに保存されます。したがって、ストレージと比較して、アクセスコストははるかに低くなりますので、できるだけConstantまたはImmutableキーワードを使用することをお勧めします。

8. 溢れ/アンダーフローが発生しないことを確認する場合にのみ、Uncheckedを使用

開発者が算術演算がオーバーフローやアンダーフローを引き起こさないことを確認できる場合、Solidity v0.8.0で導入されたuncheckedキーワードを使用して余分なオーバーフローやアンダーフローチェックを回避し、ガスコストを削減できます。

図の中で、条件制約が i によって与えられる

! Top 10 Best Practices for Gas Optimization in ETH坊スマートコントラクト

また、0.8.0以上のコンパイラでは、オーバーフローおよびアンダーフロー保護機能がコンパイラ自体に組み込まれているため、SafeMathライブラリは不要になりました。

9. 修正された最適化

修飾子のコードは変更された関数に埋め込まれ、修飾子を使用するたびにそのコードがコピーされます。これによりバイトコードのサイズが増大し、Gas 消費が増加します。修飾子 Gas コストを最適化する方法の一例は次のとおりです:

以前は:

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

後:

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

この場合、ロジックを組み込み関数_checkOwner()にリファクタリングし、その組み込み関数を修飾子で再利用できるようにすることで、バイトコードサイズとガスコストを削減できます。

10. ショートカットの最適化

||および&&演算子に対して、論理演算は短絡評価が行われ、すなわち最初の条件で論理式の結果が確定できる場合、2番目の条件は評価されません。

Gasの消費を最適化するために、コストの低い条件を前に置くことで、高コストの計算をスキップする可能性があります。

一般的なアドバイスを追加します

1. 不要なコードの削除

契約に未使用の関数や変数がある場合は、削除することをお勧めします。これは契約の展開コストを削減し、契約のサイズを小さく保つための最も直接的な方法です。

以下はいくつかの実用的なアドバイスです:

最も効率的なアルゴリズムを使用して計算します。契約に直接計算結果を使用する場合、余分な計算プロセスを削除する必要があります。本質的には、使用されていない計算はすべて削除されるべきです。

イーサリアム坊では、開発者はストレージスペースを解放することでガスリワードを得ることができます。変数が不要になった場合は、deleteキーワードを使用して削除するか、デフォルト値に設定する必要があります。

ループの最適化:高コストのループ操作を避け、可能な限りループを統合し、繰り返し計算をループ体の外に移動します。

2. プリコンパイルされたスマートコントラクトの使用

プリコンパイル契約は、暗号化やハッシュ操作などの複雑なライブラリ関数を提供します。 EVM上でコードが実行されるのではなく、クライアントノードでローカルに実行されるため、必要なGasが少なくなります。プリコンパイル契約を使用することで、スマートコントラクトの実行に必要な計算作業量を減らすことでGasを節約できます。

プリコンパイル契約の例には、楕円曲線デジタル署名アルゴリズム(ECDSA)と SHA2-256 ハッシュアルゴリズムが含まれます。これらのプリコンパイル契約をスマートコントラクトで使用することで、開発者はガスコストを削減し、アプリケーションの実行効率を向上させることができます。

ETHブロックチェーンでサポートされているプリコンパイル済みスマートコントラクトの完全なリストについては、こちら[4]をご参照ください。

3. インラインアセンブリコードの使用

インラインアセンブリ(in-line assembly)は、EVMで直接実行可能な低レベルかつ効率的なコードを開発者が記述できるようにし、高価なSolidityオペコードを使用する必要がなくなります。インラインアセンブリは、メモリとストレージの使用をより正確に制御することも可能であり、それによりGas料金をさらに削減できます。さらに、インラインアセンブリを使用することで、Solidityでは実現が難しいいくつかの複雑な操作を実行でき、Gas消費の最適化に対する柔軟性を提供します。

以下はガスを節約するためのインラインアセンブリを使用したコードの例です:

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

上図からわかるように、標準のユースケースと比較して、インラインアセンブリ技術を使用した第2のユースケースは、より高いガス効率を持っています。

しかし、インラインアセンブリを使用することは、リスクを伴い、エラーが発生しやすい場合があります。したがって、経験豊富な開発者に限定して、注意して使用する必要があります。

4. Layer 2 ソリューションを使用する

Layer 2のソリューションを使用すると、ETHメインネット上でのデータのストレージと計算が削減されます。

ロールアップ、サイドチェーン、状態チャネルなどのLayer 2ソリューションにより、トランザクション処理をメインのETHチェーンからアンロードして、より高速かつ安価なトランザクションを実現することができます。

大量な取引をまとめることで、これらのソリューションはチェーン上の取引量を減らし、ガス料金をドロップさせます。Layer 2 ソリューションを使用することで、ETHリアムのスケーラビリティが向上し、より多くのユーザーやアプリケーションがネットワークに参加できるようになり、ネットワークの過負荷による渋滞が引き起こされることはありません。

5. 最適化ツールとライブラリの使用

複数の最適化ツールが利用可能であり、例えばsolcオプティマイザ、Truffleのビルドオプティマイザ、およびRemixのSolidityコンパイラが挙げられます。

! イーサリアムスマートコントラクトのガス最適化のためのベストプラクティストップ10

これらのツールは、バイトコードのサイズを最小限に抑え、不要なコードを削除し、スマートコントラクトの実行に必要な操作回数を減らすのに役立ちます。他のGas最適化ライブラリ「solmate」と組み合わせることで、開発者はGasコストを効果的に削減し、スマートコントラクトの効率を向上させることができます。

まとめ

Gasの消費を最適化することは、開発者にとって重要なステップであり、取引コストを最小化し、EVM互換ネットワーク上のスマートコントラクトの効率を向上させることができます。コストを削減する操作を優先的に実行し、ストレージ使用量を減らし、インラインアセンブリを利用し、本文で議論されたその他のベストプラクティスに従うことにより、開発者は契約のGas消費を効果的に削減することができます。

しかし、最適化の過程で注意する必要があります。開発者は慎重に操作する必要があり、セキュリティの脆弱性を導入しないようにする必要があります。コードの最適化とGas消費の削減の過程で、スマートコントラクト固有のセキュリティを決して犠牲にすべきではありません。

[1] :

[2] :

[3] :

[4] :p再コンパイル済み

ETH3.04%
GAS13.24%
原文表示
このページには第三者のコンテンツが含まれている場合があり、情報提供のみを目的としております(表明・保証をするものではありません)。Gateによる見解の支持や、金融・専門的な助言とみなされるべきものではありません。詳細については免責事項をご覧ください。
  • 報酬
  • 1
  • 共有
コメント
0/400
IELTSvip
· 2024-12-31 01:14
2024年の急速かつ大幅な上昇により、ブラックロックのビットコインETF「IBIT」は「ETF史上最大のローンチ」であると報告されています。 " #圣诞冒险岛:喜迎新年,$50,000福利派送中# #2024 Gate.io 年度账单# #荣誉积分新年抽奖,赢Macbook、周边好礼# BSV ETH ethw etcDoge XRP adapepe
原文表示返信0
いつでもどこでも暗号資産取引
qrCode
スキャンしてGateアプリをダウンロード
コミュニティ
日本語
  • 简体中文
  • English
  • Tiếng Việt
  • 繁體中文
  • Español
  • Русский
  • Français (Afrique)
  • Português (Portugal)
  • Bahasa Indonesia
  • 日本語
  • بالعربية
  • Українська
  • Português (Brasil)