WebSocket サブスクリプション

BlockVectra の WebSocket エンドポイントに接続して、eth_subscribe による newHeads や logs を利用します。接続方法、フィルター規則、再接続バックオフ、復旧について説明します。

BlockVectra は、標準的な JSON-RPC リクエストとともにリアルタイムの Ethereum イベント購読をストリーミングするためのセキュアな WebSocket 接続(wss://)を提供します。

WebSocket、Webhook、またはポーリングの選択

アプリケーションが接続を維持できる場合は、リアルタイムの newHeads やフィルタリングされた logs に WebSocket を使用します。監視対象ウォレットのアクティビティを HTTPS エンドポイントで受信し、生ボディの署名検証、再試行、保持された一致イベントのリプレイを利用するには、ブロックチェーン Webhook API を使用します。定期的な ERC-20 決済の監視や過去のログのバックフィルには、HTTP ポーリング を使用します。ステーブルコインガイドには USDT / USDC Webhook 受信側 の例も記載されています。開発者や AI エージェント向けのチェーン対応、受信側の要件、復旧のトレードオフに関するアーキテクチャの比較については、Webhook、WebSocket、または RPC ポーリングの選択ガイド を参照してください。

WebSocket のサポートは GET /v1/chains の ws と subscriptions で確認できます。Push のサポートは認証付きの GET /v1/push/chains リストで確認できます。WebSocket に対応していないチェーンでも、リストに含まれていればアドレス Webhook を利用できます。

WebSocket の切断時は再購読とバックフィルが必要であり、Push の制御イベントである subscription.gap や chain.reorg は発行されません。Webhook の場合、ギャップには範囲スキャンが必要であり、再編成(reorg)通知では、自動再配信される正規イベントを保持する前に、置き換えられたイベントをマークまたは破棄する必要があります。Push のリプレイ は保持された一致イベントを再送するものであり、アドレスやチェーンが追加される前や購読がオフラインであった期間のデータを再送するものではありません。復旧を実装する際は、課金ルール と エラーリファレンス を確認してください。

利用可能なチェーン

ネットワーク上で WebSocket 購読がアクティブかどうかは、GET /v1/chains の ws(ブール値)および subscriptions(サポートされるタイプの配列)を読み取ることで確認できます。

以下の表は、WebSocket サポートが有効になっているネットワークを示しています:

チェーンWebSocket エンドポイント(パスに Key を含む)
Robinhood Chainwss://api.blockvectra.com/v1/robinhood_mainnet/{api_key}
Robinhood Chain Testnetwss://api.blockvectra.com/v1/robinhood_testnet/{api_key}

接続と認証

クライアントはセキュアな TLS WebSocket 接続(wss://)を確立します。API key は次の 2 つの方法で指定できます:

  • パス指定のキー:wss://api.blockvectra.com/v1/{chain}/{api_key}
  • ヘッダー指定のキー:HTTP Upgrade ハンドシェイク時に x-api-key: {api_key} または Authorization: Bearer {api_key} ヘッダーを付与した wss://api.blockvectra.com/v1/{chain}。

パス指定のキーがある場合、パス指定のキーが使用され、両方の認証ヘッダーは無視されます。パス指定のキーがない場合、空でない x-api-key が Authorization: Bearer より優先されます。ブラウザの WebSocket API ではこれらのヘッダーを設定できないため、パス指定のキーを含む URL を使用してください。

ハンドシェイクの入場チェック

ハンドシェイクは以下の場合に失敗することがあります:

  • 認証:API key が指定されていない場合は HTTP 401(missing_api_key)が返されます。API key が不明、無効、または失効している場合は HTTP 401(invalid_api_key)が返されます。認証サービスが一時的に利用できない場合、応答は HTTP 503(auth_unavailable)になります。
  • アカウント残高:前払い残高がゼロまたはマイナスのアカウントには HTTP 402(balance_exhausted)が返されます。課金ステータスを確認できない場合、応答は HTTP 503(billing_unavailable)になります。
  • 接続制限:キーあたりの制限(20 接続)またはアカウントあたりの制限(50 接続)を超えると、HTTP 429(ws_connection_limit)が返されます。
  • チェーンの利用可能性:不明または未提供のチェーンを要求すると、HTTP 404(unknown_chain)が返されます。
  • サーバー容量:サーバーがビジーまたは過負荷の場合、ハンドシェイクは Retry-After ヘッダー付きで HTTP 503(overloaded)を返します。

接続が確立されると、クライアントは標準の JSON-RPC 2.0 リクエスト(eth_blockNumber や eth_call など)および UTF-8 テキストフレームとしてフォーマットされた購読制御メソッドを送信できます。

課金ルール

  • 接続の確立、アイドル接続の維持、および ping/pong ハートビートは課金されません。
  • false を返す unsubscribe を含め、成功した eth_subscribe および eth_unsubscribe の呼び出しは課金されます。失敗した呼び出しは課金されません。通常の JSON-RPC 呼び出しは JSON-RPC 課金ルール に従います。
  • newHeads 通知は、その接続がいくつの newHeads 購読を持っているかに関係なく、接続あたりのブロックハッシュごとに 1 回カウントされます。
  • logs 通知は、一致するログがあるブロックハッシュおよびフェーズごとに、購読あたり 1 回カウントされます。一致のないブロックは課金されません。同じブロックおよびフェーズ内で複数のログが一致しても、課金額が増加することはありません。フィルターが重複していても、個別の購読は別々にカウントされます。再編成ログ(removed: true)は別個のユニットを構成します。同じ高さの置き換えブロックは異なるハッシュを持ち、異なるユニットとなります。
  • 通知は、ソケット送信バッファに正常にフラッシュされた後にのみ課金されます。キューに入れられたままフラッシュされなかった通知や破棄された通知は課金されません。eth_unsubscribe の応答前にキューに入れられた通知は、フラッシュされた場合にカウントされます。WebSocket メッセージには HTTP 課金ヘッダーが付与されません。計測された CU についてはアカウントの使用状況を参照してください。

購読メソッド

API は標準的な Ethereum の pub/sub インターフェースである eth_subscribe および eth_unsubscribe を実装しています。

newHeads

新しいブロックがチェーンヘッドに追加されるたびに、新しいブロックヘッダーオブジェクトを発行します。

  • 購読リクエスト:
    {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
  • 購読レスポンス:不透明な 16 進数の購読識別子を返します:
    {"jsonrpc":"2.0","id":1,"result":"0x1"}
  • プッシュ通知フレーム:
    {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}

logs

指定されたフィルター条件に一致するログイベントを発行します。

  • フィルター要件:すべての logs 購読フィルターには、address(コントラクトアドレスまたはアドレスの配列)または topic0(最初のトピック位置、null 不可)を必ず指定する必要があります。どちらも指定されていないフィルター({} や {"topics":[null,"0x..."]} など)は、エラーコード -32602(logs_filter_required)で拒否されます。

  • フィルター制限:最大 100 アドレス。最大 4 つのトピック位置(位置ごとに最大 16 個の候補ハッシュ)。

  • フィルター容量:アクティブなログフィルターが上限容量に達した場合、購読はエラーコード -32022(ws_filter_capacity)を返します。

  • チェーンの再編成:チェーンの再編成によりブロックが削除された場合、削除されたログのログ通知には "removed": true が付与されます。

  • 購読リクエスト:

    {"jsonrpc":"2.0","id":2,"method":"eth_subscribe","params":["logs",{"address":"0x1234567890123456789012345678901234567890"}]}

eth_unsubscribe

購読識別子を使用してアクティブな購読を終了します。

  • 購読解除リクエスト:
    {"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
  • 購読解除レスポンス:
    {"jsonrpc":"2.0","id":3,"result":true}

実行可能なサンプル

viem v2 を使用し、createPublicClient と webSocket トランスポートを介して接続します。{chain} を対象チェーンの識別子に、{api_key} をご自身の API key に置き換えてください:

import { createPublicClient, webSocket } from 'viem';

const apiKey = process.env.BLOCKVECTRA_API_KEY || '{api_key}';
const url = `wss://api.blockvectra.com/v1/robinhood_mainnet/${apiKey}`;

const client = createPublicClient({
  transport: webSocket(url),
});

// 1. Subscribe to new block headers (newHeads)
const unwatchBlocks = client.watchBlocks({
  onBlock: (block) => {
    console.log('New block header received:', block.number, block.hash);
  },
  onError: (error) => {
    console.error('watchBlocks error:', error);
  },
});

// 2. Subscribe to contract event logs (filter requires address or topic0)
const unwatchEvents = client.watchEvent({
  address: '0x1234567890123456789012345678901234567890',
  onLogs: (logs) => {
    console.log('Matching logs received:', logs);
  },
  onError: (error) => {
    console.error('watchEvent error:', error);
  },
});

クローズコードとクライアントのアクション

サーバーが WebSocket セッションを終了する場合、特定のクローズコードと短い理由を含む Close フレームを送信します。以下の表は、サーバーから発行されるクローズコードと推奨されるアクションの一覧です:

クローズコード理由文字列説明再試行可能クライアントのアクション
1001idle3600 秒(1 時間)購読やメッセージがない非アクティブな接続はい必要に応じて再接続します。
1003binary frames are not acceptedバイナリ WebSocket フレームを受信。UTF-8 テキストフレームのみ対応いいえ自動再接続は行わないでください。テキストフレームを送信するようにクライアントを更新してください。
1009message too large受信ペイロードが 1 MiB を超過いいえ自動再接続は行わないでください。大きなリクエストを分割するか、ペイロードサイズを縮小してください。
1012service restartサーバーの再起動、またはセッションが最大有効期間(24 時間)に到達はいランダム化されたジッターバックオフを使用して再接続し、購読を再確立して、取り逃したデータをバックフィルします。
1013chain unavailableチェーンが利用不可はいフルジッター指数バックオフを使用して再接続し、購読を再確立して、取り逃したデータをバックフィルします。
1013overloadedサーバーの一時的な過負荷はいフルジッター指数バックオフを使用して再接続し、購読を再確立して、取り逃したデータをバックフィルします。
4402insufficient balanceアカウント残高不足いいえ自動再接続は行わないでください。残高をチャージしてから再接続してください。
4404invalid api keyAPI key が不明、無効、または失効いいえ自動再接続は行わないでください。再接続する前に、コンソールで API key を確認またはローテーションしてください。
4408slow consumerサーバーはプッシュキューが 512 KiB を超えたセッションをクローズし、保留中の通知を破棄。クライアントはクローズフレームを受信しない場合あり(ブラウザは 1006 を報告)はい予期せぬ切断(クローズフレームを受信できず、ブラウザが 1006 を報告)を 4408 と同様に扱います:バックオフを伴って再接続し、購読を再確立して、破棄されたデータを eth_getLogs でバックフィルします。購読数を減らすか、読み取り速度を上げてください。
4429push rate exceeded通知レートが 1,000 プッシュ/秒を超過はい購読を減らすかフィルターを絞り込みます。バックオフを伴って再接続し、再購読して、バックフィルします。
4503billing unavailable課金サービスが一時的に利用不可はい一時的な状態です。フルジッター指数バックオフを使用して再接続してください。

再接続と指数バックオフ

接続が切断された際に同期的な再接続スパイクを防ぐため、クライアントはフルジッターを伴う指数バックオフを実装する必要があります:

  • バックオフ計算式:n 回目の再接続試行(n = 0, 1, 2, ...)の前に、一様ランダムに選択された待機時間だけ待機します:
    delay = random(0, min(20s, 0.5s * 2^n))
  • カウンターのリセット:中断のない安定した接続を少なくとも 60 秒 間維持した後にのみ、再試行カウンター n を 0 にリセットします。
  • クローズコード 1012:同期的な再接続スパイクを回避するため、初回の再接続試行の前にランダム化された初期遅延を導入します。
  • 再試行不可のコード:4402、4404、1003、または 1009 の場合は自動再接続を行わないでください。

再接続後の取り逃したデータのバックフィル

WebSocket 購読は接続をまたいで持続しません。切断中に発行された通知がサーバー側に保持されることはありません。再接続後、クライアントは以下のキャッチアップ戦略を実行する必要があります:

  1. eth_getLogs によるログのバックフィル:
    • 正常に処理された最大のブロック番号(last_processed_block)を永続化しておきます。
    • 再接続時に直ちに eth_subscribe("logs", ...) を呼び出して、リアルタイムイベントをキャプチャします。
    • fromBlock: last_processed_block + 1 および toBlock: "latest"(またはリアルタイムストリームから受信した最初のブロック)を指定して eth_getLogs で取り逃したブロックを照会します。
    • 切断ギャップがネットワークの max_logs_block_range(GET /v1/chains より取得)を超える場合は、その制限を超えないチャンクにクエリを分割します。
    • 一意のタプル (blockHash, transactionHash, logIndex) を使用して、クエリ境界をまたぐログエントリの重複を排除します。
  2. eth_getBlockByNumber によるブロックヘッダーのバックフィル:
    • 切断前に受信した最新のブロック番号とハッシュを記録しておきます。
    • newHeads を再購読します。
    • eth_getBlockByNumber("latest", false) を照会し、欠落している中間ブロックを順次取得します。親ハッシュ(parentHash)のチェーン連続性を検証して再編成を検出します。

制限事項

制限項目値超過時の結果
WebSocket 接続あたりの購読数100-32022 subscription_limit
WebSocket 接続あたりの newHeads 購読数4-32022 subscription_limit
logs 購読フィルター要件address または topic0(topics の先頭位置)の指定が必須-32602 logs_filter_required

次のステップ

最終更新:

このページの目次