本指南介绍如何使用 Monad 的 WebSocket RPC 进行实时数据流传输。涵盖 WSS 端点、eth_subscribe 订阅方法、通知负载,并提供一个带有重连逻辑的可运行 Node.js 示例。还包括常见问题(如连接断开和高容量订阅)的故障排除提示。
直接回答:如何通过 WebSocket 从 Monad 获取实时数据
要从 Monad 获取实时数据,您需要连接到 WebSocket RPC 端点(wss://),并使用标准的以太坊 JSON-RPC eth_subscribe 方法订阅新区块、日志和待处理交易等事件。Monad 是一个兼容 EVM 的 L1,具有并行执行和亚秒级出块时间,因此其 WebSocket 接口遵循以太坊规范,但事件频率更高。本指南将引导您了解端点表面、订阅方法、通知格式,以及如何构建一个能够处理重连和重复通知的弹性客户端。
Monad 的官方文档提供了专门的 执行事件和 WebSocket 设置 部分和 实时数据源 页面,这些是本指南的主要参考。对于特定提供商的端点和限制,请务必查阅提供商的文档;我们将指出哪些行为由 Monad 记录,哪些因提供商而异。
- Monad 支持标准的
eth_subscribe方法:newHeads、logs、newPendingTransactions和syncing。 - 公共端点可能有连接限制和空闲超时;对于生产环境,请使用具有专用 WebSocket 支持的提供商。
- Monad 的亚秒级出块时间意味着通知到达速度比以太坊更快,因此请设计您的客户端以处理高吞吐量。
Monad 的 WebSocket RPC 端点表面
Monad 在 wss:// URL 上公开 WebSocket RPC 端点,类似于以太坊。确切的端点取决于您的节点提供商。例如,公共端点可能是 wss://rpc.monad.xyz(请查看 Monad 文档以获取当前公共端点),而 Chainstack、QuickNode 或 Dwellir 等提供商提供自己的 WSS URL。始终使用 wss:// 方案进行加密连接;公共端点很少支持纯 ws://。
Monad 的文档列出了支持的 JSON-RPC 方法,并指出了与以太坊的差异,例如区块标签和限制。对于 WebSocket,关键方法是 eth_subscribe 和 eth_unsubscribe。订阅类型与以太坊相同:newHeads、logs、newPendingTransactions 和 syncing。Monad 还提供了一个自定义的 executionEvents 订阅,用于实时状态跟踪,如 执行事件和 WebSocket 设置 页面所述。
选择端点时,请考虑公共端点通常有速率限制,并可能断开空闲连接。对于生产环境,请使用提供专用 WebSocket 连接且限制更高的提供商。OnFinality 的 API 服务 和 RPC 定价 页面提供了托管端点的详细信息。
- 始终使用
wss://进行安全的 WebSocket 连接。 - 查看提供商的文档以获取确切的 WSS URL 和任何连接限制。
- Monad 的公共端点可能适合测试,但不适合高容量的生产使用。
理解 eth_subscribe 和通知负载
eth_subscribe 方法发送订阅请求并接收订阅 ID。然后,通知作为 JSON-RPC 响应推送,方法为 eth_subscription。newHeads 的负载包括区块头对象,其中包含 number、hash、parentHash、timestamp 和 transactionsRoot 等字段。对于 logs,负载包括日志对象,包含 address、topics、data、blockNumber、transactionHash 和 logIndex。
Monad 的亚秒级出块时间意味着 newHeads 通知比以太坊(约 12 秒出块)频繁得多。这对于处理每个区块的客户端来说可能是一个挑战,因此请考虑过滤或批处理。对于 logs,您可以指定 address 和 topics 过滤器以减少通知量。
以下是 newHeads 通知负载的示例:
{
"jsonrpc": "2.0",
"method": "eth_subscription",
"params": {
"subscription": "0x1234567890abcdef",
"result": {
"number": "0x1b4",
"hash": "0x...",
"parentHash": "0x...",
"timestamp": "0x...",
"transactionsRoot": "0x..."
}
}
}
对于 logs,负载包括日志条目。您可以订阅特定合约地址和主题的日志以过滤相关事件。
newHeads为每个新区块发送区块头。logs发送与过滤条件匹配的日志。newPendingTransactions发送待处理交易的交易哈希。syncing发送同步状态更改。
可运行示例:使用 ethers.js 订阅和重连
下面是一个完整的、自包含的 Node.js 脚本,使用 ethers.js 连接到 Monad WebSocket 端点,订阅新区块和日志,并处理重连和重新订阅。该脚本使用一个简单的重连循环,在连接断开后重新订阅相同的过滤器。它还通过跟踪最后看到的区块号来演示幂等重复通知处理。
要运行此脚本,请安装 ethers.js(npm install ethers)并将 MONAD_WSS_URL 环境变量设置为您的端点。该脚本记录每个通知,并演示如何通过跟踪最后看到的区块号来处理重复通知。
预期输出:脚本将记录订阅 ID,然后打印新区块通知(包含区块号和哈希),以及到达的日志通知。重复通知(例如重连后)通过 lastBlockNumber 检查进行过滤。要测试,请运行脚本并观察控制台。您应该每隔几秒看到一个新的区块通知(Monad 的出块时间亚秒级,因此预计通知会很快)。如果连接断开,脚本会自动重连并重新订阅。
- 该脚本使用
provider.send直接调用eth_subscribe,适用于 ethers.js v6。 - 重连逻辑很简单:在 'disconnected' 事件后延迟重连并重新订阅。
- 通过跟踪 newHeads 的最后区块号来处理重复通知。
const { WebSocketProvider } = require('ethers');
const WSS_URL = process.env.MONAD_WSS_URL || 'wss://rpc.monad.xyz';
async function main() {
let provider;
let lastBlockNumber = 0;
async function connect() {
console.log('Connecting to', WSS_URL);
provider = new WebSocketProvider(WSS_URL);
provider.on('error', (err) => {
console.error('WebSocket error:', err);
});
provider.on('disconnected', () => {
console.log('Disconnected. Reconnecting in 5s...');
setTimeout(connect, 5000);
});
// Subscribe to new heads
const headSub = await provider.send('eth_subscribe', ['newHeads']);
console.log('Subscribed to newHeads with id:', headSub);
// Subscribe to logs (example: all logs, adjust filter as needed)
const logSub = await provider.send('eth_subscribe', ['logs', {}]);
console.log('Subscribed to logs with id:', logSub);
// Handle notifications
provider.on('message', (message) => {
const parsed = JSON.parse(message);
if (parsed.method === 'eth_subscription') {
const { subscription, result } = parsed.params;
if (subscription === headSub) {
const blockNum = parseInt(result.number, 16);
if (blockNum > lastBlockNumber) {
lastBlockNumber = blockNum;
console.log('New head:', result.number, result.hash);
} else {
console.log('Duplicate head notification ignored:', result.number);
}
} else if (subscription === logSub) {
console.log('New log:', result.address, result.topics);
}
}
});
}
await connect();
}
main().catch(console.error);常见故障和故障排除清单
与 Monad 的 WebSocket 连接可能因多种原因失败。以下是常见问题及解决方法:
订阅过多:某些提供商限制每个连接的活动订阅数量。如果超过限制,您可能会收到错误。减少订阅数量或使用多个连接。
每 IP 连接限制:公共端点通常限制每个 IP 的连接数。如果达到限制,您将被断开。使用限制更高的提供商或轮换 IP。
区块头滞后:如果您的客户端处理通知缓慢,可能会落后于链头。由于 Monad 出块速度快,这种情况更可能发生。优化您的处理或使用更强大的机器。
空闲超时:许多提供商在一段时间后关闭空闲连接。定期发送 ping 或 keepalive 消息以保持连接。
重连风暴:如果端点暂时不可用,您的客户端可能过于激进地重连。使用带有抖动的指数退避。
重复通知:重连后,您可能会收到已处理区块的通知。使用幂等处理(例如,跟踪最后处理的区块)。
- 查看提供商的文档以了解订阅和连接限制。
- 实现心跳(例如,每 30 秒发送 ping)以防止空闲超时。
- 对重连尝试使用指数退避。
- 设计您的事件处理为幂等以处理重复。
Monad WebSocket RPC 的权衡和限制
Monad 的快速出块时间是一把双刃剑:它们提供低延迟数据,但也增加了通知量。这可能会给客户端和网络带来压力。请考虑以下权衡:
吞吐量与成本:高频率订阅消耗更多带宽,并可能在托管提供商处产生更高成本。使用过滤器减少数据量。
最终性与链头:Monad 使用 MonadBFT 共识,出块时间亚秒级,但最终性可能滞后于链头。如果您需要最终数据,请订阅 newHeads 并使用 finalized 等区块标签检查最终性。
并行执行:Monad 的并行执行意味着交易以不同于以太坊的方式包含在区块中。这不会直接影响 WebSocket 订阅,但可能影响您解释日志和交易收据的方式。
提供商特定限制:每个提供商都有自己的速率限制、连接限制和定价。请务必查看提供商的文档。OnFinality 的 Monad RPC 速率限制和 429 指南涵盖了常见的速率限制问题。
公共端点不适用于生产:公共端点通常有速率限制,并且可能不可靠。对于生产环境,请使用专用提供商或运行您自己的节点。
- 使用日志过滤器减少通知量。
- 对于关键应用,考虑订阅
finalized区块。 - 监控您的带宽并调整订阅频率。
- 对于生产环境,请使用托管提供商,如 OnFinality 的 API 服务。
后续步骤和进一步阅读
既然您已经了解了 Monad WebSocket RPC,您可以自信地构建实时应用程序。以下是一些后续步骤:
探索 Monad 官方文档中的 执行事件和 WebSocket 设置,了解 executionEvents 等高级订阅类型。
查看 OnFinality 的 Monad RPC 端点 以获取可用端点及其功能的列表。
了解 Monad RPC 超时和重试 以优雅地处理网络问题。
理解 Monad RPC 速率限制和 429 以避免达到限制。
查看 OnFinality Learn 中心 获取更多关于 Monad 和其他网络的指南。
如果您正在 Monad 上构建,请考虑使用 OnFinality 的 API 服务 以获得可靠且可扩展的 RPC 访问。
- 首先使用公共端点测试您的 WebSocket 客户端,然后迁移到提供商。
- 实现健壮的错误处理和重连逻辑。
- 使用指标监控您的订阅健康状况。