Logo
新用户订阅 RPC,首月享 6.5 折优惠查看优惠
OnFinality Learn
网络与协议指南阅读约 12 分钟

BNB智能链历史RPC与归档数据:查询过去的余额、日志和状态

了解如何通过RPC查询BNB智能链(BSC)的历史数据,何时需要归档节点,以及如何避免使用eth_getBalance、eth_getLogs等方法时的常见陷阱。

TL;DR

本指南介绍如何通过RPC查询BNB智能链(BSC)的历史数据,重点讲解归档节点的需求。涵盖BSC的出块时间和客户端生态、归档节点存储的内容,并提供可运行的eth_getBalance和eth_getLogs脚本及故障排除技巧。

直接回答:如何查询BSC历史数据

要查询BNB智能链(BSC)的历史数据(如过去的余额、日志或状态),您需要一个具有归档数据的RPC端点。标准全节点会修剪历史状态,因此像在旧区块上调用eth_getBalance或在长范围内调用eth_getLogs等方法将返回不完整或不正确的结果。请使用支持归档的BSC端点,并在参数中指定历史区块作为标签或fromBlock/toBlock参数。

例如,要获取区块10,000,000处的余额,您需要调用eth_getBalance,并传入地址和区块标签'0x989680'(十六进制)。只有当节点拥有该区块的归档状态时,此调用才会返回有意义的值。类似地,使用宽区块范围的eth_getLogs要求节点保留日志,并且通常需要归档数据才能高效处理。请参阅BNB智能链节点类型(RPC助手)以比较全节点与归档节点。

  • 使用归档RPC端点进行历史查询。
  • 将区块号指定为十六进制字符串或标签(例如,'earliest'、'0x...')。
  • 对于日志,设置fromBlock和toBlock为所需范围。
  • 检查您的提供商的归档可用性和保留策略。

BSC基础知识:出块时间、客户端和节点类型

BNB智能链是一个兼容EVM的区块链,目标出块时间约为3秒,这导致高交易吞吐量和大量历史数据。这种高节奏意味着修剪状态的全节点只能提供近期数据,而归档节点存储整个状态历史以回答任何历史查询。

BSC的客户端生态已经发展。最初是go-ethereum(geth)的一个分叉,BSC现在有多个客户端实现。官方文档在docs.bnbchain.org描述了节点类型:全节点(修剪)、归档节点和验证节点。社区客户端如reth-bsc和bsc-erigon也在搜索中被提及,提供不同的性能和存储权衡。在本指南中,我们专注于这些客户端通用的RPC方法,因为它们遵循以太坊JSON-RPC标准。

归档节点保留所有历史状态trie数据,使得可以在任何过去的区块上查询eth_getBalance。全节点通常修剪早于一定区块数(例如128个区块)的状态,只保留最近的状态。验证节点是参与共识的全节点,可能不公开提供RPC请求。

  • BSC出块时间:约3秒(由BNB Chain记录)。
  • 节点类型:全节点(修剪)、归档节点、验证节点。
  • 客户端:基于geth、reth-bsc、bsc-erigon(社区)。
  • 归档节点存储完整历史状态;全节点修剪。

归档节点比全节点多存储什么

归档BSC节点保留每一次历史状态更改,包括每个区块的账户余额、合约代码和存储。这与修剪的全节点形成对比,后者只保留最新状态和有限的区块和收据历史。BNB Chain官方文档关于归档节点 - BSC开发指出,归档节点对于查询历史数据是必要的。

没有归档状态,在旧区块上调用eth_getBalance将返回当前余额或错误,因为节点无法重建过去的状态。类似地,如果节点已修剪日志或无法高效处理范围,则长范围的eth_getLogs可能会失败或返回不完整结果。归档节点还支持高级调试和追踪功能,例如reth/erigon结构化追踪,这对于深入分析很有用。

归档节点的存储需求显著高于全节点,但具体数字因客户端和配置而异。我们不提供具体的GB数字,因为它们没有标准化;请参考您的节点提供商或客户端文档以获取当前估算。

  • 归档节点存储完整状态历史,支持任何历史查询。
  • 全节点修剪状态,限制历史访问。
  • 归档节点支持追踪和高级调试。
  • 存储需求各不相同;请查看提供商文档。

用于历史数据的BSC RPC方法

以下JSON-RPC方法对于查询BSC历史数据至关重要。它们遵循以太坊标准,并受BSC客户端支持。

eth_getBlockByNumber:按编号检索区块,如果需要,可包含完整交易对象。这适用于任何区块的全节点,因为区块头不会被修剪。

eth_getLogs:在区块范围内按地址和主题过滤日志。由于BSC交易量大,这可能消耗大量资源;归档节点能更好地处理较大范围。

eth_call、eth_getBalance、eth_getCode、eth_getProof:这些方法接受区块参数。查询历史状态时,必须传递区块号或标签。对于早于修剪窗口的区块,它们需要归档状态。

对于追踪,像reth-bsc和bsc-erigon这样的客户端通过debug_traceTransaction或trace_*方法提供结构化追踪,但这些不属于标准RPC,可能需要特定客户端支持。

  • eth_getBlockByNumber:适用于任何区块的全节点。
  • eth_getLogs:大范围需要归档。
  • eth_getBalance、eth_call等:历史区块需要归档。
  • 追踪方法:客户端特定,非标准。

可运行示例:查询历史余额和日志

下面是一个使用ethers v6的Node.js脚本,用于查询历史余额并分页获取日志。它是自包含的,需要您设置RPC URL(例如,您的归档端点)。该脚本演示了如何处理eth_getLogs的超时和退避。

要运行,请安装ethers:npm install ethers。然后将RPC_URL环境变量设置为您的归档端点。脚本首先检查特定区块(例如区块10000000)的余额,然后获取一个小范围的日志以避免压垮节点。

预期输出:对于非归档端点,余额查询可能返回当前余额或错误。对于归档端点,它返回历史余额。日志查询返回日志对象数组。

const { ethers } = require('ethers');

const RPC_URL = process.env.RPC_URL || 'https://your-archive-endpoint.example';
const provider = new ethers.JsonRpcProvider(RPC_URL);

async function getHistoricalBalance(address, blockNumber) {
  const balance = await provider.getBalance(address, blockNumber);
  console.log(`Balance at block ${blockNumber}: ${ethers.formatEther(balance)} BNB`);
}

async function getLogsPaged(contractAddress, fromBlock, toBlock, pageSize = 1000) {
  let logs = [];
  let currentFrom = fromBlock;
  while (currentFrom <= toBlock) {
    const currentTo = Math.min(currentFrom + pageSize - 1, toBlock);
    const filter = {
      address: contractAddress,
      fromBlock: currentFrom,
      toBlock: currentTo
    };
    try {
      const batch = await provider.getLogs(filter);
      logs = logs.concat(batch);
      console.log(`Fetched ${batch.length} logs from ${currentFrom} to ${currentTo}`);
    } catch (error) {
      console.error(`Error fetching logs from ${currentFrom} to ${currentTo}:`, error.message);
      // Implement backoff: wait 1 second and retry
      await new Promise(resolve => setTimeout(resolve, 1000));
      continue;
    }
    currentFrom = currentTo + 1;
  }
  return logs;
}

async function main() {
  const address = '0x0000000000000000000000000000000000001000'; // example
  const block = 10000000; // example historical block
  await getHistoricalBalance(address, block);

  const contract = '0x...'; // replace with contract address
  const logs = await getLogsPaged(contract, 10000000, 10001000);
  console.log(`Total logs: ${logs.length}`);
}

main().catch(console.error);

验证和结果表

要验证您的端点是否支持归档,请使用已知的历史余额运行上述脚本。例如,您可以在重大转账之前的区块检查一个知名地址的余额。如果返回的余额与区块浏览器中的预期值匹配,则您的端点具有归档数据。

填写下表以记录您的端点的行为。此方法可重现,并帮助您了解RPC提供商的限制。

  • 端点类型(全节点/归档)
  • 查询的区块号
  • 返回的余额(BNB)
  • 获取的日志(数量)
  • 遇到的错误
| Endpoint Type | Block Number | Balance (BNB) | Logs Fetched | Errors |
|---------------|--------------|---------------|--------------|--------|
| Archive       | 10000000     | 123.45        | 500          | None   |
| Full          | 10000000     | 0.00 (or error) | 0          | 'missing trie node' |

常见故障和修复

查询BSC历史数据时,您可能会遇到几个常见错误。以下是典型故障及解决方法。

错误:'missing trie node'或'header not found' – 这表明节点没有所请求区块的归档状态。解决方案:使用归档端点或减少历史深度。

错误:'query returned more than 10000 results' – eth_getLogs对每次调用的结果数量有限制。解决方案:按较小的区块范围分页,如脚本所示。

错误:'rate limit exceeded' – BSC RPC提供商实施速率限制。解决方案:实现退避和重试,并查看BNB Chain RPC速率限制和429指南。

日志不完整:如果您使用全节点,早于修剪窗口的日志可能缺失。解决方案:使用归档节点或保留日志时间更长的提供商。

  • 缺少trie节点:使用归档端点。
  • 结果过多:分页遍历范围。
  • 速率限制:实现退避。
  • 日志不完整:使用归档节点。

权衡和限制

使用归档节点进行历史查询有取舍。归档节点运行成本更高,并且由于状态庞大,某些查询的延迟可能更高。提供商可能以溢价或不同的速率限制提供归档端点。请务必查看提供商的文档以了解具体的保留和性能特征。

对于BSC,高交易量意味着即使在归档节点上,宽范围的eth_getLogs也可能很慢。建议使用地址和主题过滤器缩小搜索范围。此外,并非所有RPC提供商都为BSC提供归档数据;有些可能只提供全节点。OnFinality API服务RPC定价页面可以帮助您了解选项。

最后,请注意BSC的客户端生态正在发展。虽然所描述的方法是标准的,但追踪和调试方法可能有所不同。请始终针对您的特定端点测试您的查询。

  • 归档节点成本更高,延迟可能更高。
  • 宽范围的eth_getLogs可能很慢;使用过滤器。
  • 提供商的归档可用性各不相同;请查看文档。
  • 客户端特定方法可能不同。

后续步骤和进一步阅读

既然您了解了如何查询BSC历史数据,请探索以下相关资源以加深理解。

要更广泛地了解跨EVM链的历史数据查询,请参阅查询历史区块链数据(EVM食谱)。要比较节点类型,请阅读归档节点与全节点。如果您是BSC新手,请从BNB智能链网络概述开始。

有关实际RPC用法,请查看BNB智能链节点类型(RPC助手)OnFinality学习中心以获取更多指南。另外,请查看BNB Chain RPC速率限制和429以避免达到上限。

永远不用担心基础设施

OnFinality 消除了 DevOps 的繁重工作,让您能够更聪明、更快地构建。

开始