コントラクトのバイトコードとは?
コントラクトのバイトコードとは、スマートコントラクトのデプロイ時や呼び出し時にブロックチェーンの仮想マシンが実行する、機械可読形式の低水準コードです。暗号資産分野では、Ethereum系ネットワーク上のスマートコントラクトについて説明する際によく使われます。こうしたネットワークでは、オンチェーンで実行する前にソースコードをコンパイルしてEthereum Virtual Machine(EVM)のバイトコードに変換します。開発者は通常、Solidityなどの高水準言語でスマートコントラクトを記述しますが、バリデーター、ノード、仮想マシンが人間に読めるソースコードをそのまま実行するわけではありません。ソースコードはバイトコードにコンパイルされ、このバイトコードがスマートコントラクトアドレスに保存される実際のプログラムロジックになります。Ethereumのスマートコントラクトコンパイルガイドでは、EVMで実行するにはコントラクトをバイトコードにする必要があると説明されています。
コントラクトのバイトコードが重要なのは、開発者のコードエディターの裏側に隠れた技術的な要素にとどまらず、オンチェーンに展開された最終的なロジックだからです。コントラクトのソースコードに記述された内容と、デプロイ済みバイトコードの動作が異なる場合、ブロックチェーンはバイトコードに従います。そのため、バイトコードはスマートコントラクトの検証、ブロックチェーンのセキュリティ、トークン監査、分散型アプリケーション、ユーザーの信頼において中心的な役割を果たします。コントラクトのバイトコードの仕組み
スマートコントラクトは、開発者が記述するソースコードから始まります。開発者は、コンパイラのバージョン、コンパイラ設定、最適化設定、ライブラリ、コンストラクター引数、対象とする仮想マシンのバージョンを選択します。コンパイラはソースコードを、ブロックチェーンの仮想マシンが理解できるバイトコードに変換します。コントラクトをデプロイする際には、作成コードを含むトランザクションがネットワークに送信されます。作成コードはデプロイ時に1回実行され、コントラクトアドレスに保存されるランタイムバイトコードを返します。デプロイ後、ユーザーや他のコントラクトは、デプロイ済みのランタイムバイトコードとやり取りします。Ethereum Virtual Machineのドキュメントでは、EVMはEthereumの各ノードで一貫してスマートコントラクトコードを実行する環境だと説明されています。
すべてのノードが同じ結果に到達する必要があるため、バイトコードの実行は決定論的です。つまり、同じブロックチェーンの状態に同じプロトコルルールの下で同じトランザクションを適用すれば、有効なすべてのノードで同じ結果が得られるはずです。この一貫性により、中央サーバーが結果を決定しなくても、スマートコントラクトを使ったトークン、レンディング市場、スワップ、ゲーム、ガバナンスシステムなどの暗号資産アプリケーションが実現します。コントラクトのバイトコードとソースコードの違い
ソースコードは人間向けに書かれ、コントラクトのバイトコードは仮想マシン向けに書かれています。ソースコードには、コントラクトを理解しやすくする関数名、コメント、変数名、書式、設計パターンが含まれる場合があります。バイトコードは通常、ほとんどのユーザーには直接読み解くのが難しい、長い16進数の文字列として表示されます。ソースコード上の単純な関数も、コンパイル後には多数のバイトコード命令になることがあります。これらの命令は、スタック操作、メモリ、ストレージへのアクセス、算術演算、コントラクト呼び出し、ログ、ジャンプ、実行の取り消しなどの低水準の動作を制御します。Ethereumのオペコードリファレンスには、EVMのバイトコード動作を構成するオペコードが記載されています。
ソースコードの方が監査しやすい一方、ブロックチェーンが実際に実行するのはバイトコードです。そのため、厳密なコントラクトレビューでは、公開されたソースコードがデプロイ済みバイトコードと本当に一致するかを確認することがよくあります。検証済みのソースコードページが有用なのは、正しい設定でコンパイラ出力とオンチェーンのバイトコードを照合できる場合に限られます。作成バイトコードとランタイムバイトコード
コントラクトのバイトコードは主に、作成バイトコードとランタイムバイトコードの2種類に分けて説明されます。作成バイトコードは、デプロイトランザクションに含まれるコードです。コントラクトの作成、コンストラクターの実行、初期設定の処理、最終的なランタイムバイトコードの返却に必要な命令が含まれています。ランタイムバイトコードは、デプロイ後にコントラクトアドレスに保存されるコードです。後からコントラクトを呼び出した際に実行されるのがランタイムバイトコードです。デプロイに使われたバイトコードと、オンチェーンに残るバイトコードは、必ずしも同じではないため、この違いは重要です。コンストラクター引数はデプロイ時の入力に含まれる場合がありますが、最終的なランタイムバイトコード内では同じ形式で存在しないことがあります。コンパイラのメタデータも、ビルドで生成される正確なバイトコードに影響する場合があります。Solidityのメタデータに関するドキュメントでは、メタデータがコントラクトのバイトコードに含まれ、ツールで利用される仕組みが説明されています。
コントラクトを検証する際には、作成バイトコード、ランタイムバイトコード、コンストラクターデータ、リンク済みライブラリアドレス、コンパイラ設定のすべてが重要になる場合があります。コントラクトのバイトコードに含まれるもの
コントラクトのバイトコードには、仮想マシンに実行内容を指示する命令が含まれています。これらの命令はオペコード(operation codeの略)と呼ばれます。各オペコードは、ブロックチェーンの実行ルールに基づいて特定の意味を持ちます。たとえば、算術演算を行うオペコード、トランザクションデータを読み取るもの、コントラクトストレージに書き込むもの、ログを生成するもの、他のコントラクトを呼び出すものなどがあります。EVMのバイトコードはスタックベースで実行されるため、多くの演算はスタックから入力を取り出し、結果をスタックに戻します。EVMには一時データ用のメモリと、コントラクト状態を永続的に保存するストレージもあります。ストレージには、トークン残高、所有権記録、設定値、マッピングなど、長期的に保持するコントラクトデータが保存されます。メモリは一時的なもので、トランザクションの終了後に消去されます。Calldataには、関数セレクターやエンコードされた引数など、コントラクト呼び出しに送られる入力が含まれます。Solidity ABI仕様では、スマートコントラクトとのやり取りに使う関数呼び出しと戻り値のエンコード方法が説明されています。
通常、コントラクトのバイトコードには、ソースコードにあるコメント、分かりやすい変数名、全体的な構造は保持されません。そのため、検証済みのソースコードはユーザー、監査人、開発者、セキュリティ研究者にとって価値があります。暗号資産分野でコントラクトのバイトコードが重要な理由
暗号資産はスマートコントラクトのロジックによって直接管理されることがあるため、コントラクトのバイトコードは重要です。トークンコントラクトのバイトコードは、残高の変更方法、トークンの送付権限、承認の仕組み、特別な権限の有無を決定します。分散型アプリケーションでは、コントラクトのバイトコードが入金、出金、手数料、強制決済、報酬、投票、自動実行などを処理することがあります。バイトコードにバグがあれば、実際の資金に影響する可能性があります。隠された権限、管理者用関数、危険なアップグレード経路、悪意ある送金ルールがバイトコードに含まれている場合、ユーザーは重大なリスクにさらされるおそれがあります。ブロックチェーン上のトランザクションは、承認後に取り消せないことが多いため、ユーザーはコントラクトのバイトコードを、そのコントラクトに適用されるルールとして扱う必要があります。ウェブサイトのインターフェースが単純に見えても、オンチェーンで実際に何が起きるかはコントラクトのバイトコードが決定します。ウォレットの警告、コントラクト検証ラベル、監査レポート、トランザクションシミュレーションが、より慎重な暗号資産利用に重要なのはこのためです。コントラクトのバイトコードとスマートコントラクトの検証
スマートコントラクトの検証とは、公開されたソースコードがデプロイ済みのコントラクトのバイトコードと一致することを証明するプロセスです。読み解きにくい16進数の文字列をそのまま信頼するのではなく、理解しやすいソースコードをユーザーが読めるようにすることが目的です。Ethereumのコントラクト検証ガイドでは、デプロイ時の元情報を使ってソースコードを再コンパイルし、その結果をオンチェーンのバイトコードと照合するのが検証のプロセスだと説明されています。
検証には通常、正確なコンパイラバージョン、ソースファイル、コンストラクター引数、最適化設定、外部ライブラリアドレス、ビルド設定が必要です。コンパイラ設定がわずかに異なるだけでも、異なるバイトコードが生成されることがあります。コントラクトが検証済みであることは、そのコントラクトが安全であることを自動的に意味するわけではありません。表示された設定の下で、公開ソースコードとデプロイ済みバイトコードを照合できることを意味します。ユーザーは引き続き、権限、所有権、アップグレード可能性、外部呼び出し、トークンの動作、監査結果を確認する必要があります。検証は透明性を高めますが、スマートコントラクトのリスクをなくすものではありません。コントラクトのバイトコードとガス代
仮想マシンのルールでは命令ごとに実行コストが設定されているため、コントラクトのバイトコードはガス代に影響します。コストの低い演算もあれば、ストレージへの書き込みや特定のコントラクト間のやり取りのように、高コストになる操作もあります。コントラクトのデプロイ時には、バイトコードのサイズと複雑さもデプロイコストに影響する場合があります。小さく効率的なバイトコードはガス使用量を減らせる可能性がありますが、過度な最適化によってコードの動作を把握しにくくなることがあります。Solidityコンパイラには、生成されるバイトコードを変える最適化設定があります。Solidityの最適化に関するドキュメントでは、最適化が生成コードとガス効率に及ぼす影響が説明されています。
開発者は、ガスの節約と読みやすさ、監査のしやすさ、動作の予測可能性のバランスを取ることがよくあります。ユーザーがガス代を理解するために生のバイトコードを読む必要はありませんが、コントラクトの設計が暗号資産アプリケーションの利用コストに直接影響する点は知っておく必要があります。コントラクトのバイトコードとオペコード
オペコードは、コントラクトのバイトコードを構成する個々の命令です。EVMのオペコードには、ADD、CALL、SLOAD、SSTORE、JUMP、LOG、RETURN、REVERTなどがあります。各オペコードは、定義された方法で実行状態を変化させます。たとえば、SLOADはコントラクトストレージから読み取り、SSTOREはコントラクトストレージに書き込みます。CALLは他のコントラクトに処理を移せますが、慎重に扱わなければセキュリティリスクが生じる可能性があります。REVERTは、特定の失敗条件の下で実行を停止し、残りのガスを返します。プロトコルの変更に伴うネットワークのアップグレードで、新しいオペコードが追加される場合があります。たとえば、EIP-3855では、値0をより効率的にスタックへ積むPUSH0オペコードが導入されました。
プロトコルのアップグレードによってオペコードのルールが変更される場合があるため、開発者は適切な対象環境向けにコントラクトをコンパイルする必要があります。そのため、古いバイトコードと新しいバイトコードでは、前提となる動作が異なる場合があります。コントラクトのバイトコードとABI
コントラクトのバイトコードとABIは関連していますが、同じものではありません。バイトコードは、オンチェーンに保存される実行可能なプログラムです。ABI(Application Binary Interface)は、外部のユーザーやアプリケーションがコントラクトを呼び出す方法を示します。ウォレット、フロントエンド、スクリプト、ブロックチェーンツールはABIを使って関数呼び出しをエンコードし、返されたデータをデコードします。ABIは、ある関数が存在すること、その関数がどの入力を受け取るか、出力をどう解釈するかをソフトウェアに伝えます。通常、ABIは人間が読めるインターフェース情報の全体がオンチェーンのコントラクトアカウントに保存されているわけではありません。そのため、ABIを公開していなくても、コントラクトのバイトコードがオンチェーンに存在することはあります。ソースコードが検証されると、ブロックチェーンエクスプローラーや開発者向けツールでABIが表示され、コントラクトを操作しやすくなる場合があります。ABIが検証されていない場合、ユーザーは呼び出しを手作業でデコードしたり、サードパーティ製ツールに頼ったりする必要があり、ミスの可能性が高まります。コントラクトのバイトコードと逆コンパイル
逆コンパイルとは、バイトコードをより読みやすい形式に戻そうとするプロセスです。逆コンパイラーは未検証のコントラクトを研究者が理解する助けになりますが、元のソースコードを完全に復元することはできません。コメント、変数名、書式、ファイル構造、多くの高水準の設計判断は、コンパイル時に通常失われます。コンパイラの最適化によってロジックの配置が変わり、逆コンパイル後の出力がさらに分かりにくくなることもあります。それでも、逆コンパイルによって関数セレクター、ストレージの使い方、外部呼び出し、イベントログ、不審なパターンなどの重要な手掛かりが見つかる場合があります。ただし、逆コンパイルされたコードを検証済みのソースコードと同等に扱ってはいけません。これはバイトコードをリバースエンジニアリングしたものであり、開発者が作成した元のソースファイルではありません。コントラクトのバイトコードとアップグレード可能なコントラクト
アップグレード可能なコントラクトでは、ユーザーが操作するアドレスにアプリケーションのロジックすべてが含まれていない場合があるため、バイトコードの分析が複雑になります。多くのアップグレード可能なシステムでは、呼び出しを実装コントラクトへ転送するプロキシコントラクトが使われています。プロキシアドレスにユーザー向けの状態が保存され、実装アドレスにロジックのバイトコードが含まれる場合があります。実装アドレスが変更されると、プロキシアドレスを変えずにユーザー向けコントラクトの動作が変わる可能性があります。これはバグ修正や機能追加に役立つ一方、ガバナンスや信頼に関するリスクも生みます。アップグレード可能なコントラクトのバイトコードを確認するときは、プロキシ、実装、アップグレード管理者、アップグレードルールを調べる必要があります。実装コントラクトが未検証、またはリスクの高い管理者設定で制御されている場合、プロキシが検証済みであるだけでは不十分です。コントラクトのバイトコードを分析する際は、そのコードが不変なのか、アップグレード可能なのか、他のコントラクトに依存するのかを必ず考慮してください。コントラクトのバイトコードとセキュリティ監査
セキュリティ監査では通常ソースコードが中心となりますが、デプロイされた実体はバイトコードであるため、バイトコードも重要です。監査対象のソースコードがデプロイ済みバイトコードと異なる場合、監査レポートの有用性が低下する可能性があります。監査人は、レビューしたバージョンとオンチェーンのバージョンが一致することを確認するため、ソースコード、コンパイル出力、デプロイトランザクション、依存関係のバージョン、検証済みバイトコードを比較する場合があります。バイトコードレベルのレビューでは、ソースコードだけでは見つけにくいパターンを発見できることもあります。たとえば、バイトコード分析によって、到達不能なコード、通常と異なるジャンプ動作、低水準の呼び出し、自己破壊のパターン、プロキシ転送、隠された関数セレクターなどが明らかになる場合があります。デプロイ済みコントラクトの多くは検証されていないため、研究ツールがEVMバイトコードを直接分析することもよくあります。スマートコントラクト検証サービスに関する研究では、スマートコントラクトエコシステムの信頼にとって、ソースコードとオンチェーンのバイトコードを照合することが重要だと指摘されています。
ユーザーにとっての実務上の教訓はシンプルです。洗練されたウェブサイトや見慣れたトークン名だけを理由に、コントラクトを信頼してはいけません。コントラクトのバイトコードと不変性
通常のスマートコントラクトのランタイムバイトコードは、一度デプロイされると、同じアドレスで変更するのが一般に困難です。この不変性は、スマートコントラクトが透明なルールと自動実行を実現できる理由の1つです。ただし、不変性が必ずしもアプリケーションの動作全体が固定されていることを意味するわけではないため、注意が必要です。コントラクトは、ガバナンスや設定によってアドレスが変更される可能性のある別のコントラクトを呼び出す場合があります。プロキシが異なる実装に処理を委譲する場合もあります。管理者が関数の一時停止、手数料の変更、トークンのミント、アドレスのブラックリスト登録、ロジックのアップグレード、一部資産の引き出しなどを行う権限を持つ場合があります。オフチェーンの署名、オラクルデータ、外部キーパーに依存するコントラクトもあります。そのため、バイトコードの不変性は権限、依存関係、アップグレード設計と併せて評価する必要があります。コントラクトのバイトコードを確認する方法
ユーザーはブロックチェーンエクスプローラー、ノードへの照会、開発者向けツール、ウォレットのセキュリティプラットフォームを通じてコントラクトのバイトコードを確認できます。ブロックチェーンエクスプローラーでは、コントラクトが検証済みかどうかが表示され、ソースコード、コンパイラ設定、ABI、作成トランザクション、デプロイ済みバイトコードを確認できる場合があります。同様のバイトコードとの一致を表示するエクスプローラーもあり、同一または非常によく似たコードから作成されたコントラクトを特定するのに役立つことがあります。コントラクトコードタブのガイドでは、コントラクトページにソースコード、ABI、バイトコード、検証情報がどのように表示されるかが説明されています。
上級ユーザーは、コントラクトアドレスに保存されたコードを返すメソッドを使い、ノードに照会できます。開発者はソースコードをローカルでコンパイルし、生成されたランタイムバイトコードをオンチェーンのコードと比較することもできます。コントラクトの検証に失敗した場合、読み取り可能なソースコードが入手できない、またはデプロイ済みバイトコードと一致しない可能性があるため、ユーザーは注意が必要です。コントラクトのバイトコードを確認する際の一般的な危険信号
ソースコードが検証されていないコントラクトは、一般のユーザーにとって評価が難しい場合があります。未検証だからといって必ず悪意があるとは限りませんが、透明性に問題が生じます。隠されたミント権限、送金制限、ブラックリスト管理、通常と異なる手数料ロジックを持つトークンコントラクトは、保有者を大きなリスクにさらす可能性があります。アップグレード可能なプロキシに依存するコントラクトは、実装と管理者権限も併せて確認する必要があります。重要な関数で外部呼び出しを行うコントラクトは、リエントランシーや権限に関する追加の確認が必要な場合があります。既知の詐欺パターンと不審な類似点があるコントラクトは、適格なレビューで問題がないと確認されない限り、利用を避けてください。無制限のトークン使用を承認するよう求めるコントラクトは、特に新規、未検証、または未監査の場合、慎重に扱う必要があります。初心者がバイトコードだけですべてを判断することはできませんが、ユーザーがトランザクションに署名する前に、セキュリティツールがリスクパターンを検出する助けにはなります。トークンローンチにおけるコントラクトのバイトコード
トークンローンチでは、コントラクトのバイトコードが実際のトークンルールを制御します。マーケティング資料に固定供給量、公平な配布、低い手数料、特別な管理者権限がないことなどが記載されていても、コントラクトがその主張を裏付けているか確認する必要があります。バイトコードには、ミント関数、バーン関数、税ルール、流動性管理、所有者権限、送金上限、緊急時の制御機能が定義されている場合があります。ソースコードが検証済みであれば、ユーザーや監査人はこうしたルールを確認しやすくなります。ソースコードが検証されていない場合、ユーザーはバイトコード分析ツールを使う必要があるか、透明性が高まるまで利用を避けるべきです。トークンの購入者は、バイトコードの基本を理解することで、トークン名やシンボルよりコントラクトアドレスが重要な理由を把握しやすくなります。異なるコントラクトが同じシンボルを使うことがあり、偽トークンが正規資産の名称を模倣する場合もあります。実際のオンチェーン上の動作を定義するのは、正規のコントラクトアドレスにあるバイトコードです。コントラクトのバイトコードとLayer 2ネットワーク
多くのLayer 2ネットワークはEVM互換のバイトコードをサポートしているため、開発者は類似したスマートコントラクトを複数のネットワークにデプロイできます。EVM互換性によって開発が容易になることがありますが、すべてのネットワークで実行、手数料、ブリッジ、セキュリティの特性が同じだと思い込んではいけません。ネットワークによって、オペコードの動作、プリコンパイル済みコントラクト、ガス体系、アカウントモデル、アップグレード時期が異なる場合があります。開発者は複数のチェーンにバイトコードをデプロイする前に、対象ネットワークのドキュメントを確認してください。ユーザーも、正しいネットワーク上の正しいコントラクトアドレスとやり取りしていることを確認する必要があります。見慣れたバイトコードに見えても、誤ったネットワークで資金を送ったり承認を付与したりすると、損失や混乱につながる可能性があります。コントラクトのバイトコードが読みづらい理由
コントラクトのバイトコードは人ではなく機械向けに設計されているため、読み解くのが困難です。通常は16進数で表示され、各バイトがデータまたは命令を表します。EVMはスタックベースのアーキテクチャを採用しているため、バイトコードを理解するには、多数の命令を通じてスタックの値を追跡することが必要になる場合があります。ジャンプ命令によって制御フローの把握が難しくなることがあります。コンパイラの最適化によってロジックがさらに圧縮、再配置される場合もあります。ライブラリ、プロキシ、メタデータ、コンストラクター引数、リンク済みアドレスも解釈に影響する可能性があります。そのため、多くのユーザーは生のバイトコードを直接読もうとせず、検証済みソースコード、監査、ウォレットの警告、信頼できる開発者向けツールを利用します。それでも、オンチェーンでの実行を最終的に決定するのはバイトコードであるため、その概念を理解することは重要です。よくある質問
コントラクトのバイトコードとは何ですか?
コントラクトのバイトコードとは、ブロックチェーンの仮想マシンがスマートコントラクトのために実行する、コンパイル済みの機械可読コードです。コントラクトのバイトコードはスマートコントラクトのソースコードと同じですか?
いいえ。ソースコードは人間が読める形式で、バイトコードはオンチェーンで実行されるコンパイル済みの形式です。コントラクトのバイトコードが重要なのはなぜですか?
デプロイ済みスマートコントラクトの実際の動作を制御し、暗号資産に直接影響する可能性があるためです。ユーザーはコントラクトのバイトコードを読めますか?
ほとんどのユーザーにとって生のバイトコードを読むのは困難ですが、開発者やセキュリティツールは逆アセンブルまたは分析できます。ランタイムバイトコードとは何ですか?
ランタイムバイトコードはデプロイ後にコントラクトアドレスに保存され、コントラクトの呼び出し時に実行されるコードです。作成バイトコードとは何ですか?
作成バイトコードは、コントラクトを作成してランタイムバイトコードを返すために1回実行されるデプロイ用コードです。ソースコードが検証済みなら、コントラクトは安全ですか?
いいえ。検証済みのソースコードは、公開されたソースコードをデプロイ済みバイトコードと照合できることを示すだけです。安全性は引き続き、コントラクトのロジックと権限に左右されます。デプロイ後にコントラクトのバイトコードを変更できますか?
通常、デプロイ済みのランタイムバイトコードは固定されています。ただし、アップグレード可能なプロキシ設計では、新しい実装バイトコードを指定することでアプリケーションの動作が変わる場合があります。オペコードとは何ですか?
オペコードとは、仮想マシンに特定の処理を指示するバイトコード内の低水準命令です。バイトコードでコンパイラのバージョンが重要なのはなぜですか?
同じソースコードでも、コンパイラのバージョンや設定が異なると、異なるバイトコードが生成されるためです。まとめ
コントラクトのバイトコードは、ブロックチェーン仮想マシン上で実行されるスマートコントラクトの実行形式です。ソースコードをコンパイルして生成され、ユーザーがコントラクトとやり取りする際にノードが実行する実際のロジックになります。暗号資産ユーザーにとってバイトコードが重要なのは、トークン、資金、承認、ガバナンス権、手数料、アップグレードなど、価値の高い操作を制御する可能性があるためです。開発者にとっては、コンパイラ設定、最適化の選択、コンストラクター引数、メタデータ、対象ネットワークのルールが、最終的にデプロイされる内容に影響するため重要です。監査人やセキュリティ研究者にとって、バイトコードはオンチェーン上の事実であり、主張されたソースコードや監査範囲と一致している必要があるため重要です。スマートコントラクトに分かりやすい名前、洗練されたウェブサイト、シンプルなインターフェースがあっても、ブロックチェーンが実際に従うのはバイトコードです。コントラクトのバイトコードを理解すれば、暗号資産ユーザーはより慎重な判断を行い、検証が重要な理由を把握し、あらゆるスマートコントラクトとのやり取りに伴うリスクをより適切に評価できます。関連コンテンツ
Peter Todd
Peter McCormack
パフォーマンスボンド(履行保証金)
ホット
現在、市場で大きな注目を集めているトレンドの暗号資産
トップ取引高
取引高が最も多い暗号資産

