Assinaturas via WebSocket

Conecte-se aos endpoints WebSocket da BlockVectra para eth_subscribe newHeads e logs. Conheça métodos de conexão, regras de filtro, recuo de reconexão e recuperação.

A BlockVectra fornece conexões WebSocket seguras (wss://) para streaming de assinaturas de eventos Ethereum em tempo real juntamente com requisições JSON-RPC padrão.

Escolher WebSocket, Webhook ou polling

Use WebSocket para newHeads em tempo real e logs filtrados quando sua aplicação puder manter uma conexão. Use a API de Webhooks de Blockchain para receber a atividade de carteiras monitoradas em um endpoint HTTPS, com verificação de assinatura no corpo bruto, novas tentativas e replay de correspondências retidas. Use polling via HTTP para monitoramento agendado de pagamentos ERC-20 e recuperação de logs históricos. O guia de stablecoins também apresenta um receptor de Webhooks para USDT / USDC. Para uma comparação arquitetural abrangendo suporte a redes, requisitos de receptor e trade-offs de recuperação para desenvolvedores e agentes de IA, consulte o guia de escolha entre Webhooks, WebSocket ou polling de RPC.

O suporte a WebSocket vem de ws e subscriptions em GET /v1/chains; o suporte a Push vem da lista autenticada GET /v1/push/chains. Uma rede sem suporte a WebSocket ainda pode usar Webhooks de endereços se estiver listada ali.

Desconexões de WebSocket exigem nova assinatura e preenchimento de histórico; elas não emitem os eventos de controle de Push subscription.gap ou chain.reorg. Para Webhooks, uma lacuna requer varredura de intervalo; uma notificação de reorg requer que eventos substituídos sejam marcados ou descartados antes de manter os eventos canônicos reenviados automaticamente. O replay de Push reenvia correspondências retidas, e não dados anteriores à inclusão de um endereço ou rede, ou enquanto a assinatura estava offline. Revise as regras de cobrança e a referência de erros ao implementar a recuperação.

Redes disponíveis

Você pode verificar se assinaturas via WebSocket estão ativas em uma rede lendo ws (booleano) e subscriptions (array de tipos suportados) em GET /v1/chains.

A tabela abaixo reflete as redes onde o suporte a WebSocket está habilitado:

RedeEndpoint WebSocket (chave no caminho)
Robinhood Chainwss://api.blockvectra.com/v1/robinhood_mainnet/{api_key}
Robinhood Chain Testnetwss://api.blockvectra.com/v1/robinhood_testnet/{api_key}

Conexão e autenticação

Os clientes estabelecem uma conexão WebSocket TLS segura (wss://). A API key pode ser fornecida de duas maneiras:

  • Chave no caminho: wss://api.blockvectra.com/v1/{chain}/{api_key}
  • Chave no cabeçalho: wss://api.blockvectra.com/v1/{chain} com o cabeçalho x-api-key: {api_key} ou Authorization: Bearer {api_key} durante o handshake HTTP Upgrade.

Com uma chave no caminho, a chave do caminho é usada e ambos os cabeçalhos de autenticação são ignorados. Sem uma chave no caminho, um x-api-key não vazio tem precedência sobre Authorization: Bearer. APIs de WebSocket em navegadores não podem definir esses cabeçalhos; utilize a URL com a chave no caminho.

Verificações de admissão no handshake

O handshake pode falhar com:

  • Autenticação: Uma API key ausente retorna HTTP 401 (missing_api_key); uma API key desconhecida, desativada ou revogada retorna HTTP 401 (invalid_api_key); se a autenticação estiver temporariamente indisponível, a resposta será HTTP 503 (auth_unavailable).
  • Saldo da conta: Uma conta com saldo pré-pago zero ou negativo retorna HTTP 402 (balance_exhausted); se o estado de cobrança não puder ser confirmado, a resposta será HTTP 503 (billing_unavailable).
  • Limites de conexão: Ultrapassar o limite por chave (20 conexões) ou o limite por conta (50 conexões) retorna HTTP 429 (ws_connection_limit).
  • Disponibilidade da rede: Requisitar uma rede desconhecida ou não atendida retorna HTTP 404 (unknown_chain).
  • Capacidade do servidor: Quando o servidor estiver ocupado ou sobrecarregado, o handshake retornará HTTP 503 (overloaded) com um cabeçalho Retry-After.

Uma vez conectados, os clientes podem enviar requisições JSON-RPC 2.0 padrão (como eth_blockNumber ou eth_call) e métodos de controle de assinatura formatados como quadros de texto UTF-8.

Regras de cobrança

  • Estabelecer uma conexão, manter uma conexão ociosa aberta e batimentos de coração ping/pong não são cobrados.
  • Chamadas bem-sucedidas a eth_subscribe e eth_unsubscribe são cobradas, incluindo um cancelamento de assinatura que retorne false; chamadas com falha não são cobradas. Chamadas JSON-RPC comuns seguem as regras de cobrança de JSON-RPC.
  • Notificações de newHeads contam uma vez por hash de bloco por conexão, independentemente de quantas assinaturas newHeads a conexão tiver.
  • Notificações de logs contam uma vez por assinatura por hash de bloco e fase com logs correspondentes; blocos sem correspondências não são cobrados. Vários logs correspondentes no mesmo bloco e fase não multiplicam a cobrança. Assinaturas separadas contam separadamente, mesmo quando seus filtros se sobrepõem. Logs de reorganização (removed: true) formam uma unidade separada; um bloco de substituição na mesma altura tem um hash diferente e é uma unidade diferente.
  • Notificações são cobradas apenas após serem descarregadas com sucesso no buffer de envio do socket; notificações enfileiradas ou descartadas que não foram descarregadas não são cobradas. Notificações enfileiradas antes da resposta de um eth_unsubscribe contam se forem descarregadas. Mensagens WebSocket não carregam cabeçalhos HTTP de cobrança; consulte o consumo da conta para ver as CU medidas.

Métodos de assinatura

A API implementa a interface pub/sub padrão do Ethereum: eth_subscribe e eth_unsubscribe.

newHeads

Emite um novo objeto de cabeçalho de bloco sempre que um novo bloco for anexado ao topo da cadeia.

  • Requisição de assinatura:
    {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
  • Resposta da assinatura: Retorna um identificador de assinatura hexadecimal opaco:
    {"jsonrpc":"2.0","id":1,"result":"0x1"}
  • Quadro de notificação push:
    {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}

logs

Emite eventos de log que correspondem aos critérios de filtro especificados.

  • Exigência de filtro: Todo filtro de assinatura de logs deve especificar um address (um endereço de contrato ou array de endereços) ou um topic0 (a primeira posição de tópico, não nula). Um filtro que não especifique nenhum dos dois (como {} ou {"topics":[null,"0x..."]}) é rejeitado com o código de erro -32602 (logs_filter_required).

  • Limites de filtros: No máximo 100 endereços; no máximo 4 posições de tópicos com no máximo 16 hashes candidatos por posição.

  • Capacidade de filtros: Se os filtros de log ativos atingirem a capacidade máxima, a assinatura retornará o código de erro -32022 (ws_filter_capacity).

  • Reorganizações de cadeia: Se um bloco for removido devido a uma reorg de cadeia, as notificações de log para os logs removidos trarão "removed": true.

  • Requisição de assinatura:

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

eth_unsubscribe

Encerra uma assinatura ativa usando o identificador da assinatura.

  • Requisição de cancelamento de assinatura:
    {"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
  • Resposta do cancelamento de assinatura:
    {"jsonrpc":"2.0","id":3,"result":true}

Exemplos executáveis

Conecte-se usando o viem v2 via createPublicClient e o transporte webSocket. Substitua {chain} pelo identificador da rede de destino e {api_key} pela sua 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);
  },
});

Códigos de encerramento e ações do cliente

Quando o servidor encerra uma sessão WebSocket, ele envia um quadro Close com um código de encerramento específico e um motivo curto. A tabela abaixo lista os códigos de encerramento emitidos pelo servidor e as ações recomendadas:

Código de encerramentoString de motivoDescriçãoRepetívelAção do cliente
1001idleConexão inativa sem assinaturas ou mensagens por 3600 segundos (1 hora)SimReconecte conforme necessário.
1003binary frames are not acceptedQuadro WebSocket binário recebido; apenas quadros de texto UTF-8 são aceitosNãoNão reconecte automaticamente. Atualize o cliente para enviar quadros de texto.
1009message too largeCarga útil recebida excedeu 1 MiBNãoNão reconecte automaticamente. Divida requisições grandes ou reduza o tamanho da carga útil.
1012service restartServidor reiniciando ou a sessão atingiu o tempo de vida máximo (24 horas)SimReconecte usando recuo com jitter aleatório, restabeleça as assinaturas e recupere dados perdidos.
1013chain unavailableRede indisponívelSimReconecte usando recuo exponencial com full jitter, restabeleça as assinaturas e recupere dados perdidos.
1013overloadedServidor temporariamente sobrecarregadoSimReconecte usando recuo exponencial com full jitter, restabeleça as assinaturas e recupere dados perdidos.
4402insufficient balanceSaldo da conta esgotadoNãoNão reconecte automaticamente. Recarregue seu saldo e reconecte.
4404invalid api keyA API key é desconhecida, está desativada ou foi revogadaNãoNão reconecte automaticamente. Verifique ou rotacione a API key no console antes de reconectar.
4408slow consumerO servidor fecha uma sessão cuja fila de envio ultrapassa 512 KiB e descarta notificações pendentes; clientes podem não receber um quadro de encerramento (o navegador reporta 1006)SimTrate desconexões inesperadas (nenhum quadro de encerramento recebido, navegador reporta 1006) como 4408: reconecte com recuo, restabeleça as assinaturas e preencha dados descartados com eth_getLogs; assine menos ou leia mais rápido.
4429push rate exceededTaxa de notificação excedeu 1.000 envios/segundoSimReduza as assinaturas ou restrinja os filtros; reconecte com recuo, assine novamente e recupere dados.
4503billing unavailableCobrança temporariamente indisponívelSimEstado transitório; reconecte usando recuo exponencial com full jitter.

Reconexão e recuo exponencial

Para evitar tempestades de reconexão sincronizadas quando conexões caem, os clientes devem implementar recuo exponencial com full jitter:

  • Fórmula de recuo: Antes da n-ésima tentativa de reconexão (n = 0, 1, 2, ...), aguarde por uma duração escolhida uniformemente ao acaso:
    delay = random(0, min(20s, 0.5s * 2^n))
  • Redefinição do contador: Redefina o contador de tentativas n para 0 somente após manter uma conexão ininterrupta e estável por pelo menos 60 segundos.
  • Código de encerramento 1012: Introduza um atraso inicial aleatório antes da primeira tentativa de reconexão para evitar picos sincronizados de reconexão.
  • Códigos não repetíveis: Não reconecte automaticamente em 4402, 4404, 1003 ou 1009.

Recuperação de dados perdidos após a reconexão

Assinaturas via WebSocket não persistem entre conexões; notificações emitidas durante uma desconexão não são retidas no servidor. Após a reconexão, os clientes devem executar uma estratégia de sincronização:

  1. Recuperar logs com eth_getLogs:
    • Persista o número de bloco mais alto processado com sucesso (last_processed_block).
    • Chame imediatamente eth_subscribe("logs", ...) na reconexão para capturar eventos em tempo real.
    • Consulte os blocos perdidos via eth_getLogs com fromBlock: last_processed_block + 1 e toBlock: "latest" (ou o primeiro bloco recebido do fluxo em tempo real).
    • Se a lacuna da desconexão exceder o max_logs_block_range da rede (obtido em GET /v1/chains), divida as consultas em partes que não excedam esse limite.
    • Deduplique entradas de log no limite da consulta usando a tupla exclusiva (blockHash, transactionHash, logIndex).
  2. Recuperar cabeçalhos de blocos com eth_getBlockByNumber:
    • Registre o número e o hash do bloco mais recente recebido antes da desconexão.
    • Assine novamente newHeads.
    • Consulte eth_getBlockByNumber("latest", false) e busque os blocos intermediários ausentes sequencialmente. Verifique a continuidade da cadeia via parentHash para detectar reorgs.

Limites

LimiteValorResultado ao exceder
Assinaturas por conexão WebSocket100-32022 subscription_limit
Assinaturas newHeads por conexão WebSocket4-32022 subscription_limit
Requisitos de filtro da assinatura de logsDeve especificar um address ou um topic0 (primeira posição em topics)-32602 logs_filter_required

Próximos passos

Última atualização:

Nesta página