スマートコントラクトのテスト
最終編集者: @HiroyukiNaito(opens in a new tab), Invalid DateTime
スマートコントラクトのテストは、スマートコントラクトのセキュリティを向上させる最も重要な対策の 1 つです。 従来のソフトウェアとは異なり、通常、スマートコントラクトは起動後に更新することができないため、イーサリアムネットワークにコントラクトをデプロイする前に厳格なテストを行うことが不可欠です。
スマートコントラクトのテストとは
スマートコントラクトのテストとは、スマートコントラクトの開発サイクルにおいて、そのソースコードの品質を評価するために詳細な分析と評価を行うことを意味します。 スマートコントラクトをテストすることで、バグや脆弱性の特定が容易になり、コストのかかるエクスプロイトにつながるソフトウェアエラーの可能性を低減することができます。
スマートコントラクトのテストには様々な形態があり、それぞれの手法によってメリットがあります。 イーサリアムスマートコントラクトのテスト戦略は、大きく 2 つに分類されます。自動テストと手動テストです。
自動テスト
自動テストでは、自動化ツールを使って、スマートコントラクトのスクリプトテストを実施します。 この技術は、スマートコントラクトの欠陥を見つけるためにテストを繰り返し実行できる自動化されたソフトウェアに依存しています。
自動テストは効率的で、使用するリソースも少なく、手動分析よりも高いカバレッジレベルを実現します。 また、自動テストツールにテストデータを設定することで、予測された動作と実際の結果を比較することができます。
手動テスト
手動テストは、人が介在し、テスト手順を手動で実行するものです。 コード監査は、デベロッパーや監査人がコントラクトコードのすべての行に目を通すもので、スマートコントラクトの手動テストの一例です。
スマートコントラクトの手動テストには、かなりのスキルと、時間、費用、労力の投資が必要です。 さらに、手作業によるテストは、時にヒューマンエラーの問題をはらんでいることがあります。
さらに、手作業によるテストは、時にヒューマンエラーの問題をはらんでいることがあります。 コード監査は、人間の知能を利用して、自動テストでは検出されない可能性のある契約コードの欠陥を見つけます。
スマートコントラクトを手動でテストすることで、コードの外に存在する、しかし影響を及ぼしうる脆弱性を発見することもできます。 例えば、スマートコントラクトの監査では、オフチェーンのコンポーネントとの欠陥のある相互作用に起因する脆弱性を発見することができます。
スマートコントラクトのテストの重要性
以下の理由により、スマートコントラクトのテストは重要です。
1. スマートコントラクトは高価値のアプリケーションである
スマートコントラクトは、特に分散型金融(DeFi)などの業界において価値の高い金融資産や、非代替性トークン(NFT)などの有価物を扱うことがよくあります。 そのため、スマートコントラクトの些細な脆弱性が、ユーザーにとって回復不能な巨額の損失につながることがしばしばあります。 しかし、包括的なテストにより、スマートコントラクトのコードの誤りを明らかにし、デプロイする前にセキュリティリスクを低減することができます。
2. スマートコントラクトはイミュータブル(不変)である
イーサリアム仮想マシン(EVM)にデプロイされたスマートコントラクトは、デフォルトでイミュータブル(不変)となっています。 従来のデベロッパーは、発売後にソフトウェアのバグを修正することに慣れているかもしれませんが、イーサリアムの開発では、スマートコントラクトがブロックチェーン上で稼働すると、セキュリティ上の欠陥を修正する余地がほとんどなくなります。
プロキシパターンなど、スマートコントラクトでアップグレード可能なメカニズムは存在するものの、実装が難しい場合があります。 アップグレードによって不変性が損なわれ、複雑さが生じるだけでなく、しばしば複雑なガバナンスプロセスが要求されます。
ほとんどの場合、アップグレードは最後の手段と考え、必要な場合を除き避けるべきです。 起動前の段階でスマートコントラクトの潜在的な脆弱性や欠陥を検出することで、ロジックのアップグレードの必要性を減らすことができます。
スマートコントラクトの自動テスト
1. 機能テスト
機能テストは、スマートコントラクトの機能を検証し、コード内の各機能が期待通りに動作することを保証するものです。 機能テストでは、スマートコントラクトが特定の条件下でどのように動作すべきかを理解する必要があります。 その後、選択した値で計算を実行し、返された出力と期待される出力を比較することで、各機能をテストすることができます。
機能テストには 3 つの手法があります。単体テスト、統合テスト、システムテストです。
単体テスト
単体テストは、スマートコントラクトの個々のコンポーネントの正確性をテストするものです。 単体テストはシンプルで、素早く実行でき、テストが失敗した場合に何が悪かったのかを明確にすることができます。
スマートコントラクトの開発では、特にコードに新しいロジックを追加する必要がある場合、単体テストは非常に重要です。 各機能の動作を検証し、意図したとおりに実行されることを確認することができます。
多くの場合、単体テストを実行するには、アサーション(スマートコントラクトの要件を指定する単純で非公式なステートメント)の作成が必要になります。 単体テストでは、それぞれのアサーションをテストし、実行時にそれが正しいかどうかを確認することができます。
コントラクト関連のアサーションの例としては、以下のものがあります。
I. 「コントラクトを一時停止できるのは管理者のみ」
ii. 「管理者以外は新しいトークンをミントできない」
iii. 「コントラクトはエラーになると元に戻る」
統合テスト
統合テストは、テスト階層において単体テストより上位に位置します。 統合テストでは、スマートコントラクトの個々のコンポーネントが一緒にテストされます。
このアプローチは、コントラクトの異なる構成要素間、または複数のコントラクトにまたがる相互作用に起因するエラーを検出するものです。 複数の機能を持つ複雑なコントラクトや、他のコントラクトとのインターフェイスを持つコントラクトがある場合は、この手法を使用する必要があります。
統合テストは、継承(opens in a new tab)や依存性注入などが適切に動作することを確認するのに便利です。
システムテスト
システムテストは、スマートコントラクトの機能テストの最終段階です。 システムテストは、スマートコントラクトを完全に統合された 1 つの製品として評価し、技術要件で指定されたとおりの性能を発揮するかどうかを確認します。
この段階は、ユーザーの視点からスマートコントラクトのエンドツーエンドの流れを確認することだと考えることができます。 スマートコントラクトのシステムテストを行うには、テストネットや開発用ネットワークなどの本番同様の環境上にデプロイすることが良い方法と言えます。
ここでは、エンドユーザーが試験運用を行い、コントラクトのビジネスロジックや全体的な機能に関する問題を報告することができます。 システムテストが重要なのは、コントラクトがメインの EVM 環境にデプロイされると、コードを変更することができないからです。
2. 静的/動的解析
スマートコントラクトのセキュリティ品質を評価するための自動テスト手法として、静的解析と動的解析があります。 しかし、どちらの手法も、コントラクトコードの不具合を発見するために、異なるアプローチを採用しています。
静的解析
静的解析は、実行前にスマートコントラクトのソースコードまたはバイトコードを調査します。 つまり、実際にプログラムを実行することなく、コントラクトコードをデバッグすることができるのです。 静的解析ツールは、イーサリアムスマートコントラクトに共通する脆弱性を検出し、最善の方法の遵守を支援します。
動的解析
動的解析手法では、スマートコントラクトをランタイム環境で実行し、コードの問題点を特定する必要があります。 動的コードアナライザーは、実行中のコントラクトの振る舞いを観察し、特定された脆弱性やプロパティ違反の詳細なレポートを生成します。
ファジングは、コントラクトをテストするための動的解析手法の一例です。 ファズテストでは、ファザーがスマートコントラクトに不正なデータを与え、その入力に対してコントラクトがどのように応答するかを監視します。
ファズテストでは、ファザーがスマートコントラクトに不正なデータを与え、その入力に対してコントラクトがどのように応答するかを監視します。 ユーザーが正しい入力をすることを前提としていますが、必ずしもそうであるとは限らないからです。
スマートコントラクトに誤った入力値を送ると、リソースリークやクラッシュを引き起こしたり、最悪の場合、意図しないコードの実行につながったりするケースがあります。 ファジングキャンペーンでは、このような問題を事前に発見し、脆弱性を排除することが可能です。
スマートコントラクトの手動テスト
1. コード監査
コード監査とは、スマートコントラクトのソースコードを詳細に評価し、起こりうる障害点、セキュリティ上の欠陥、不適切な開発手法を発見することです。 コード監査は自動化することもできますが、ここでは人の手を介したコード解析を指しています。
コード監査では、スマートコントラクトで考えられる攻撃ベクトルをマッピングするために、攻撃者のマインドセットが必要です。 自動監査を行うにしても、ソースコードの一行一行を解析することは、安全なスマートコントラクトを書くための最低条件です。
また、スマートコントラクトの安全性をより確実にするために、セキュリティ監査を依頼することも可能です。 監査では、サイバーセキュリティの専門家による広範な解析が行われ、スマートコントラクトの機能を破壊する可能性のある脆弱性やバグを検出することができます。
2. バグ報奨金
バグ報奨金とは、プログラムのコードに脆弱性やバグを発見し、デベロッパーに報告した個人に与えられる金銭的な報酬のことです。 バグ報奨金は、スマートコントラクトの不具合の発見を他の人に依頼するもので、監査に似ています。 大きな違いは、バグ報奨金プログラムには、デベロッパーコミュニティやハッカーコミュニティからも幅広く参加できるということです。
バグ奨励金プログラムには、独自のスキルや経験を持つ幅広い層の倫理的ハッカーや独立したセキュリティ専門家が多く参加します。 これは、限られた専門知識を持つチームに依存するスマートコントラクト監査にはない利点と言えるでしょう。
テストと形式検証の比較
テストは、あるデータ入力に対してコントラクトが期待通りの結果を返すことを確認するのに役立ちますが、テストで使用されていない入力に対して同じことを決定的に証明することはできません。 スマートコントラクトのテストは「機能的な正しさ」を保証できません。つまり、入力値や条件のすべてのセットに対してプログラムが要求通りに動作することを示すことはできないのです。
そのため、デベロッパーはスマートコントラクトの正しさを評価するアプローチに形式検証を取り入れることが推奨されています。 形式検証では、形式手法(opens in a new tab)(ソフトウェアを仕様化し検証するための数学的に厳密な技法)を用います。
形式検証は、デベロッパーがスマートコントラクトに関連する仮定を形式的に検証するのに役立つため、スマートコントラクトにとって重要であると考えられています。 これは、スマートコントラクトの特性を記述した形式的な仕様を作成し、スマートコントラクトの形式モデルがその仕様に合致していることを検証することで実現されます。 このアプローチにより、スマートコントラクトはビジネスロジックで定義された機能のみを実行し、それ以外の機能は実行しないという信頼性を高めることができます。
テストのためのツールとライブラリ
単体テストツール
Solidity-Coverage - スマートコントラクトのテストに便利な Solidity のコードカバレッジツールです。
Waffle - 高度なスマートコントラクトの開発とテストのためのフレームワークです(ethers.js をベースとする)。
Remix Tests - Solidity スマートコントラクトをテストするためのツールです。 Remix IDE の「Solidity Unit Testing」プラグインで動作します。このプラグインは、コントラクトのテストケースの作成と実行に使用されます。
OpenZeppelin テストヘルパー - イーサリアムスマートコントラクトテストのためのアサーションライブラリです。 コントラクトが期待通りに動作することを確認してください。
Truffle スマートコントラクトテストフレームワーク - 自動テストフレームワークにより、コントラクトのテストを簡単に行うことができます。
ユニットテストフレームワーク Brownie - Brownie は、最小限のコードで小さなテストを作成することができ、大規模なプロジェクトでもうまく拡張できる、機能豊富なテストフレームワークである Pytest を利用しています。
Foundry Tests - Foundry 社は、シンプルな単体テスト、ガス最適化チェック、コントラクトファジングを実行できる、高速で柔軟なイーサリアムテストフレームワークである Forge を提供しています。
Etheno - JSON RPC マルチプレクサ、解析ツールラッパー、テスト統合ツールからなるオールインワンのイーサリアムテストツールです。 Etheno は、大規模なマルチコントラクトプロジェクトにおいて、Manticore や Echidna のような分析ツールを設定する複雑さを解消します。
Woke development and testing framework - Python のテスト・デプロイメントスクリプトで、型ヒント、ファザー、デバッグサポート、コードカバレッジ、クロスチェーンテストを備えています。
静的解析ツール
Mythril - Taint 解析、Concolic 解析、制御フローチェックを用いてコントラクトの脆弱性を検出する EVM バイトコード評価ツールです。
Slither - Python ベースの Solidity 静的解析フレームワークで、脆弱性の発見、コード理解の強化、スマートコントラクトのカスタム解析の記述に使用します。
Rattle - デプロイされたスマートコントラクトで動作するように設計された EVM バイトコード静的解析フレームワークです。
動的解析ツール
Echidna - プロパティベースのテストによりスマートコントラクトの脆弱性を検出する高速なコントラクトファザーです。
Harvey - スマートコントラクトのコードのプロパティ違反を検出するのに便利な自動ファジングツールです。
Manticore - EVM バイトコード解析のための動的シンボリック実行フレームワーク。
スマートコントラクト監査サービス
ConsenSys Diligence - スマートコントラクトの監査サービスによって、ブロックチェーンエコシステム全体のプロジェクトについて、プロトコルが起動に適した状態にあり、ユーザーを保護できるように構築されていることを保証します。
CertiK - スマートコントラクトとブロックチェーンネットワークに最先端の形式検証技術を使用する先駆的なブロックチェーンセキュリティ企業です。
Trail of Bits - セキュリティ研究と攻撃者の心理を融合させ、リスクの低減とコードの堅牢化を図るサイバーセキュリティ企業です。
PeckShield - ブロックチェーンエコシステム全体のセキュリティ、プライバシー、ユーザビリティのための製品やサービスを提供するブロックチェーンセキュリティ企業です。
QuantStamp - セキュリティおよびリスク評価サービスを通じて、ブロックチェーン技術の主流化を促進する監査サービスです。
OpenZeppelin - 分散型システムのセキュリティ監査を提供するスマートコントラクトセキュリティ企業です。
Nethermind - Solidity と Cairo の監査サービスにより、イーサリアムと Starknet 全体でスマートコントラクトの整合性とユーザーの安全が確保されます。
バグ報奨金プラットフォーム
Immunefi - スマートコントラクトと DeFi プロジェクトのためのバグ報奨金プラットフォームです。セキュリティ研究者がコードをレビューし、脆弱性を開示し、報酬を得て、暗号をより安全なものにします。
HackerOne - 企業とペネトレーションテスターやサイバーセキュリティ研究者をつなぐ、脆弱性調整とバグ報奨金のプラットフォームです。
関連チュートリアル
- 安定性と Truffle 連続統合設定 – Travis または Circle CI の Truffle テストと有益なプラグインのセットアップ方法
- 製品テストの概要 – 様々な製品テストの概要と比較
- スマートコントラクトのテストに Echidna を使用する方法
- Manticore を使用してスマートコントラクトのバグを見つける方法
- Slither を使用してスマートコントラクトのバグを見つける方法
- テスト用 Solidity コントラクトのモックの作成方法
- Truffle テストから OpenZeppelin テスト環境に移行する方法(opens in a new tab)
- ネットワークにデプロイした後にスマートコントラクトをテストする方法(opens in a new tab)
- JavaScript で学ぶブロックチェーン、Solidity、フルスタック Web3 開発(YouTube)(opens in a new tab)
- Solidity、ブロックチェーン、スマートコントラクト講座(YouTube)(opens in a new tab)
参考文献
- イーサリアムスマートコントラクトのテストに関する徹底ガイド(opens in a new tab) - Ben Hauser
- イーサリアムスマートコントラクトのテスト方法(opens in a new tab) - Alex Roan