Підписки через WebSocket

Підключайтеся до WebSocket-ендпоінтів BlockVectra для eth_subscribe newHeads та logs. Дізнайтеся про методи підключення, правила фільтрації, затримку перепідключення та відновлення даних.

BlockVectra надає безпечні з'єднання WebSocket (wss://) для потокової передачі підписок на події Ethereum у реальному часі разом зі стандартними запитами JSON-RPC.

Вибір WebSocket, Webhook або опитування

Використовуйте WebSocket для отримання newHeads та відфільтрованих logs у реальному часі, коли ваш застосунок здатний підтримувати постійне з'єднання. Використовуйте Blockchain Webhook API для отримання активності відстежуваних гаманців на ендпоінт HTTPS із перевіркою підписів сирого тіла, повторними спробами та повторним відтворенням збережених збігів. Використовуйте опитування через HTTP для запланованого моніторингу платежів ERC-20 та відновлення історичних логів. Посібник зі стейблкоїнів також містить приклад отримувача вебхуків для USDT / USDC. Архітектурне порівняння підтримки мереж, вимог до отримувача та компромісів відновлення для розробників та AI-агентів див. у посібнику з вибору між вебхуками, WebSocket або опитуванням RPC.

Підтримка WebSocket визначається полями ws та subscriptions у GET /v1/chains; підтримка Push — автентифікованим списком GET /v1/push/chains. Мережа без WebSocket усе одно може використовувати вебхуки для адрес, якщо вона присутня в цьому списку.

Розриви з'єднання WebSocket вимагають повторної підписки та заповнення пропущених даних; вони не генерують керуючі події Push subscription.gap або chain.reorg. Для вебхуків виникнення прогалини потребує сканування діапазону; сповіщення про реорганізацію вимагає позначення або відкидання замінених подій перед збереженням автоматично повторно доставлених канонічних подій. Повторне відтворення Push повторно надсилає збережені збіги, а не дані до додавання адреси або мережі чи під час перебування підписки офлайн. Перегляньте правила тарифікації та довідник помилок під час реалізації відновлення.

Доступні мережі

Ви можете перевірити, чи активні підписки WebSocket у певній мережі, прочитавши значення ws (boolean) та subscriptions (масив підтримуваних типів) у GET /v1/chains.

У наведеній нижче таблиці відображено мережі, для яких увімкнено підтримку WebSocket:

МережаЕндпоінт WebSocket (ключ у шляху)
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 можна надати двома способами:

  • Ключ у шляху: wss://api.blockvectra.com/v1/{chain}/{api_key}
  • Ключ у заголовку: wss://api.blockvectra.com/v1/{chain} із заголовком x-api-key: {api_key} або Authorization: Bearer {api_key} під час рукостискання оновлення протоколу HTTP (HTTP Upgrade).

Якщо передано ключ у шляху, використовується саме він, а обидва заголовки автентифікації ігноруються. Без ключа у шляху непорожній заголовок x-api-key має пріоритет над Authorization: Bearer. Браузерні API WebSocket не дозволяють встановлювати ці заголовки; використовуйте 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).
  • Ємність сервера: коли сервер зайнятий або перевантажений, рукостискання повертає HTTP 503 (overloaded) із заголовком Retry-After.

Після підключення клієнти можуть надсилати стандартні запити JSON-RPC 2.0 (такі як eth_blockNumber або eth_call) та методи керування підписками у вигляді текстових фреймів UTF-8.

Правила тарифікації

  • Встановлення з'єднання, підтримка простою відкритого з'єднання та перевірки пульсу ping/pong не тарифікуються.
  • Успішні виклики eth_subscribe та eth_unsubscribe тарифікуються, включно зі скасуванням підписки, що повертає false; невдалі виклики не тарифікуються. Звичайні виклики JSON-RPC підпорядковуються правилам тарифікації JSON-RPC.
  • Сповіщення newHeads враховуються один раз на хеш блоку для кожного з'єднання, незалежно від того, скільки підписок newHeads відкрито на цьому з'єднанні.
  • Сповіщення logs враховуються один раз на підписку для кожного хешу блоку та фази з відповідними логами; блоки без збігів не тарифікуються. Кілька відповідних логів в одному блоці та фазі не збільшують плату. Окремі підписки рахуються окремо, навіть якщо їхні фільтри перекриваються. Логи реорганізації (removed: true) утворюють окрему одиницю; замінений блок на тій самій висоті має інший хеш і є іншою одиницею.
  • Сповіщення тарифікуються лише після їхнього успішного скидання у буфер надсилання сокета; сповіщення в черзі або відкинуті сповіщення, які не були скинуті в сокет, не тарифікуються. Сповіщення, що потрапили в чергу до відповіді на eth_unsubscribe, враховуються, якщо вони були скинуті в буфер. Повідомлення WebSocket не містять заголовків тарифікації HTTP; перевіряйте використання акаунта щодо нарахованих CU.

Методи підписки

API реалізує стандартний інтерфейс публікації/підписки Ethereum: eth_subscribe та eth_unsubscribe.

newHeads

Надсилає новий об'єкт заголовка блоку щоразу, коли новий блок додається до вершини ланцюга.

  • Запит на підписку:
    {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
  • Відповідь на підписку: повертає непрозорий шістнадцятковий ідентифікатор підписки:
    {"jsonrpc":"2.0","id":1,"result":"0x1"}
  • Фрейм push-сповіщення:
    {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}

logs

Надсилає події логів, що відповідають зазначеним критеріям фільтра.

  • Вимога до фільтра: кожен фільтр підписки logs повинен визначати address (адресу контракту або масив адрес) або topic0 (перша позиція теми, непорожня). Фільтр, у якому не вказано жодного з цих параметрів (наприклад, {} або {"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 із певним кодом закриття та коротким поясненням. У таблиці нижче наведено коди закриття, які видає сервер, та рекомендовані дії:

Код закриттяРядок причиниОписМожливість повторуДія клієнта
1001idleНеактивне з'єднання без підписок або повідомлень протягом 3600 секунд (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Сервер закриває сесію, черга push якої перевищує 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))
  • Скидання лічильника: скидайте лічильник спроб n на 0 лише після підтримки безперервного стабільного з'єднання протягом щонайменше 60 секунд.
  • Код закриття 1012: впроваджуйте рандомізовану початкову затримку перед першою спробою повторного підключення, щоб уникнути сплесків синхронних підключень.
  • Коди без можливості повтору: не перепідключайтеся автоматично у відповідь на 4402, 4404, 1003 або 1009.

Відновлення пропущених даних після повторного підключення

Підписки WebSocket не зберігаються між з'єднаннями; сповіщення, випущені під час розриву з'єднання, не зберігаються на сервері. Після відновлення підключення клієнтам слід виконати стратегію наздоганяння:

  1. Заповнення логів за допомогою eth_getLogs:
    • Зберігайте найбільший номер блоку, успішно оброблений застосунком (last_processed_block).
    • Одразу викличте eth_subscribe("logs", ...) після перепідключення, щоб отримувати події в реальному часі.
    • Запитуйте пропущені блоки через eth_getLogs із fromBlock: last_processed_block + 1 та toBlock: "latest" (або першим блоком, отриманим із живого потоку).
    • Якщо розрив з'єднання перевищує ліміт max_logs_block_range мережі (з GET /v1/chains), розбийте запити на частини, що не перевищують цей ліміт.
    • Дедуплікуйте записи логів на межі запитів за допомогою унікального кортежу (blockHash, transactionHash, logIndex).
  2. Заповнення заголовків блоків за допомогою eth_getBlockByNumber:
    • Зафіксуйте останній номер і хеш блоку, отримані перед розривом з'єднання.
    • Повторно підпишіться на newHeads.
    • Запитуйте eth_getBlockByNumber("latest", false) та послідовно вибирайте пропущені проміжні блоки. Перевіряйте неперервність ланцюжка parentHash для виявлення реорганізацій.

Ліміти

ЛімітЗначенняРезультат у разі перевищення
Підписок на одне з'єднання WebSocket100-32022 subscription_limit
Підписок newHeads на одне з'єднання WebSocket4-32022 subscription_limit
Вимоги до фільтра підписки logsНеобхідно вказати address або topic0 (перша позиція в topics)-32602 logs_filter_required

Наступні кроки

Востаннє оновлено:

На цій сторінці