Solidityのガスコスト節約術

はじめに

スマートコントラクト開発においてガスコストは重要な課題となっています。
プログラミングでも変数パッキングと言う方法でガスコストを節約するできるということで、
どれくらいの削減効果があるかを試してみようと思います。

ストレージ構造の理解

まずはイーサリアムのストレージ構造を理解します。

イーサリアムのストレージは「スロット」と呼ばれる単位で構成されており、
各スロットは32バイト(256ビット)のデータを格納できます。
このスロットの理解が変数パッキングを行う上での基礎となってきます。

ストレージスロットの図

このスロットに対して状態変数を更新するとガスコストが発生します。
新しいストレージスロットに初めて値を書き込む場合(スロットを初期化する場合)は、既に値が設定されているスロットの値を更新する場合よりも大幅にガスコストが高くなります。
○ガスコスト
新しいストレージスロットへの書き込み > 既存スロットの更新

上記を理解して、複数の小さな変数を1つのスロットにまとめることが変数パッキングというものです。

試してみた

2つのコントラクトを作成してガスコストに違いが出るか試してみます。

○効率的な変数宣言

contract EfficientContract {
    uint64 public a;    // 8バイト
    uint64 public c;    // 8バイト
    uint64 public e;    // 8バイト
    uint64 public g;    // 8バイト
    uint256 public b;   // 32バイト
    uint256 public d;   // 32バイト
    uint256 public f;   // 32バイト

図にすると以下のような感じ。

○非効率な変数宣言

contract InefficientContract {
    uint64 public a;    // 8バイト
    uint256 public b;   // 32バイト
    uint64 public c;    // 8バイト
    uint256 public d;   // 32バイト
    uint64 public e;    // 8バイト
    uint256 public f;   // 32バイト
    uint64 public g;    // 8バイト

図にすると以下のような感じ。

ブロックチェーンの状態変更を行う以下の関数を呼び出し、その時のガスコストを比べてみたいと思います。

function setValues(uint64 _a, uint256 _b, uint64 _c, uint256 _d, uint64 _e, uint256 _f, uint64 _g) public {
        a = _a;
        b = _b;
        c = _c;
        d = _d;
        e = _e;
        f = _f;
        g = _g;
}

それぞれ実行したところ以下の結果となりました。(単位はGas Units)

実際のガス代は以下
「実際の支払額(ETH) = Gas Units × Gas Price」
なので、Gas Priceを1Gwei(1 Gwei = 0.000000001 ETH)とすると、
効率化コントラクト:112,994 × 1 Gwei = 112,994 Gwei = 0.000112994 ETH
非効率コントラクト:178,544 × 1 Gwei = 178,544 Gwei = 0.000178544 ETH

1ETH = 370,000円と仮定すると、約24円の差が出てきます。

この効率化は単純なコントラクトでは小さな差に見えるかもしれませんが、複雑なアプリや高頻度で使用されるコントラクトでは、大きなコスト削減につながると思っています。

他にも効率化できるところがないか調査してみようと思います。