Подписки WebSocket
Подключайтесь к WebSocket-эндпоинтам BlockVectra для eth_subscribe newHeads и logs. Изучите методы подключения, правила фильтрации, задержки при переподключении и восстановление.
BlockVectra предоставляет защищенные соединения WebSocket (wss://) для потоковой передачи подписок на события Ethereum в реальном времени наряду со стандартными запросами JSON-RPC.
Выбор WebSocket, Webhook или опроса
Используйте WebSocket для получения newHeads и отфильтрованных логов logs в реальном времени, когда ваше приложение способно поддерживать постоянное соединение. Используйте Blockchain Webhook API для получения активности отслеживаемых кошельков на HTTPS-эндпоинт с проверкой подписи исходного тела запроса, повторными попытками и повтором (replay) сохраненных совпадений. Используйте HTTP-опрос для периодического мониторинга платежей ERC-20 и довыгрузки исторических логов. В руководстве по стейблкоинам также показан приемник Webhook для USDT / USDC. Архитектурное сравнение поддержки сетей, требований к приемнику и компромиссов восстановления для разработчиков и AI Agent см. в руководстве по выбору Webhooks, WebSocket или RPC-опроса.
Поддержка WebSocket определяется полями ws и subscriptions в ответе GET /v1/chains; поддержка Push определяется списком аутентифицированного запроса GET /v1/push/chains. Сеть без поддержки WebSocket может использовать адресные Webhooks, если она присутствует в этом списке.
Отключения WebSocket требуют повторной подписки и довыгрузки данных; они не генерируют управляющие Push-события subscription.gap или chain.reorg. В случае Webhooks пропуск требует сканирования диапазона; уведомление о реорганизации требует пометить или отбросить замененные события перед сохранением автоматически повторно доставленных канонических событий. Replay в Push повторно отправляет сохраненные совпадения, но не данные до добавления адреса или сети либо за время нахождения подписки в статусе offline. При реализации восстановления ознакомьтесь с правилами тарификации и справочником ошибок.
Доступные сети
Вы можете проверить активность подписок WebSocket в сети, прочитав поля ws (boolean) и subscriptions (массив поддерживаемых типов) в ответе GET /v1/chains.
В таблице ниже представлены сети, в которых включена поддержка WebSocket:
| Сеть | Конечная точка WebSocket (Key в пути) |
|---|---|
| Robinhood Chain | wss://api.blockvectra.com/v1/robinhood_mainnet/{api_key} |
| Robinhood Chain Testnet | wss://api.blockvectra.com/v1/robinhood_testnet/{api_key} |
Подключение и аутентификация
Клиенты устанавливают защищенное соединение TLS WebSocket (wss://). API key можно передать двумя способами:
- Ключ в пути (Path key):
wss://api.blockvectra.com/v1/{chain}/{api_key} - Ключ в заголовке (Header key):
wss://api.blockvectra.com/v1/{chain}с заголовкомx-api-key: {api_key}илиAuthorization: Bearer {api_key}во время рукопожатия 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 heartbeats не тарифицируются.
- Успешные вызовы
eth_subscribeиeth_unsubscribeтарифицируются, включая отписку, вернувшуюfalse; вызовы, завершившиеся ошибкой, не тарифицируются. Обычные вызовы JSON-RPC следуют правилам тарификации JSON-RPC. - Уведомления
newHeadsучитываются один раз на хэш блока для каждого соединения независимо от того, сколько подписокnewHeadsоткрыто в этом соединении. - Уведомления
logsучитываются один раз на подписку для каждого хэша блока и фазы с совпадающими логами; блоки без совпадений не тарифицируются. Несколько совпадающих логов в одном блоке и фазе не увеличивают плату. Раздельные подписки учитываются отдельно, даже если их фильтры пересекаются. Логи реорганизации (removed: true) составляют отдельную единицу тарификации; замещающий блок на той же высоте имеет другой хэш и является другой единицей. - Уведомления тарифицируются только после успешного сброса в буфер отправки сокета; находящиеся в очереди или отброшенные уведомления, которые не были отправлены в сокет, не тарифицируются. Уведомления, поставленные в очередь до ответа на
eth_unsubscribe, учитываются, если они были отправлены в сокет. Сообщения WebSocket не содержат заголовков тарификации HTTP; проверяйте потребление учтенных CU в разделе использования аккаунта.
Методы подписки
API реализует стандартный интерфейс pub/sub 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(первая позиция в topic, не null). Фильтр, не указывающий ни того, ни другого (например,{}или{"topics":[null,"0x..."]}), отклоняется с кодом ошибки-32602(logs_filter_required). -
Лимиты фильтра: не более 100 адресов; не более 4 позиций topic с максимум 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 с определенным кодом закрытия и короткой причиной. В таблице ниже перечислены коды закрытия, отправляемые сервером, и рекомендуемые действия:
| Код закрытия | Причина (reason) | Описание | Повторяемый | Действие клиента |
|---|---|---|---|---|
| 1001 | idle | Неактивное соединение без подписок или сообщений в течение 3600 секунд (1 час) | Да | Переподключайтесь по мере необходимости. |
| 1003 | binary frames are not accepted | Получен бинарный фрейм WebSocket; поддерживаются только текстовые фреймы UTF-8 | Нет | Не переподключайтесь автоматически. Обновите клиент для отправки текстовых фреймов. |
| 1009 | message too large | Размер входящей полезной нагрузки превысил 1 МиБ | Нет | Не переподключайтесь автоматически. Разделите крупные запросы или уменьшите размер полезной нагрузки. |
| 1012 | service restart | Перезапуск сервера или сессия достигла максимального времени жизни (24 часа) | Да | Переподключитесь со случайной задержкой (jitter backoff), восстановите подписки и довыгрузите пропущенные данные. |
| 1013 | chain unavailable | Сеть недоступна | Да | Переподключитесь с полной экспоненциальной задержкой со случайным разбросом (full-jitter), восстановите подписки и довыгрузите пропущенные данные. |
| 1013 | overloaded | Сервер временно перегружен | Да | Переподключитесь с полной экспоненциальной задержкой со случайным разбросом (full-jitter), восстановите подписки и довыгрузите пропущенные данные. |
| 4402 | insufficient balance | Баланс аккаунта исчерпан | Нет | Не переподключайтесь автоматически. Пополните баланс, затем переподключитесь. |
| 4404 | invalid api key | API key неизвестен, отключен или отозван | Нет | Не переподключайтесь автоматически. Проверьте или обновите API key в консоли перед переподключением. |
| 4408 | slow consumer | Сервер закрывает сессию, чья очередь push превышает 512 КиБ, и сбрасывает ожидающие уведомления; клиенты могут не получить фрейм закрытия (браузер сообщает 1006) | Да | Обрабатывайте непредвиденные отключения (фрейм закрытия не получен, браузер сообщает 1006) аналогично коду 4408: переподключитесь с задержкой, восстановите подписки и довыгрузите сброшенные данные с помощью eth_getLogs; уменьшите количество подписок или считывайте быстрее. |
| 4429 | push rate exceeded | Скорость уведомлений превысила 1 000 push/секунду | Да | Уменьшите число подписок или сузьте фильтры; переподключитесь с задержкой, подпишитесь заново и довыгрузите данные. |
| 4503 | billing unavailable | Тарификация временно недоступна | Да | Переходное состояние; переподключитесь с полной экспоненциальной задержкой со случайным разбросом (full-jitter). |
Переподключение и экспоненциальная задержка
Для предотвращения шторма синхронных переподключений при обрыве соединений клиенты должны реализовать экспоненциальную задержку с полным случайным разбросом (full jitter):
- Формула задержки: перед n-й попыткой переподключения (n = 0, 1, 2, ...) подождите промежуток времени, выбранный равномерно случайным образом:
delay = random(0, min(20s, 0.5s * 2^n)) - Сброс счетчика: сбрасывайте счетчик повторов n в 0 только после поддержания непрерывного стабильного соединения в течение не менее
60 seconds. - Код закрытия 1012: добавьте случайную начальную задержку перед первой попыткой переподключения, чтобы избежать синхронных пиков повторных подключений.
- Неповторяемые коды: не переподключайтесь автоматически при кодах 4402, 4404, 1003 или 1009.
Довыгрузка пропущенных данных после переподключения
Подписки WebSocket не сохраняются между соединениями; уведомления, отправленные во время отключения, не сохраняются на сервере. После переподключения клиенты должны реализовать стратегию наверстывания (catch-up):
- Довыгрузка логов с помощью
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).
- Сохраняйте максимальный номер блока, успешно обработанный вашей системой (
- Довыгрузка заголовков блоков с помощью
eth_getBlockByNumber:- Зафиксируйте последний номер блока и его хэш, полученные перед отключением.
- Подпишитесь заново на
newHeads. - Запросите
eth_getBlockByNumber("latest", false)и последовательно получите недостающие промежуточные блоки. Проверяйте непрерывность цепочки поparentHashдля выявления реорганизаций.
Лимиты
| Лимит | Значение | Результат при превышении |
|---|---|---|
| Подписок на соединение WebSocket | 100 | -32022 subscription_limit |
Подписок newHeads на соединение WebSocket | 4 | -32022 subscription_limit |
Требования к фильтру подписки logs | Необходимо указать address или topic0 (первая позиция в topics) | -32602 logs_filter_required |
Следующие шаги
- Изучите каталог наборов данных, чтобы увидеть все наборы данных, индексируемые BlockVectra.
- Посмотрите бесплатный тариф и цены, чтобы узнать, что включено в ваш аккаунт.
- Войдите в консоль, чтобы создать API key.
Последнее обновление: