スマートコントラクトの検証
最終編集者: @miyamok(opens in a new tab), 2023年11月23日
スマートコントラクト は「トラストレス」なものとして設計されています。つまり、ユーザーはスマートコントラクトとやりとりをする前に、第三者(デベロッパーや企業など)を信頼する必要はありません。 トラストレスであることを確保するためには、ユーザーやその他のデベロッパーがスマートコントラクトのソースコードを検証できるようにする必要があります。 ソースコード検証により、ユーザーとデベロッパーは、公開されたコントラクトコードが、イーサリアムブロックチェーン上のコントラクトアドレスで実行されているのと同じコードであることを確認できます。
「ソースコード検証」と「形式的検証」を区別することは重要です。 以下で詳述するソースコード検証とは、高級言語(Solidityなど)で書かれたスマートコントラクトのソースコードをコンパイルしたものが、コントラクトアドレスで実行されるバイトコードと一致するかどうかを検証する手法ですが、 形式的検証は、スマートコントラクトの正しさ、つまり、スマートコントラクトが意図したとおりに動作することを検証するものです。 コントラクト検証とは、文脈にもよりますが、一般的にはソースコード検証を指します。
ソースコード検証とは
スマートコントラクトをイーサリアム仮想マシン(EVM)にデプロイする前に、デベロッパーはスマートコントラクトのソースコード(Solidityもしくは他の高級プログラミング言語で書かれた命令)をバイトコードにコンパイルします。 EVMは高級言語による命令を解釈できないため、EVM内でスマートコントラクトのビジネスロジックを実行するには、ソースコードをバイトコード(すなわち低級のマシン命令)にコンパイルする必要があります。
ソースコード検証とは、スマートコントラクトの作成時に使用したソースコードと、実行時にコンパイルされたバイトコードを比較して、違いを検出することです。 公表されたスマートコントラクトのコードと、ブロックチェーン上で実行されるコードが異なる可能性があるため、スマートコントラクトの検証は重要な作業となります。
スマートコントラクト検証では、マシンコードを読むことなく、スマートコントラクトが書かれた高級言語を通してスマートコントラクトの挙動を調査することができます。 関数、値、そして通常は変数名とコメントは、コンパイルやデプロイを行っても、元のソースコードと同じままです。 そのため、コードの読解がとても簡単になります。 ソース検証は、コードのドキュメンテーションも規定するため、エンドユーザーはスマートコントラクトが何を行うように設計されているのかを理解することができます。
全検証とは何か
ソースコードには、コメントや変数名など、コンパイル後のバイトコードに影響しない部分があります。 そのため、変数名やコメントが異なるソースコードでも、同じスマートコントラクトを検証することができます。 これを悪用して、ソースコードに嘘のコメントや誤解を招く変数名を与えて、元のソースコードとは別のコードでスマートコントラクトを検証することができます。
ソースコードと正確に一致していることを暗号学的に保証したり、コンパイル情報のフィンガープリントをバイトコードに追加したりすることで、この問題を回避できます。 必要な情報は、Solidityのコントラクトメタデータ(opens in a new tab)に含まれており、このファイルのハッシュは、コントラクトのバイトコードに追加されます。 この動作は、メタデータのプレイグラウンド(opens in a new tab)で確認できます。
メタデータファイルには、ソースファイルとそのハッシュを含む、スマートコントラクトのコンパイルに関する情報が含まれています。 コンパイル設定やソースファイルの1つが1バイトでも変更されると、メタデータファイルも変更されます。 そのため、バイトコードに付加されるメタデータファイルのハッシュも変更されます。 つまり、スマートコントラクトのバイトコードと付加されたメタデータハッシュが、指定されたソースコードおよびコンパイル設定と一致する場合、このソースコードは元のコンパイルで使われたものと完全に一致しており、1バイト単位で変更されていないことを確認できるのです。
メタデータハッシュを活用するこのタイプの検証は、"全検証(opens in a new tab)"(または「完全検証」)と呼ばれます。 一方、メタデータハッシュが一致しない、または検証で考慮されていない場合は「部分一致」と呼ばれ、現在ではこれがより一般的なスマートコントラクト検証の方法です。 全検証をしない場合は、検証されたソースコードに表れない悪意のあるコードを挿入(opens in a new tab)することが可能です。 しかし、ほとんどのデベロッパーは全検証を知らないうえに、コンパイルのメタデータファイルを保持していないため、現実的には部分検証がスマートコントラクト検証の主流となっています。
ソースコード検証が重要な理由
トラストレス性
トラストレス性は、スマートコントラクトと分散型アプリケーション(dapps)の最も重要な前提条件です。 スマートコントラクトは「不変」で、変更することはできません。そのため、スマートコントラクトは、デプロイ時にコードで定義されているビジネスロジックのみを実行します。 つまり、デベロッパーや企業は、イーサリアムにデプロイした後に、スマートコントラクトのコードを改ざんすることはできません。
スマートコントラクトがトラストレスとなるためには、そのコードが独立した検証のために公開されている必要があります。 しかし、ブロックチェーン上で公開されているスマートコントラクトのコンパイル済みバイトコードは、デベロッパーやユーザーにとって理解するのが難しい低水準言語で書かれています。
スマートコントラクトのソースコードを公開することで、信頼を前提とする必要性が減ります。 しかし、これには別の問題があり、公開されたソースコードがスマートコントラクトのバイトコードと一致するかどうかを検証することが難しくなります。 このシナリオでは、ユーザーは、デベロッパーがスマートコントラクトをブロックチェーンにデプロイする前に、ビジネスロジックが変更されていない(つまり、バイトコードが変更されていない)ことを信頼する必要があります。そのため、トラストレス性の価値が失われます。
ソースコード検証ツールは、スマートコントラクトのソースコードファイルとアセンブリコードの一致を保証します。 これにより、トラストレスなエコシステムで、ユーザーはやみくもに第三者を信頼することなく、スマートコントラクトに資金を預ける前にコードを検証することができます。
ユーザーの安全性
スマートコントラクトには、通常、高額のコストがかかります。 そのため、より高いセキュリティが求められ、使用前のスマートコントラクトのロジックの検証が必須となります。 問題は、悪意のある開発者がスマートコントラクトに悪意のあるコードを混ぜて、ユーザーを騙す可能性があることです。 検証を行わないと、悪意のあるスマートコントラクトには、ユーザーの安全性を脅かす問題が潜んだままの状態になります。例えば、バックドア(opens in a new tab)や、物議をかもすようなアクセスコントロール機構、悪用されうる脆弱性などです。
スマートコントラクトのソースコードファイルを公開すると、監査役など、潜在的な攻撃媒介を評価する者は、スマートコントラクトの評価を容易に行うことができます。 複数の当事者が独自にスマートコントラクトを検証することで、ユーザーはより強力なセキュリティの保証を得ることができます。
イーサリアムのスマートコントラクトコードの検証方法
イーサリアムにスマートコントラクトをデプロイするには、データペイロード(コンパイル済みバイトコード)を含むトランザクションを、特別なアドレスに送信する必要があります。 データペイロードは、トランザクション内のデータペイロードに付加されるコントラクトインスタンスのコンストラクタ引数(opens in a new tab)に加えて、ソースコードをコンパイルすることによって生成されます。 コンパイルは決定論的です。つまり、ソースファイルとコンパイル設定(コンパイラのバージョンや最適化など)が同じであれば、常に同じ結果(スマートコントラクトのバイトコード)を生成します。
スマートコントラクトの検証は、大きく分けて次の手順で行われます。
ソースファイルとコンパイル設定をコンパイラに入力します。
コンパイラはスマートコントラクトのバイトコードを出力します。
指定されたアドレスでデプロイされたスマートコントラクトのバイトコードを取得します。
デプロイされたバイトコードを再コンパイルされたバイトコードと比較します。 コードが一致すれば、スマートコントラクトが指定されたソースコードとコンパイル設定に基づいて作成されたことが確認できます。
さらに、バイトコード末尾のメタデータハッシュが一致すれば、完全一致となります。
これは検証の単純化された記述であり、 イミュータブル変数(opens in a new tab)を持つ場合など、検証できない例外が多いことに注意してください。
ソースコード検証ツール
スマートコントラクトを検証する従来のプロセスは複雑になりがちです。 そのため、イーサリアムにデプロイされたスマートコントラクトのソースコードを検証するツールが存在します。 これらのツールは、ソースコード検証の大部分を自動化し、ユーザーに有益となるように検証済みのスマートコントラクトをキュレーションします。
Etherscan
主にイーサリアムのブロックチェーンエクスプローラーとして知られているEtherscanは、スマートコントラクトのデベロッパーやユーザー向けに、ソースコード検証サービス(opens in a new tab)も提供しています。
Etherscanを使用すると、元のデータペイロード(ソースコード、ライブラリのアドレス、コンパイラの設定、スマートコントラクトのアドレスなど)から、スマートコントラクトのバイトコードを再コンパイルできます。 再コンパイルされたバイトコードがチェーン上のスマートコントラクトのバイトコード(およびコンストラクタのパラメータ)に結び付くと、 コントラクトが検証されます(opens in a new tab)。
検証が完了すると、スマートコントラクトのソースコードは「検証済み」のラベルを受け取り、他の人が監査できるようにEtherscanで公開されます。 また、検証済みソースコードを備えたスマートコントラクトのリポジトリである検証済みコントラクト(opens in a new tab)のセクションにも追加されます。
Etherscanはスマートコントラクトを検証するのに最もよく使用されるツールです。 しかし、Etherscanのコントラクト検証には欠点があります。チェーン上のバイトコードのメタデータハッシュと再コンパイルされたバイトコードを比較することができないため、 部分一致しか得られません。
Etherscanでスマートコントラクトを検証する方法の詳細(opens in a new tab)
Sourcify
Sourcify(opens in a new tab)は、オープンソースで分散化された、スマートコントラクトを検証するためのツールです。 ブロックエクスプローラーではなく、 異なるEVMベースのネットワーク(opens in a new tab)でスマートコントラクトを検証するためのものです。 このツールは、他のツールを構築するためのパブリックインフラストラクチャとして機能します。ABIやメタデータファイル内で見つけたNatSpec(opens in a new tab)コメントを使い、よりヒューマンフレンドリーにコントラクトとやり取りできるようにすることを目指しています。
Etherscanと違って、Sourcifyでは、メタデータハッシュとの完全一致をサポートしています。 検証されたコントラクトは、Sourcifyのパブリックリポジトリ(opens in a new tab)によりHTTPおよびIPFS(opens in a new tab)で提供されます。IPFSは、分散化されたコンテンツアドレス付(opens in a new tab)ストレージです。 添付されたメタデータハッシュがIPFSハッシュであるため、IPFSを通してコントラクトファイルのメタデータを取り出すことができます。
さらに、ソースコードファイルのIPFSハッシュもメタデータ内にあるため、IPFSを通してソースコードファイルを取得することもできます。 APIもしくはUI(opens in a new tab)を通して、またはプラグインを使って、メタデータファイルとソースファイルを提供することでコントラクトを検証できます。 また、Sourcifyのモニタリングツールは、新しいブロックでコントラクトの作成をリッスンし、メタデータとソースファイルがIPFSで公開されている場合にコントラクトを検証しようとします。
Sourcifyのコントラクト検証の詳細(opens in a new tab)
Tenderly
Tenderlyプラットフォーム(opens in a new tab)は、Web3デベロッパー向けにスマートコントラクトのビルド、テスト、モニタリング、操作を提供します。 Tenderlyでは、オブザーバビリティおよびインフラストラクチャのビルディングブロックを持つデバックツールを組み合わせることで、デベロッパーがスマートコントラクトの開発をより迅速に行えるようサポートします。 Tenderlyの機能を完全に有効にするには、デベロッパーはいくつかの方法でソースコード検証を実行(opens in a new tab)する必要があります。
コントラクトは、公開または非公開で検証できます。 非公開で検証する場合、スマートコントラクトは、作成者(もしくはプロジェクト内の他のメンバー)のみに公開されます。 公開で検証する場合、Tenderlyプラットフォームを使用するすべての人に公開されます。
ダッシュボード(opens in a new tab)、Tenderly Hardhatプラグイン(opens in a new tab)、CLI(opens in a new tab)を使ってコントラクトを検証することができます。
ダッシュボードを通してコントラクトを検証する場合、Solidityコンパイラによって生成されたソースファイルもしくはメタデータファイル、アドレス/ネットワーク、コンパイラー設定をインポートする必要があります。
Tenderly Hardhatプラグインを使うと、少ない労力で検証プロセスをより細かく制御できます。また、自動(コードなし)検証と手動(コードベース)検証のいずれかを選択できます。