ブロックチェーン上のスマートコントラクトを開発するに当たって実行コストである「ガス代」を削減することは重要な事です。消費Gasを削減するためのいくつかの有名なトリック があるのですが、そのうちの一つに「ストレージ変数の変更を避ける(Avoid changing storage data)」というのがあります。
例えばUniswapV2のスマートコントラクトにはこんな感じでgas savings
のトリックが至る所に施されています。
自分でスマートコントラクトを書いたり、レビューしたりするときにはこの点常に気をつけているのですが、先日ふと「これあまりにも古典的なトリックなので、すでにSolidityのオプティマイザで解決されてるのでは?」と思い、最新のSolidityコンパイラ0.8.11
で検証してみました。
検証したスマートコントラクト
Hardhatプロジェクトを作成し、以下のようなスマートコントラクトを書きました。 検証ソースコード一式
counter1()
はガス最適化していないコード、counter2()
はガス最適化したコードです。違いはローカル変数(memory)j
にStorage変数counter
をコピーしてj
でカウントした結果をcounter
に戻しています。
テストコード
ガス測定のコードは以下のとおり
ガス代の測定
ガス代の測定のために便利なHardhatプラグインhardhat-gas-reporter を使います
インストールは以下のとおり
$ yarn add --dev hardhat-gas-reporter
としてhardhat.confg.js
の冒頭にrequire("hardhat-gas-reporter");
を追加。
設定は、hardhat.confg.js
にgasReporter
を追加します。ここで環境変数CMC_API_KEY
にCoinmarketcap
のAPIキーを設定するとUSD換算した費用がレポートされます。
module.exports = {
....
gasReporter: {
currency: "USD",
gasPrice: 100,
coinmarketcap: process.env.CMC_API_KEY,
},
};
検証
準備ができたので早速検証していきます。まずSolidityのオプティマイザを利用せずに実行してみます。
$ npx hardhat test
結果は以下のようになりました
Solidityのオプティマイザ無し
コード最適化無し(counter1): 630,118
コード最適化有り(counter2): 407,289 (-25%)
25%ほどガスが削減できているようです、これはほぼ予想通りです。
次にSolidityのオプティマイザをオン(runs:1,000)にしてみます。
結果は以下のようになりました
Solidityのオプティマイザ有り
コード最適化無し(counter1): 439,118
コード最適化有り(counter2): 218,271 (-50%)
Solidityのオプティマイザ有り/無しともに大きくガスの節約ができていますが、やはりコード最適化による効果は大きいようです。
結論
この「ストレージ変数の変更回数を避ける」というガス削減トリックは、最新のSolidityのオプティマイザを有効にしてもいまだに有効ということが分かりました。ストレージ変数の変更には引き続き注意を払いましょう。