⛏️

Solidity 0.8.26での変更点まとめ

2024/05/25に公開

はじめに

初めまして。
CryptoGamesというブロックチェーンゲーム企業でエンジニアをしている cardene(かるでね) です!
スマートコントラクトを書いたり、フロントエンド・バックエンド・インフラと幅広く触れています。

https://cryptogames.co.jp/

代表的なゲームはクリプトスペルズというブロックチェーンゲームです。

https://cryptospells.jp/

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!

https://twitter.com/cardene777

https://chaldene.net/

https://qiita.com/cardene

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

今回はSolidityのバージョン0.8.26が2024年5月21日にリリースされたので、その変更点をまとめていきます。

以下の公式のリリース記事をもとにまとめていきます。

https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

変更点

Solidityのバージョン0.8.26では以下の項目が変更されました。

  • requireでのcustomエラーサポート
  • エンコードサイズが小さいカスタムエラーの最適化
  • 高速なYul Optimizerシーケンス
  • コンパイル時に使用されるJSONライブラリの変更

requireでのcustomエラーサポート

カスタムエラーとは、以下のように任意のエラーを自分で定義できる機能です。

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

contract Solidity0826 {
    uint256 requiredAmount = 0.01 ether;

    error InsufficientBalance(uint256 available, uint256 required);

    function deposit() public payable {
        if (msg.value <= 0.001 ether) {
            revert InsufficientBalance(msg.value, requiredAmount);
        }
    }
}

https://soliditylang.org/blog/2021/04/21/custom-errors/

error InsufficientBalance(uint256 available, uint256 required);

上記でInsufficientBalanceというエラーを定義しておきます。

if (msg.value <= 0.001 ether) {
    revert InsufficientBalance(msg.value, requiredAmount);
}

その後、上記のようにif文などの条件にマッチした場合に、先ほど定義したエラーを返すようにします。

エラーを返すときによく使用されるエラーとしては、requireというものがあります。
こちらの方がより一般的かつ、ガス効率が良いです。

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

contract Solidity0826 {
    uint256 requiredAmount = 0.01 ether;

    error InsufficientBalance(uint256 available, uint256 required);

    function deposit() public payable {
        require(msg.value > 0.001 ether, "InsufficientBalance");
    }
}

上記のrequireでは、msg.value > 0.001 etherという条件に一致しない場合は、InsufficientBalanceというメッセージを返して処理を止めます。
しかし、Solidiry 0.8.25以前まではrequireのメッセージ部分にカスタムエラーを入れることができませんでした。

Solidiry 0.8.26では、ここにカスタムエラーを入れられるようになりました。

// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

contract Solidity0826 {
    uint256 requiredAmount = 0.01 ether;

    error InsufficientBalance(uint256 available, uint256 required);

    function deposit() public payable {
        require(
            msg.value > 0.001 ether ,
            InsufficientBalance(msg.value, requiredAmount)
        );
    }
}

これにより以前のカスタムエラーよりもガス効率が良くなります。

ただ、一点注意が必要です。
それは、コンパイル時にIRパイプライン(Yul経由でのコンパイル)でのみこの機能がサポートされているということです。
IRパイプラインとは、直接コードをバイトコードに変換するのではなく、中間表現(人間が読みやすいコードと機械語の中間に位置する表現形式)に変換して、より効率的なバイトコードを生成するコンパイル方式です。
SolidityではYulという中間表現があります。

https://zenn.dev/heku/books/c28469224e315f/viewer/0799d1

hardhatとremixでのIRパイプラインでのコンパイルをする方法を簡単に説明しておきます。

hardhat

hardhat.config.jsで以下のようにviaIR: true,を追加してください。

hardhat.config.js
solidity: {
  version: "0.8.24", // any version you want
  settings: {
+   viaIR: true,
    optimizer: {
      enabled: true,
      details: {
        yulDetails: {
          optimizerSteps: "u",
        },
      },
    },
  },
}

https://hardhat.org/hardhat-runner/docs/reference/solidity-support

remix

remixでは、compiler_config.jsonに以下のように、"viaIR": true,を追加してください。

compiler_config.json

{
	"language": "Solidity",
	"settings": {
+		"viaIR": true,
		"optimizer": {
			"enabled": true,
			"runs": 200
		},
		"outputSelection": {
			"*": {
			"": ["ast"],
			"*": ["abi", "metadata", "devdoc", "userdoc", "storageLayout", "evm.legacyAssembly", "evm.bytecode", "evm.deployedBytecode", "evm.methodIdentifiers", "evm.gasEstimates", "evm.assembly"]
			}
		}
	}
}

ソースコード

remixで作成したソースコードも載せておきます。

https://gist.github.com/cardene777/fbb3435fe20ea94aed1be9b016824d12

エンコードサイズが小さいカスタムエラーの最適化

これまでカスタムエラーを使用して処理をrevert(中断)する時のコードの最適化には、インラインアセンブリを使用していました。

https://ethereum.stackexchange.com/questions/142752/yul-inline-assembly-revert-with-a-custom-error-message

https://stackoverflow.com/questions/73373480/solidity-yul-inline-assembly-revert-with-custom-error

https://stackoverflow.com/questions/73373480/solidity-yul-inline-assembly-revert-with-custom-error/74704254

https://zenn.dev/heku/books/c28469224e315f/viewer/bce7f7

Solidiry 0.8.26では、引数のないカスタムエラーやメモリ領域に収まる程度のサイズのカスタムエラーの場合、デプロイ段階でガスコストを自動で最適化してくれるようになります。
これにより、インラインアセンプリでカスタムエラーコードを最適化する必要がなくなります。

// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.26;

error ForceFailure();

contract FailureForcer {
    function fail() external pure {
        revert ForceFailure();
    }
}

引数のないカスタムエラーは上記のようなエラーです。

高速なYul Optimizerシーケンス

Yul Optimizerを使用してコンパイルするときのシーケンス(どのように最適化するか)に、新しいデフォルトシーケンスを導入することが決まりました。
新しいデフォルトシーケンスでは、コードの最適化の精度を維持しつつ、コンパイル時間を大幅に短縮しています。

これまでは最適化の手順を複数回繰り返して最適化の機会を増やしていましたが、解析の結果、最初の最適化と最終結果がほとんど変わらないことがわかりました。


引用: https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

そのため、新しいデフォルトシーケンスでは繰り返しの回数を減らして、1回の最適化が行われるように変更されました。


引用: https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

ガス代の効率化も同じように1回の最適化に変換したようです。

これまでのシーケンス

引用: https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

新しいシーケンス

引用: https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

これにより、以下の図のように多くのプロジェクトでコンパイル時間が最大65%まで減少しました。

プロジェクト コンパイル時間の減少率 バイトコードサイズの変化 実行時ガスコストの変化
pool-together -63% -1.29% 未測定
uniswap -53% +1.67% 未測定
zeppelin -47% -0.48% -0.01%
elementfi -42% -1.87% 未測定
euler -34% +1.00% 未測定
yield_liquidator -27% +0.84% +0.14%
ens -22% -1.20% -0.01%
brink -20% +0.61% 未測定
perpetual-pools -16% -0.23% +0.02%
gp2 -12% +0.50% 未測定

注意点として、0.8.21以前のバージョンで問題となった脆弱性があり、新しいデフォルトシーケンスは0.8.22以降で使うようにして、それ以前のバージョンでは古いシーケンスを使用する必要があります。

コンパイル時に使用されるJSONライブラリの変更

コンパイル内部で使用されているJSONライブラリを、jsoncppというライブラリからnlohmann::jsonというライブラリに変更されました。

https://github.com/open-source-parsers/jsoncpp
https://github.com/nlohmann/json

これによりUTF-8エンコーディング(可変長の文字エンコーディング方式)がより厳密になり、不正なUTF-8シーケンスが許容されなくなります。

また、速度も上がる?ようです。

https://github.com/nlohmann/json/issues/1633

その他の変更

その他の細かい修正については以下の記事を参考にしてください。

https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

参考

https://soliditylang.org/blog/2024/05/21/solidity-0.8.26-release-announcement

https://web3blog.playmining.com/solidity-0.8.26

最後に

今回はSolidityのバージョン0.8.26の変更点をまとめました。

以下でも情報発信しているので、興味ある記事があればぜひ読んでみてください!

https://twitter.com/cardene777

https://chaldene.net/

https://qiita.com/cardene

https://cardene.substack.com/

https://mirror.xyz/0xcE77b9fCd390847627c84359fC1Bc02fC78f0e58

https://cardene.notion.site/ERC-EIP-2a03fa3ea33d43baa9ed82288f98d4a9?pvs=4

CryptoGames

Discussion