Đăng ký WebSocket

Kết nối endpoint WebSocket của BlockVectra để eth_subscribe newHeads và logs. Tìm hiểu cách kết nối, quy tắc lọc, backoff kết nối lại và khôi phục.

BlockVectra cung cấp kết nối WebSocket bảo mật (wss://) để nhận luồng đăng ký sự kiện Ethereum thời gian thực cùng với yêu cầu JSON-RPC tiêu chuẩn.

Chọn WebSocket, Webhook hoặc thăm dò

Dùng WebSocket cho newHeads trực tiếp và logs đã lọc khi ứng dụng có thể duy trì kết nối. Dùng Blockchain Webhook API để nhận hoạt động ví được theo dõi tại endpoint HTTPS, với xác minh chữ ký body gốc, thử lại và phát lại các sự kiện khớp đã lưu giữ. Dùng thăm dò HTTP để giám sát thanh toán ERC-20 theo lịch và truy xuất bổ sung log lịch sử. Hướng dẫn stablecoin cũng trình bày bộ nhận Webhook USDT / USDC. Để so sánh kiến trúc về hỗ trợ chuỗi, yêu cầu bộ nhận và đánh đổi khi khôi phục cho nhà phát triển và AI Agent, xem hướng dẫn chọn Webhook, WebSocket hoặc thăm dò RPC.

Hỗ trợ WebSocket được xác định từ ws và subscriptions trong GET /v1/chains; hỗ trợ Push được xác định từ danh sách GET /v1/push/chains có xác thực. Chuỗi không có WebSocket vẫn có thể dùng Webhook địa chỉ nếu được liệt kê ở đó.

Ngắt kết nối WebSocket cần đăng ký lại và truy xuất bổ sung; không phát sự kiện điều khiển Push subscription.gap hay chain.reorg. Với Webhook, khoảng trống cần quét theo khoảng; thông báo tái tổ chức cần đánh dấu hoặc loại bỏ sự kiện bị thay thế trước khi giữ lại sự kiện từ chuỗi chuẩn được tự động gửi lại. Phát lại Push gửi lại các sự kiện khớp đã lưu giữ, không phải dữ liệu trước khi thêm địa chỉ hoặc chuỗi, hay khi đăng ký ở trạng thái offline. Xem quy tắc tính phí và tham chiếu lỗi khi triển khai khôi phục.

Chuỗi khả dụng

Bạn có thể kiểm tra đăng ký WebSocket có hoạt động trên một mạng hay không bằng cách đọc ws (boolean) và subscriptions (mảng loại đăng ký được hỗ trợ) trong GET /v1/chains.

Bảng dưới đây phản ánh các mạng đã bật hỗ trợ WebSocket:

ChuỗiEndpoint WebSocket (Key trên đường dẫn)
Robinhood Chainwss://api.blockvectra.com/v1/robinhood_mainnet/{api_key}
Robinhood Chain Testnetwss://api.blockvectra.com/v1/robinhood_testnet/{api_key}

Kết nối và xác thực

Client thiết lập kết nối WebSocket TLS bảo mật (wss://). API key có thể được cung cấp theo hai cách:

  • API key trong đường dẫn: wss://api.blockvectra.com/v1/{chain}/{api_key}
  • API key trong header: wss://api.blockvectra.com/v1/{chain} với header x-api-key: {api_key} hoặc Authorization: Bearer {api_key} trong handshake HTTP Upgrade.

Khi có API key trong đường dẫn, API key đó được dùng và cả hai header xác thực bị bỏ qua. Khi không có API key trong đường dẫn, x-api-key không rỗng được ưu tiên hơn Authorization: Bearer. WebSocket API của trình duyệt không thể đặt các header này; dùng URL có API key trong đường dẫn.

Kiểm tra chấp nhận handshake

Handshake có thể thất bại với:

  • Xác thực: Thiếu API key trả HTTP 401 (missing_api_key); API key không xác định, bị vô hiệu hóa hoặc thu hồi trả HTTP 401 (invalid_api_key); nếu xác thực tạm thời không khả dụng, phản hồi là HTTP 503 (auth_unavailable).
  • Số dư tài khoản: Tài khoản có số dư trả trước bằng không hoặc âm trả HTTP 402 (balance_exhausted); nếu không thể xác nhận trạng thái tính phí, phản hồi là HTTP 503 (billing_unavailable).
  • Giới hạn kết nối: Vượt giới hạn mỗi API key (20 kết nối) hoặc mỗi tài khoản (50 kết nối) trả HTTP 429 (ws_connection_limit).
  • Tính khả dụng của chuỗi: Yêu cầu chuỗi không xác định hoặc không được phục vụ trả HTTP 404 (unknown_chain).
  • Dung lượng máy chủ: Khi máy chủ bận hoặc quá tải, handshake trả HTTP 503 (overloaded) với header Retry-After.

Sau khi kết nối, client có thể gửi yêu cầu JSON-RPC 2.0 tiêu chuẩn (như eth_blockNumber hoặc eth_call) và phương thức điều khiển đăng ký dưới dạng frame văn bản UTF-8.

Quy tắc tính phí

  • Thiết lập kết nối, giữ kết nối nhàn rỗi và heartbeat ping/pong không bị tính phí.
  • Lệnh gọi eth_subscribe và eth_unsubscribe thành công bị tính phí, kể cả unsubscribe trả false; lệnh gọi thất bại không bị tính phí. Lệnh gọi JSON-RPC thông thường tuân theo quy tắc tính phí JSON-RPC.
  • Thông báo newHeads được tính một lần cho mỗi hash khối trên mỗi kết nối, bất kể kết nối có bao nhiêu đăng ký newHeads.
  • Thông báo logs được tính một lần cho mỗi đăng ký, mỗi hash khối và giai đoạn có log khớp; khối không có log khớp không bị tính phí. Nhiều log khớp trong cùng khối và giai đoạn không làm tăng số lần tính phí. Các đăng ký riêng được tính riêng, kể cả khi bộ lọc chồng lấn. Log tái tổ chức (removed: true) tạo thành đơn vị riêng; khối thay thế ở cùng độ cao có hash khác và là đơn vị khác.
  • Thông báo chỉ bị tính phí sau khi được flush thành công vào bộ đệm gửi socket; thông báo đang xếp hàng hoặc bị bỏ mà chưa flush không bị tính phí. Thông báo xếp hàng trước phản hồi eth_unsubscribe được tính nếu đã flush. Thông điệp WebSocket không có HTTP header tính phí; xem mức sử dụng tài khoản để biết CU đã đo.

Phương thức đăng ký

API triển khai giao diện pub/sub Ethereum tiêu chuẩn: eth_subscribe và eth_unsubscribe.

newHeads

Phát đối tượng header khối mới mỗi khi một khối mới được thêm vào đầu chuỗi.

  • Yêu cầu đăng ký:
    {"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["newHeads"]}
  • Phản hồi đăng ký: Trả mã định danh đăng ký thập lục phân không mang ý nghĩa có thể suy diễn:
    {"jsonrpc":"2.0","id":1,"result":"0x1"}
  • Frame thông báo Push:
    {"jsonrpc":"2.0","method":"eth_subscription","params":{"subscription":"0x1","result":{"number":"0x1b4","hash":"0x..."}}}

logs

Phát log sự kiện khớp tiêu chí lọc đã chỉ định.

  • Yêu cầu bộ lọc: Mọi bộ lọc đăng ký logs phải chỉ định address (địa chỉ hợp đồng hoặc mảng địa chỉ) hoặc topic0 (vị trí topic đầu tiên, không null). Bộ lọc không chỉ định cả hai (như {} hoặc {"topics":[null,"0x..."]}) bị từ chối với mã lỗi -32602 (logs_filter_required).

  • Giới hạn bộ lọc: Tối đa 100 địa chỉ; tối đa 4 vị trí topic với tối đa 16 hash ứng viên mỗi vị trí.

  • Dung lượng bộ lọc: Nếu bộ lọc log đang hoạt động đạt giới hạn dung lượng, đăng ký trả mã lỗi -32022 (ws_filter_capacity).

  • Tái tổ chức chuỗi: Nếu khối bị loại bỏ do tái tổ chức chuỗi, thông báo log cho log bị loại bỏ có "removed": true.

  • Yêu cầu đăng ký:

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

eth_unsubscribe

Chấm dứt đăng ký đang hoạt động bằng mã định danh đăng ký.

  • Yêu cầu hủy đăng ký:
    {"jsonrpc":"2.0","id":3,"method":"eth_unsubscribe","params":["0x1"]}
  • Phản hồi hủy đăng ký:
    {"jsonrpc":"2.0","id":3,"result":true}

Ví dụ có thể chạy

Kết nối bằng viem v2 qua createPublicClient và transport webSocket. Thay {chain} bằng mã định danh chuỗi đích và {api_key} bằng API key của bạn:

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);
  },
});

Mã đóng kết nối và hành động của client

Khi máy chủ chấm dứt phiên WebSocket, nó gửi frame Close với mã đóng cụ thể và reason ngắn. Bảng dưới đây liệt kê mã đóng máy chủ phát ra và hành động được khuyến nghị:

Mã đóngChuỗi reasonMô tảCó thể thử lạiHành động của client
1001idleKết nối không hoạt động, không có đăng ký hay thông điệp trong 3600 giây (1 giờ)CóKết nối lại khi cần.
1003binary frames are not acceptedNhận frame WebSocket nhị phân; chỉ chấp nhận frame văn bản UTF-8KhôngKhông tự động kết nối lại. Cập nhật client để gửi frame văn bản.
1009message too largePayload nhận vào vượt 1 MiBKhôngKhông tự động kết nối lại. Chia yêu cầu lớn hoặc giảm kích thước payload.
1012service restartMáy chủ khởi động lại, hoặc phiên đạt thời gian tồn tại tối đa (24 giờ)CóKết nối lại với backoff có ngẫu nhiên hóa, thiết lập lại đăng ký và truy xuất bổ sung dữ liệu bị bỏ lỡ.
1013chain unavailableChuỗi không khả dụngCóKết nối lại với backoff cấp số nhân có full jitter, thiết lập lại đăng ký và truy xuất bổ sung dữ liệu bị bỏ lỡ.
1013overloadedMáy chủ tạm thời quá tảiCóKết nối lại với backoff cấp số nhân có full jitter, thiết lập lại đăng ký và truy xuất bổ sung dữ liệu bị bỏ lỡ.
4402insufficient balanceSố dư tài khoản cạnKhôngKhông tự động kết nối lại. Nạp thêm số dư rồi kết nối lại.
4404invalid api keyAPI key không xác định, bị vô hiệu hóa hoặc thu hồiKhôngKhông tự động kết nối lại. Xác minh hoặc xoay vòng API key trong bảng điều khiển trước khi kết nối lại.
4408slow consumerMáy chủ đóng phiên khi hàng đợi Push vượt 512 KiB và bỏ thông báo đang chờ; client có thể không nhận frame đóng (trình duyệt báo 1006)CóXử lý ngắt kết nối bất ngờ (không nhận frame đóng, trình duyệt báo 1006) như 4408: kết nối lại với backoff, thiết lập lại đăng ký và truy xuất bổ sung dữ liệu bị bỏ bằng eth_getLogs; giảm số đăng ký hoặc đọc nhanh hơn.
4429push rate exceededTốc độ thông báo vượt 1,000 lượt Push/giâyCóGiảm số đăng ký hoặc thu hẹp bộ lọc; kết nối lại với backoff, đăng ký lại và truy xuất bổ sung.
4503billing unavailableTính phí tạm thời không khả dụngCóTrạng thái tạm thời; kết nối lại với backoff cấp số nhân có full jitter.

Kết nối lại và backoff cấp số nhân

Để tránh nhiều client đồng loạt kết nối lại khi mất kết nối, client phải triển khai backoff cấp số nhân với full jitter:

  • Công thức backoff: Trước lần thử kết nối lại thứ n (n = 0, 1, 2, ...), chờ một khoảng thời gian được chọn ngẫu nhiên đều:
    delay = random(0, min(20s, 0.5s * 2^n))
  • Đặt lại bộ đếm: Chỉ đặt lại bộ đếm thử lại n về 0 sau khi duy trì kết nối ổn định, không gián đoạn ít nhất 60 seconds.
  • Mã đóng 1012: Thêm thời gian chờ ban đầu ngẫu nhiên trước lần thử kết nối lại đầu tiên để tránh tăng đột biến do kết nối lại đồng loạt.
  • Mã không thể thử lại: Không tự động kết nối lại với 4402, 4404, 1003 hoặc 1009.

Truy xuất bổ sung dữ liệu bị bỏ lỡ sau khi kết nối lại

Đăng ký WebSocket không tồn tại qua các kết nối; thông báo phát trong lúc ngắt kết nối không được lưu giữ trên máy chủ. Sau khi kết nối lại, client nên thực hiện chiến lược bắt kịp dữ liệu:

  1. Truy xuất bổ sung log bằng eth_getLogs:
    • Lưu bền vững số khối cao nhất đã xử lý thành công (last_processed_block).
    • Gọi ngay eth_subscribe("logs", ...) khi kết nối lại để nhận sự kiện trực tiếp.
    • Truy vấn khối bị bỏ lỡ qua eth_getLogs với fromBlock: last_processed_block + 1 và toBlock: "latest" (hoặc khối đầu tiên nhận từ luồng trực tiếp).
    • Nếu khoảng ngắt kết nối vượt max_logs_block_range của mạng (từ GET /v1/chains), chia truy vấn thành các phần không vượt giới hạn đó.
    • Loại trùng mục log ở ranh giới truy vấn bằng bộ giá trị duy nhất (blockHash, transactionHash, logIndex).
  2. Truy xuất bổ sung header khối bằng eth_getBlockByNumber:
    • Ghi lại số khối và hash mới nhất nhận trước khi ngắt kết nối.
    • Đăng ký lại newHeads.
    • Truy vấn eth_getBlockByNumber("latest", false) và lấy tuần tự các khối trung gian bị thiếu. Xác minh tính liên tục của chuỗi qua parentHash để phát hiện tái tổ chức.

Giới hạn

Giới hạnGiá trịKết quả khi vượt
Đăng ký mỗi kết nối WebSocket100-32022 subscription_limit
Đăng ký newHeads mỗi kết nối WebSocket4-32022 subscription_limit
Yêu cầu bộ lọc đăng ký logsPhải chỉ định address hoặc topic0 (vị trí đầu tiên trong topics)-32602 logs_filter_required

Các bước tiếp theo

Cập nhật lần cuối:

Trên trang này