はじめに

初めまして。 『DApps開発入門』という本や色々記事を書いているかるでねです。

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

今回はSolidityのバージョン0.8.28での変更点をまとめていきます。

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

変更点

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

  • Transientストレージ変数の完全サポート
  • Yul ASTのJSON生成をオンデマンド化
  • コントラクトごとのパイプラインの設定
  • バグ修正とその他の改善

Transientストレージ変数の完全サポート

Solidity 0.8.28では、「Transientストレージ変数」と呼ばれる一時的なストレージ変数が正式にサポートされました。 Version 0.8.27では、Transient変数の構文自体は解析されていましたが、バイトコードを生成することはできなかったです。 今回のリリースにより、Transientストレージ変数を完全にサポートしてバイトコード生成が可能になりました。

Transientストレージとは?

通常、Solidityのストレージ変数は、ブロックチェーン上の永続的なデータとして保存されますが、Transientストレージは一時的な保存領域を提供します。 memoryやcalldataなど一時的なデータ保存領域は他にもあり効率的なメモリ管理が可能になります。

例えば、計算の途中で一時的にデータを保存してその後不要になったタイミングでデータを廃棄するような場合、Transientストレージは非常に有効です。 従来のストレージ変数を使うと、そのデータは永続的に保存されてしまうため、ブロックチェーンのストレージを無駄に使用することになります。

ストレージレイアウトとTransientストレージレイアウトは独立しているため、ストレージからTransientストレージに変換された場合にその変数が使用していた場所が空になり、その後ストレージに保存する変数の場所がズレてストレージレイアウトが崩れる可能性があります。

これを防ぐために、例えばストレージ変数をTransientに変換した場合、その変数が元々存在していた位置にダミーの変数を挿入する必要があります。 これにより、ストレージレイアウトが崩れるのを防ぎます。

Yul ASTのJSON生成をオンデマンド化

Yulとは?

複雑なSolidityのコードを、より効率的な低レベルのコードに変換するために使用されます。 Yulは最適化しやすい構造を持っているため、パフォーマンスを向上させることができます。

オンデマンド化とは?

必要なときにだけ処理やデータ生成を行うこと。 ここでは、SolidityコンパイラーがYul AST(抽象構文木)のJSONデータを、ユーザーが明示的に要求したときにだけ生成する仕組みに変更したことを意味します。

Yul ASTは、Yulコードをツリー形式で表現したもので、コードの各部分(関数、変数、条件式など)をノードとして階層的に整理したものです。 これにより、コンパイラーがコードの構造を効率的に解析し、最適化やバイトコード生成が可能になります。

Solidityコンパイラーは、出力データ(ABIやメタデータなど)を内部的にキャッシュします。 これにより、ABIとメタデータの両方を同時にリクエストした場合、同じデータが重複して生成されることを防いで効率的なコンパイルが可能になります。

しかし、Yul ASTのような新しく導入された大きなデータも、明示的にリクエストされなくてもキャッシュされてしまう問題がありました。 大規模プロジェクトでは、この問題により大量のメモリを消費するにもかかわらず、パフォーマンスの向上に結びつかず効率が良くない状態でした。

バージョン0.8.28では、この問題を解決して以下の改善が行われました。

  • キャッシュの削減
    • 必要ない場合はYul ASTを生成せずメモリ使用量を大幅に削減。
    • これにより、メモリの消費が最大で80%削減。
  • コンパイル時間の短縮
    • Yul ASTの不要な生成を防ぎコンパイル時間を最大で25%短縮。
File Time (v0.8.27) Time (v0.8.28) Change
openzeppelin 40 s 35 s -13%
uniswap-v4 157 s 128 s -18%
eigenlayer 716 s 545 s -24%
File Memory (0.8.27) Memory (0.8.28) Change
openzeppelin 1220 MiB 506 MiB -59%
uniswap-v4 4805 MiB 1496 MiB -69%
eigenlayer 20346 MiB 4455 MiB -78%

コントラクトごとのパイプラインの設定

Solidityコンパイラーは「遅延評価」という仕組みを持っており、必要な部分だけを実行して出力を生成します。 必須の処理は「解析」と「分析」段階でエラーを検出し、ABI(アプリケーションバイナリインターフェース)、メタデータ、Solidity AST(抽象構文木)、ストレージレイアウトなどの情報が得られます。 もしバイトコードやIR(中間表現)が不要であれば、コード生成や最適化のステージはスキップされます。

これまでの仕組みでは、コンパイルの時に全てのコントラクトに対して同じパイプラインが適用されていました。 そのため、例えば1つのコントラクトに対してバイトコードをリクエストしたとしても、他の全てのコントラクトに対してもバイトコードが生成されていました。 これにより、不要な作業が増え、コンパイル時間が長くなってしまう問題がありました。

バージョン0.8.28では、この制限が解除されてr特定のコントラクトに対してのみ必要なステージを実行できるようになりました。 あるコントラクトでバイトコードが必要な場合でも、他のコントラクトでは必要ない場合はそれらのコントラクトのバイトコード生成はスキップされます。 これにより、無駄な処理が減り、コンパイル全体の効率が向上します。

この変更は、全てのコントラクトに同じ出力を求めるようなシンプルなコンパイル作業にはあまり影響を与えません。 しかし、フレームワークなどを使ってより高度なワークフローを実装する場合など、コードの一部だけが変更される場合に再コンパイル作業がより迅速になります。

この変更はStandard JSONインターフェース(Solidityコンパイラーの標準的なJSON形式のインターフェース)にのみ適用され、CLIではコントラクトごとの出力選択はまだサポートされていません。

その他の変更

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

最後に

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

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