本文解释了什么是 Polkadot 和基于 Substrate 的链上的归档节点,它与修剪过的全节点有何不同,以及如何使用 state_getStorage 和 state_queryStorage 等方法通过 RPC 查询历史状态。文章包含一个可复现的 JavaScript 示例、常见故障模式以及何时使用归档节点的决策指南。
直接回答:如何在 Polkadot 上查询历史状态
要在 Polkadot 或基于 Substrate 的链上查询历史状态,你需要一个归档节点,该节点保留每个区块的完整状态树。通过 RPC,你首先使用 chain_getBlockHash 将给定的区块号解析为区块哈希,然后使用该哈希调用 state_getStorage 来读取该区块处的存储值。在修剪过的全节点上,此类查询要么失败,要么返回最新值,因为历史状态未被保留。
本指南将介绍 Substrate 存储模型、确切的 RPC 方法以及一个可运行的示例,你可以自行验证。它还涵盖了常见的陷阱和权衡,以便你决定何时需要归档节点以及如何访问它。
什么是 Polkadot 和 Substrate 上的归档节点?
Polkadot 和其他基于 Substrate 的链将其状态存储为通过运行时暴露的键值数据库。当前状态是一个 Merkle 树,每个区块产生一个状态根,该状态根提交到该点的整个状态。修剪过的全节点仅保留最近的状态(通常为最近几百个区块)以及足够的历史数据来验证最终性和提供区块头。相比之下,归档节点保留每个区块的完整状态树,允许你查询任何历史区块的确切存储值。
Polkadot 文档区分了节点类型:归档节点存储所有历史状态,而修剪节点则不存储。这是基于 Substrate 的节点的文档化行为,而非特定于提供商的功能。权衡在于磁盘空间和同步时间,这因链和配置而异;此处不提供通用数字,因为它们取决于链的大小和修剪设置。
有关更广泛的区块链背景下归档节点和全节点的深入比较,请参阅我们的 归档节点与全节点 指南。
- 归档节点:保留每个区块的完整状态树,支持历史状态查询。
- 修剪过的全节点:仅保留最近状态;历史查询受限或不可用。
- Substrate 状态是键值存储,不仅仅是账户余额;任何存储项都可以历史查询。
Substrate 存储模型与 RPC 方法
Substrate 通过一组存储键暴露状态。每个键是 pallet 前缀和存储项名称的哈希。例如,账户余额存储在从 System pallet 的 Account 存储派生的键下。要读取值,你提供存储键,并可选地提供区块哈希。你需要的 RPC 方法在 polkadot.js RPC 文档 和 Substrate RPC 文档 中有记录。
用于历史查询的关键方法:
chain_getBlockHash – 将区块号映射到其哈希。 state_getStorage – 在给定的区块哈希处读取存储值(如果省略则为最新区块)。 state_getKeys / state_getPairs – 列出特定区块的存储键或键值对。 state_queryStorage – 查询一系列区块中的存储更改,用于跟踪值何时更改。
这些方法适用于任何 Substrate 节点,但历史数据仅在节点是归档节点时才可用。Polkadot 节点基础设施文档确认,历史状态查询需要归档节点。
chain_getBlockHash– 区块号到哈希state_getStorage– 在区块哈希处读取存储值state_getKeys/state_getPairs– 枚举区块处的存储state_queryStorage– 查询区块范围内的存储更改
可运行示例:查询历史余额
以下 JavaScript 示例使用 @polkadot/api 库连接到 Polkadot 归档节点,并查询已知账户在过去区块的余额。安装依赖后,你可以使用 Node.js 运行它。将端点替换为你自己的归档节点 URL。
该示例将区块号 10,000,000 解析为哈希,然后读取特定账户的 System.Account 存储。在归档节点上,你获得真实的历史余额;在修剪节点上,你可能会收到错误或最新值。
要独立验证结果,你可以与提供历史余额数据的区块浏览器(如 Polkascan 或 Subscan)进行交叉检查,尽管这些是第三方服务。
// 安装:npm install @polkadot/api
const { ApiPromise, WsProvider } = require('@polkadot/api');
async function main() {
// 使用你自己的归档节点端点
const provider = new WsProvider('wss://rpc.polkadot.io');
const api = await ApiPromise.create({ provider });
// 要查询的区块号
const blockNumber = 10000000;
const blockHash = await api.rpc.chain.getBlockHash(blockNumber);
console.log('区块哈希:', blockHash.toHex());
// 要查询的账户(示例:一个知名地址)
const address = '15oF4uVJwmo4TdGW7VfQxNLavjCXviqxT9S1MgbjMNHr6Sp5';
const accountKey = api.query.system.account.key(address);
// 在历史区块读取存储
const accountInfo = await api.rpc.state.getStorage(accountKey, blockHash);
if (accountInfo.isEmpty) {
console.log('未找到数据(可能是修剪节点或账户不存在)。');
} else {
const data = api.registry.createType('AccountInfo', accountInfo);
console.log('区块', blockNumber, '的自由余额:', data.data.free.toString());
}
await api.disconnect();
}
main().catch(console.error);
// 预期输出(示例):
// 区块哈希: 0x...
// 区块 10000000 的自由余额: 1234567890常见故障与修复
查询历史状态时,你可能会遇到几个问题。以下是最常见的问题及解决方法。
如果你收到类似 State already discarded for ... 的错误,说明节点已被修剪,没有历史状态。解决方法是使用归档节点。如果你得到的是最新值而不是历史值,则节点可能因配置错误而忽略了区块哈希参数;确保你正确传递了哈希,并且节点没有位于剥离参数的代理之后。
另一个问题是使用了错误的存储键。存储键是经过哈希的;你必须使用正确的键格式。上面的示例使用 API 的 key() 方法生成键,这是可靠的。如果你手动构造键,请仔细检查哈希。
最后,公共端点可能会发生速率限制或超时。对于生产环境,请考虑通过我们的 RPC 助手 或托管服务使用专用端点。
- 错误 'State already discarded' – 节点已修剪;切换到归档节点。
- 返回最新值而不是历史值 – 验证区块哈希参数和节点配置。
- 无效的存储键 – 使用 API 的键生成方法。
- 速率限制/超时 – 使用专用或托管端点。
权衡与限制
归档节点对于某些用例至关重要,但它们会带来显著的成本。磁盘空间和同步时间远高于修剪节点。具体数字因链和配置而异;对于 Polkadot,归档节点的大小记录为比修剪节点大几倍,但此处我们不提供具体数字,因为它们会随时间变化。
即使在归档节点上,并非所有历史数据都可用。例如,已迁移或删除的存储可能无法访问。此外,查询非常旧的区块可能会很慢,因为节点必须遍历树。对于复杂的历史分析,你可能需要外部索引器或快照服务。
在决定是运行自己的归档节点还是使用托管节点时,请考虑你的查询频率和延迟要求。像 OnFinality 的 API 服务 这样的托管服务提供高可用性的归档节点,但你应该与提供商核实其保留策略。
有关 RPC 性能的更多信息,请参阅我们的 Polkadot RPC 延迟指南。
- 归档节点的磁盘空间和同步时间显著更高。
- 对于已迁移或删除的存储,历史状态可能不可用。
- 查询非常旧的区块可能会很慢。
- 对于复杂的历史查询,请考虑外部索引器。
决策指南:何时使用归档节点
当你需要回答诸如“这个账户在区块 N 的余额是多少?”或“当时的总发行量是多少?”之类的问题时,请使用归档节点。这些查询在审计、研究和构建需要历史上下文的 dApp 中很常见。
如果你只需要当前状态或最近的历史,修剪过的全节点就足够了,并且更具成本效益。对于事件日志或交易历史,你可能不需要归档节点;像 SubQuery 这样的索引器可以更有效地提供这些数据。
要快速入门,你可以使用公共归档端点,但要注意速率限制。对于生产环境,请考虑通过 RPC 定价 或托管提供商使用专用端点。始终针对已知的归档节点测试你的查询,以确保正确性。
- 对于特定区块的历史存储查询,使用归档节点。
- 对于当前状态和最近区块,使用修剪节点。
- 对于事件/交易历史,使用索引器。
- 在依赖查询之前,先在已知的归档节点上测试查询。
后续步骤与进一步阅读
既然你了解了如何在 Polkadot 上查询历史状态,你可以探索更高级的主题。如果你是 Polkadot 新手,请从我们的 Polkadot 网络概述 开始。有关更多 RPC 技术,请参阅我们的指南 查询历史区块链数据 和 Polkadot RPC 端点。
如果你正在考虑运行自己的节点,请查阅官方 Polkadot 文档中关于节点基础设施的内容。对于托管解决方案,请查看我们的 API 服务 和 RPC 定价。别忘了探索 OnFinality Learn 中心 获取更多教程。