Solidity v0.6.0の破壊的変更点
このセクションでは、Solidityバージョン0.6.0で導入された主な変更点と、変更の理由、影響を受けるコードの更新方法について説明します。 完全なリストは リリースチェンジログ を参照してください。
コンパイラが警告しない可能性のある変更点
このセクションでは、コンパイラーが教えてくれないのにコードの動作が変更される可能性のある変更点を挙げます。
指数計算の結果として得られる型は、基数の型です。 以前は、対称演算のように、基数の型と指数の型の両方を保持できる最小の型でした。 さらに、指数の底には符号付きの型が許されています。
明示的な要件
このセクションでは、コードをより明確にする必要があるが、セマンティクスは変わらないという変更点を挙げます。 ほとんどの項目では、コンパイラが提案をしてくれます。
関数は、
virtual
キーワードでマークされているか、インターフェースで定義されている場合にのみオーバーライドできるようになりました。 インターフェースの外で実装されていない関数は、virtual
とマークされなければなりません。 関数やモディファイアをオーバーライドする際には、新しいキーワードoverride
を使用しなければなりません。 複数の並列ベースで定義された関数やモディファイアをオーバーライドする場合、キーワードの後の括弧内にすべてのベースを以下のように記載する必要があります:override(Base1, Base2)
。
配列の
length
へのメンバーアクセスは、ストレージ配列であっても常に読み取り専用になりました。 ストレージ配列の長さに新しい値を割り当ててサイズを変更できなくなりました。 代わりにpush()
、push(value)
、pop()
を使用するか、完全な配列を割り当てると、当然ながら既存のコンテンツは上書きされます。 この理由は、巨大なストレージ配列のストレージ衝突を防ぐためです。
新しいキーワード
abstract
は、コントラクトを抽象的にマークするために使用できます。 これはコントラクトがそのすべての関数を実装していない場合に使用しなければなりません。 抽象コントラクトはnew
演算子を使って作成できませんし、コンパイル時にコントラクト用のバイトコードを生成することもできません。
ライブラリは、内部だけでなく、すべての関数を実装しなければなりません。
インラインアセンブリで宣言された変数の名前は、
_slot
や_offset
で終わることはありません。
インラインアセンブリ内の変数宣言は、インラインアセンブリブロック外の宣言を影で支えることはできません。 名前にドットが含まれている場合、ドットまでの接頭辞はインラインアセンブリブロック外の宣言と衝突してはなりません。
インラインアセンブリでは、引数をとらないオペコードは、独立した識別子ではなく、「組み込み関数」として表現されるようになりました。 つまり、
gas
はgas()
になりました。
状態変数のシャドーイングが禁止されました。派生コントラクトは、そのベースのいずれかに同名の可視状態変数が存在しない場合にのみ、状態変数
x
を宣言できます。
セマンティックかつシンタックスの変更点
このセクションでは、コードを修正する必要があり、その後に何か別のことが行われる変更点をリストアップしています。
外部関数型から
address
への変換は認められなくなりました。 その代わりに、外部関数型は既存のselector
メンバと同様にaddress
というメンバを持ちます。
動的ストレージ配列用の関数
push(value)
は、新しい長さを返さなくなりました(何も返しません)。
一般的に「fallback関数」と呼ばれる無名関数は、
fallback
キーワードで定義される新しいfallback関数と、receive
キーワードで定義されるreceive Ether関数に分割されました。
存在する場合、コールデータが空になるたびに(Etherを受信したかどうかに関わらず)receive Ether関数が呼び出されます。 この関数は暗黙のうちに
payable
です。
新しいフォールバック関数は、他の関数がマッチしない場合に呼び出されます(receive Ether関数が存在しない場合は、コールデータが空のコールも含まれます)。 この関数を
payable
にするかどうかは自由です。payable
でない場合は、値を送信する他の関数にマッチしないトランザクションがリバートします。 新しいフォールバック関数を実装する必要があるのは、アップグレードやプロキシのパターンに従っている場合だけです。
新機能
このセクションでは、Solidity 0.6.0以前では実現できなかったことや、実現が困難だったことを挙げています。
try/catch文 では、失敗した外部呼び出しに反応できます。
struct
およびenum
型は、ファイルレベルで宣言できます。例えば
abi.decode(msg.data[4:], (uint, uint))
は関数呼び出しのペイロードをデコードする低レベルな方法です。Natspecは開発者向けドキュメントで複数のリターンパラメータをサポートし、
@param
と同じネーミングチェックを実施します。YulとInline Assemblyには、現在の関数を終了させる
leave
という新しい文があります。address
からaddress payable
への変換はpayable(x)
を介して可能になりました。
インターフェースの変更点
このセクションでは、言語そのものとは関係なく、コンパイラーのインターフェースに影響を与える変更点を紹介します。 これらの変更により、コマンドラインでのコンパイラの使用方法、プログラマブルインターフェースの使用方法、コンパイラが生成した出力の分析方法が変わる可能性があります。
新しいエラーリポーター
新しいエラーレポーターが導入されました。
これは、コマンドライン上でよりアクセスしやすいエラーメッセージを生成することを目的としています。
デフォルトでは有効になっていますが、 --old-reporter
を指定すると、非推奨の古いエラーレポーターに戻ります。
メタデータハッシュオプション
コンパイラは、メタデータファイルの IPFS ハッシュをデフォルトでバイトコードの最後に追加するようになりました(詳細については、 コントラクトメタデータ のドキュメントを参照してください)。
0.6.0より前のバージョンでは、コンパイラはデフォルトで Swarm ハッシュを付加していましたが、この動作を引き続きサポートするために、新しいコマンドラインオプション --metadata-hash
が導入されました。
--metadata-hash
コマンドラインオプションの値として ipfs
または swarm
を渡すことで、生成および付加されるハッシュを選択できます。
none
という値を渡すと、ハッシュが完全に削除されます。
これらの変更は、 標準JSONインターフェース を介して使用することもでき、コンパイラによって生成されるメタデータJSONに影響を与えます。
推奨されるメタデータの読み方は、最後の2バイトを読んでCBORエンコーディングの長さを判断し、 メタデータのセクション で説明されているようにそのデータブロックに対して適切なデコーディングを行うことです。
Yulオプティマイザ
レガシーのバイトコードオプティマイザとともに、 Yul オプティマイザが --optimize
でコンパイラーを呼び出したときにデフォルトで有効になりました。
これを無効にするには、 --no-optimize-yul
でコンパイラを呼び出します。
これは主に ABI coder v2 を使用しているコードに影響します。
C APIの変更点
libsolc
のC APIを使用するクライアントコードは、コンパイラが使用するメモリを制御するようになりました。
この変更に一貫性を持たせるために、 solidity_free
は solidity_reset
に改名され、関数 solidity_alloc
と solidity_free
が追加され、 solidity_compile
は solidity_free()
を介して明示的に解放しなければならない文字列を返すようになりました。
コードのアップデート方法
このセクションでは、全ての変更点のために以前のコードを更新する方法を詳しく説明しています。
f
が外部関数型のため、address(f)
をf.address
に変更してください。
function () external [payable] { ... }
をreceive() external payable { ... }
、fallback() external [payable] { ... }
のいずれか、または両方で置き換えてください。 可能な限り、receive
関数のみを使用してください。
uint length = array.push(value)
をarray.push(value);
に変更してください。 新しい長さはarray.length
からアクセスできます。
ストレージ配列の長さを増やすには
array.length++
をarray.push()
に変更し、減らすにはpop()
を使用してください。
関数の
@dev
ドキュメントでは、名前のついたリターンパラメータごとに、パラメータの名前を最初の単語として含む@return
エントリを定義します。 例えば、関数f()
がfunction f() public returns (uint value)
のように定義されていて、それに注釈をつけた@dev
がある場合、その戻りパラメータを次のように文書化します:@return value The return value.
。 タプルの戻り値の型に表示されている順序で通知を行う限り、名前のある戻り値パラメータと名前のない戻り値パラメータの文書を混在させることができます。
インラインアセンブリ内の変数宣言には、インラインアセンブリブロック外の宣言と衝突しないように、一意の識別子を選択してください。
オーバーライドしようとするすべての非インタフェース関数に
virtual
を追加してください。 インターフェースの外にある実装のないすべての関数にvirtual
を追加してください。 単一継承の場合は、オーバーライドするすべての関数にoverride
を追加してください。 多重継承の場合は、override(A, B, ..)
を追加し、オーバーライドする関数を定義するすべてのコントラクトを括弧内に列挙してください。 複数のベースが同じ関数を定義している場合、継承するコントラクトは、競合するすべての関数をオーバーライドしなければなりません。
インラインアセンブリでは、引数を受け付けないすべてのオペコードに
()
を追加してください。 例えば、pc
をpc()
に、gas
をgas()
に変更してください。