スマートコントラクトから外部へ情報を伝える仕組みを学びましょう。
スマートコントラクトはブロックチェーン上で動作しますが、その内部状態の変化や特定の出来事を外部アプリケーション(DAppsのフロントエンドなど)やユーザーに効率的に知らせる仕組みが必要です。それが「イベント」と「ログ」です。イベントを使うことで、コントラクトは実行中に特定の情報をブロックチェーンのログ領域に記録できます。このログは、外部から比較的低コストでアクセス・監視することが可能です。
イベントは、オンチェーンのトランザクション実行結果をオフチェーンの世界に伝えるための重要な橋渡し役となります。
イベントの定義
Solidityでは、event
キーワードを使ってイベントを定義します。関数定義に似ていますが、引数にはイベントで記録したいデータの型と名前を指定します。
上記の例では、Transfer
、ItemCreated
、ActionCompleted
という3つのイベントを定義しています。各イベントには、記録したい情報の種類に応じたパラメータが設定されています。
パラメータ名の前に indexed
キーワードを付けることができます(詳細は後述)。
イベントの発行 (emit)
定義したイベントは、コントラクト内の関数実行中に emit
キーワードを使って発行(記録)します。イベントを発行する際には、定義したパラメータに対応する値を渡します。
transfer
関数では、送金処理が成功した後に Transfer
イベントを発行し、送金元、送金先、送金額を記録しています。
createItem
関数では、新しいアイテムが作成された際に ItemCreated
イベントを発行し、アイテムID、名前、所有者を記録しています。
イベントの発行自体は、コントラクトの状態変数を変更するよりもガス代が安価な操作です。そのため、状態変化そのものではなく、変化があったことを通知する目的でよく利用されます。
インデックス化されたパラメータ (indexed)
イベントのパラメータに indexed
キーワードを付けると、そのパラメータの値を使ってログを効率的に検索・フィルタリングできるようになります。これは、DAppsのフロントエンドなどが特定の条件に合致するイベントログだけを素早く見つけるのに役立ちます。
特徴:
indexed
を付けたパラメータは「トピック (Topic)」として扱われ、ログの特別な領域に保存されます。- トピックを使うと、特定のアドレスやIDに関連するイベントログを高速に検索できます。例えば、「特定のアドレスが関与した全てのTransferイベント」や「特定の所有者が作成した全てのItemCreatedイベント」を探すことが容易になります。
indexed
を付けられるパラメータの数には制限があります。通常、1つのイベントにつき最大3つまでです。(匿名イベントの場合は4つまで)。indexed
を付けなかったパラメータの値は、ログのデータ部分にABIエンコードされて保存されます。これらはトピックによる直接的なフィルタリングはできませんが、ログを取得した後に内容を確認することは可能です。- 参照型(
string
,bytes
, 配列, 構造体)をindexed
にすると、そのデータのハッシュ値がトピックとして保存されます。元の値そのものではない点に注意が必要です。
indexed
にするかは、アプリケーションがどのようにイベントログを検索・利用するかを考慮して慎重に決める必要があります。検索対象としたいキー情報を indexed
にするのが一般的です。
ログの取得と利用方法
スマートコントラクトが発行したイベントログは、ブロックチェーン上に記録されます。これらのログは、Ethereumクライアントが提供するAPI(JSON-RPC API)を通じて取得できます。
代表的なAPIエンドポイント:
eth_getLogs
: 過去のブロックに含まれるログを、コントラクトアドレスやトピック(indexedパラメータの値)などの条件を指定して一括で取得します。eth_subscribe
: 新しいブロックが生成された際に、指定した条件に合致する新しいログが発生したらリアルタイムで通知を受け取ります(WebSocket接続などが必要)。
通常、DAppsの開発では、これらの低レベルAPIを直接扱うのではなく、web3.js や ethers.js といったJavaScriptライブラリを使用します。これらのライブラリは、イベントログの取得や購読をより簡単に行うための便利な機能を提供しています。
このように、フロントエンドやバックエンドのアプリケーションは、イベントログを監視することで、コントラクトの状態変化を検知し、UIの更新、データベースへの記録、他のシステムへの通知など、様々なアクションを実行できます。
具体的なライブラリの使い方やフロントエンドとの連携については、「Step 7: 実践的なDApp開発」で詳しく解説しますので、ここでは概念を理解しておきましょう。
イベントの主なユースケース
イベントは様々な目的で利用されます。主なユースケースをいくつか見てみましょう。
ユースケース | 説明 | 例 |
---|---|---|
状態変化の通知 | コントラクトの重要な状態が変わったことをオフチェーンアプリケーションに知らせる。 | ERC-20トークンのTransfer イベント、ERC-721 NFTの所有権移転を示すTransfer イベント、ガバナンス投票の結果通知、オークションの終了通知など。 |
オフチェーンデータの同期 | イベントログを監視し、その情報を元に外部データベースやキャッシュを更新する。 | ユーザーのトークン残高をデータベースに記録する、NFTのメタデータを外部サーバーで管理する際のトリガーとする。 |
安価なデータ記録 | コントラクトのストレージに直接書き込むよりもガス代が安いため、履歴データやログ情報を記録する手段として利用する。ただし、コントラクト内からログデータを直接読み取ることはできません。 | ユーザーアクションの監査ログ、システムパラメータ変更の履歴など。 |
デバッグ | 開発中に特定のコードパスが実行されたことや、その時点での変数の値などを確認するために一時的にイベントを発行する。 | emit DebugLog("Reached point A", value); のように使用する。 |
外部システム連携 | イベントをトリガーとして、他のブロックチェーンやオフチェーンのシステム(API、サーバーレス関数など)を起動する。 | 特定のイベント発生時に、Chainlinkなどのオラクルサービスを利用して外部APIを呼び出す、など。(高度な応用例) |
まとめ
今回は、スマートコントラクトから外部へ情報を伝えるための重要な仕組みである「イベント」と「ログ」について学びました。
- イベントは
event
キーワードで定義し、emit
キーワードで発行します。 - パラメータに
indexed
を付けることで、ログの検索・フィルタリングが効率化されます。 - イベントログは、DAppsフロントエンドなどがコントラクトの状態変化を監視するために不可欠です。
- web3.jsやethers.jsなどのライブラリを使うと、ログの取得や購読が容易になります。
- 状態変化の通知、データ同期、安価なログ記録、デバッグなど、多様なユースケースがあります。
イベントをうまく活用することで、よりインタラクティブで効率的なDAppsを構築できます。しっかり理解しておきましょう!
次は、コントラクトの実行時エラーを適切に処理するための「エラー処理(require, revert, assert)」について学びます。