整块订阅(blockreq_newBlocks)
blockreq_newBlocks 是 BlockReq 为 eth_subscribe 提供的订阅类型。链上每出一个块,你会收到一条标准的 eth_subscription 通知,params.result 是带完整交易对象的整个块,与 eth_getBlockByHash(hash, true) 返回的对象一致,字段原样来自节点。
它替代了常见的两步循环:先订阅 newHeads,再对收到的每个链头调用 eth_getBlockByHash。
这是 BlockReq 的扩展订阅,不是以太坊标准订阅。ethers 和 viem 内置的区块监听不会用它,请像下面的示例那样直接发送原始 eth_subscribe。
支持的链
仅在 BlockReq 自建节点的主网上提供。其他链和所有测试网都会拒绝该订阅。
| 链 | Chain ID | WSS 端点 |
|---|---|---|
| Ethereum | 1 | wss://ethereum-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Base | 8453 | wss://base-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Arbitrum One | 42161 | wss://arbitrum-one-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| BNB Smart Chain | 56 | wss://bsc-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Robinhood | 4663 | wss://robinhood-mainnet-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
| Arc | 5042 | wss://arc-rpc.blockreq.com/v1/rpc/BRQ1P0000000000000000000000000000000000000000000000000000000 |
该订阅需要带 API key 的端点,公开端点(/v1/rpc/public)会拒绝。
订阅
只发送一个参数 "blockreq_newBlocks",大小写必须完全一致。其他任何写法都会返回 invalid params 错误。
{
"jsonrpc": "2.0",
"id": 1,
"method": "eth_subscribe",
"params": ["blockreq_newBlocks"]
}和其他订阅一样,响应里是订阅 ID:
{ "jsonrpc": "2.0", "id": 1, "result": "0x9a1c3f0e5b7d2a48c6e1f3b5d7a9c2e4" }之后每个新块以通知的形式到达。示例经过截短:数值仅作示意,logsBloom 被截断,交易列表只放了该块的一笔交易。
{
"jsonrpc": "2.0",
"method": "eth_subscription",
"params": {
"subscription": "0x9a1c3f0e5b7d2a48c6e1f3b5d7a9c2e4",
"result": {
"number": "0x1312d00",
"hash": "0x5e1c0b7c2c4f0a9d6b3e8f21a7d4c9b05e6f1a2b3c4d5e6f708192a3b4c5d6e7",
"parentHash": "0x3b9f4a1d8c7e6052f1a3b4c5d6e7f8091a2b3c4d5e6f708192a3b4c5d6e7f809",
"timestamp": "0x6745a9c3",
"miner": "0x4838b106fce9647bdf1e7877bf73ce8b0bad5f97",
"gasLimit": "0x1c9c380",
"gasUsed": "0xb71b00",
"baseFeePerGas": "0x3b9aca00",
"logsBloom": "0x00a1…0004",
"transactionsRoot": "0x7a1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f9",
"stateRoot": "0x1f2e3d4c5b6a79880716253443526170899a8b7c6d5e4f30211203f4e5d6c7b8",
"receiptsRoot": "0x9c8b7a69584736251403f2e1d0c9b8a7968574635241302f1e0d1c2b3a495867",
"transactions": [
{
"hash": "0xa1b2c3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90",
"blockHash": "0x5e1c0b7c2c4f0a9d6b3e8f21a7d4c9b05e6f1a2b3c4d5e6f708192a3b4c5d6e7",
"blockNumber": "0x1312d00",
"transactionIndex": "0x0",
"from": "0x00000000219ab540356cbb839cbe05303d7705fa",
"to": "0xdac17f958d2ee523a2206206994597c13d831ec7",
"type": "0x2",
"nonce": "0x2a",
"gas": "0x186a0",
"maxFeePerGas": "0x77359400",
"maxPriorityFeePerGas": "0x59682f00",
"value": "0x0",
"input": "0xa9059cbb…",
"chainId": "0x1",
"accessList": []
}
],
"uncles": []
}
}
}实际出现哪些字段取决于链及其最近一次硬分叉:通知携带的是节点对 eth_getBlockByHash(hash, true) 的返回,包含链自己的扩展字段。
用 eth_unsubscribe 退订,传入订阅 ID:
{ "jsonrpc": "2.0", "id": 2, "method": "eth_unsubscribe", "params": ["0x9a1c3f0e5b7d2a48c6e1f3b5d7a9c2e4"] }示例
把 BRQ1P0000000000000000000000000000000000000000000000000000000 换成你的端点 key,下面从环境变量 BLOCKREQ_API_KEY 读取。
wscat
npx wscat -c "wss://ethereum-rpc.blockreq.com/v1/rpc/$BLOCKREQ_API_KEY" \
-x '{"jsonrpc":"2.0","id":1,"method":"eth_subscribe","params":["blockreq_newBlocks"]}' -w 60Node.js
需要 Node.js 22 或更新版本,无需安装任何包:
const ws = new WebSocket(`wss://ethereum-rpc.blockreq.com/v1/rpc/${process.env.BLOCKREQ_API_KEY}`);
ws.addEventListener("open", () => {
ws.send(JSON.stringify({ jsonrpc: "2.0", id: 1, method: "eth_subscribe", params: ["blockreq_newBlocks"] }));
});
let lastNumber = null;
ws.addEventListener("message", (event) => {
const message = JSON.parse(event.data);
if (message.error) {
console.error(message.error.code, message.error.message);
ws.close();
return;
}
if (message.method !== "eth_subscription") {
console.log("subscription id:", message.result);
return;
}
const block = message.params.result;
const number = Number(block.number);
if (lastNumber !== null && number > lastNumber + 1) {
console.warn(`blocks ${lastNumber + 1}..${number - 1} were not pushed; fetch them with eth_getBlockByNumber`);
}
lastNumber = number;
console.log(number, block.hash, `${block.transactions.length} transactions`);
});Python
需要 Python 3.9 或更新版本,并执行 pip install websockets:
import asyncio
import json
import os
import websockets
URL = f"wss://ethereum-rpc.blockreq.com/v1/rpc/{os.environ['BLOCKREQ_API_KEY']}"
async def main() -> None:
async with websockets.connect(URL, max_size=None) as ws:
await ws.send(json.dumps({"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["blockreq_newBlocks"]}))
last_number = None
async for raw in ws:
message = json.loads(raw)
if "error" in message:
print(message["error"]["code"], message["error"]["message"])
return
if message.get("method") != "eth_subscription":
print("subscription id:", message["result"])
continue
block = message["params"]["result"]
number = int(block["number"], 16)
if last_number is not None and number > last_number + 1:
print(f"blocks {last_number + 1}..{number - 1} were not pushed; fetch them with eth_getBlockByNumber")
last_number = number
print(number, block["hash"], f"{len(block['transactions'])} transactions")
asyncio.run(main())max_size=None 解除 websockets 库默认的 1 MiB 单条消息上限,以太坊的一个块可能超过它。
错误
被拒绝的订阅不计 Request。
| 错误码 | 何时出现 | 怎么办 |
|---|---|---|
-32601 | 该链不提供此订阅,或连接没有 API key(公开端点)。消息为 subscription blockreq_newBlocks is not available on this network or endpoint。 | 在支持的链上使用带 key 的端点。 |
-32000 | 这个网络的订阅容量暂时已满。消息以 blockreq_newBlocks subscriptions are temporarily unavailable on this network 开头,并建议稍后再试。 | 稍后再订阅一次。 |
Request 计数
eth_subscribe本身计 1 个 Request,与其他请求相同。- 推送给你的每条整块通知计 2 个 Request:它替代的那条
newHeads通知,加上你原本要自己发出的取块调用。没有推送给你的块不计数。 - 被拒绝的订阅不计数。
通用规则见 Request Counting。
重组与缺口
该订阅跟随 newHeads:
- 发生重组后,替换它的新块会在到达时照常推送,所以你可能收到两个
number相同的块。请用number和parentHash判断哪些块在你的链上。 - 如果节点没能在时限内给出某个块的内容,这个块就不会推送,你会看到块号跳变。被跳过的块之后不会补发,重新连接后也不会回放。需要每个块都不漏时,请把每条通知的
number与上一条比较,并用eth_getBlockByNumber补取缺失的块。
消息体积
整块比链头大得多。Ethereum 的一个块约 0.5–0.7 MB JSON,BNB Smart Chain 约 0.1 MB,其余链的块从几 KB 到几十 KB。消息不压缩。读得太慢的客户端会被断开,规则与其他订阅相同,所以请在消息到达时就读走,把耗时的处理放到套接字循环之外。
与 newHeads 的区别
newHeads | blockreq_newBlocks | |
|---|---|---|
| 以太坊标准订阅 | 是 | 否,BlockReq 扩展 |
| 通知内容 | 区块头 | 带完整交易对象的整个块 |
| 获取交易 | 每个链头再调用一次 eth_getBlockByHash | 已在通知里 |
| 每条通知计的 Request | 1 | 2 |
| 支持的链 | 所有支持 WSS 的链 | 上面列出的六条链 |
| 访问方式 | 公开端点或带 key 端点 | 仅带 key 端点 |
| 消息体积 | 区块头 | 整个块,最大约 0.7 MB |
只需要知道有新块时用 newHeads;要读取每个新块的交易时用 blockreq_newBlocks。