用途:讲解链上历史数据的读取与查询方法,核心观点是历史状态无法通过普通 RPC 廉价读取,需要索引器来处理。
主要内容: 一、常见误区。eth_call 只能读当前状态,读取历史区块状态需归档节点,成本高速度慢;用 eth_getLogs 循环扫描数百万区块是 O(n),会超时、被限流或消耗大量 RPC 额度;排行榜、活动流、分析类查询结果应放在链下,链上只存哈希做承诺。
二、事件即 API。Solidity 事件写入交易回执而非合约存储,发送成本低(基础约 375 gas,每个 indexed topic 约 375 gas,数据每字节约 8 gas),链下读取免费。应事件优先设计合约,每次状态变更都发事件;每个事件可用 3 个 indexed topic,用于会被过滤的地址和 ID。
三、直接读事件。用 viem 的 getLogs 适合最近几千区块、低流量合约和实时监控;扫描超过约 1 万区块的历史查询则不适用。
四、The Graph 子图。定义 schema、编写映射处理事件、部署后获得 GraphQL API,适合活动流、排行榜、NFT 浏览器、DeFi 看板等需要历史数据的场景。安装与部署命令:npm install -g @graphprotocol/graph-cli;graph init --studio my-subgraph;graph codegen;graph build;graph deploy --studio my-subgraph。Subgraph Studio 用于开发测试,免费,生产需发布到去中心化网络。
五、其他方案。Dune Analytics 用 SQL 做分析和看板,不适合做应用后端;Alchemy/QuickNode 提供 getTokenBalances、getNFTs、getAssetTransfers 等快捷查询但中心化;Etherscan/Blockscout API 适合简单日志查询但有速率限制;Ponder 偏 TypeScript、本地优先。
六、当前状态读取。当前余额、授权等直接 RPC 读取即可;多笔读取可用 Multicall3(地址 0xcA11bde05977b3631167028862bE2a173976CA11,多链同地址);实时更新可用 WebSocket 订阅(viem 的 watchContractEvent)。
限制:资料未提供各类方案的价格、性能指标及完整支持链列表,具体以官方文档为准。