题目
一个资产页面需要展示当前余额、代币元数据、历史转账、NFT 图片、法币价格和协议排行榜。哪些数据适合直接从 RPC 读取,哪些适合索引器或第三方 API?如何处理不同数据源的延迟、错误和相互矛盾?
考察目标
- 是否会按实时性、查询形态、历史范围和信任成本选择数据源。
- 是否理解索引器提供的是派生视图,可能落后、出错或受到 reorg 影响。
- 是否能为每个字段定义来源、区块高度、新鲜度和降级策略。
考察按数据语义选择来源、处理索引延迟与链重组,并建立可追踪的新鲜度和降级策略。
一个资产页面需要展示当前余额、代币元数据、历史转账、NFT 图片、法币价格和协议排行榜。哪些数据适合直接从 RPC 读取,哪些适合索引器或第三方 API?如何处理不同数据源的延迟、错误和相互矛盾?
当前余额、allowance、交易 receipt 和关键写操作前校验适合直接读取目标链 RPC,因为它们需要接近链头并绑定明确的 chainId 与 block。历史列表、聚合统计和跨合约关系查询适合索引器,因为原始 RPC 不擅长分页和关系查询。NFT 媒体、代币图标、价格和风险标签通常来自链外或第三方 API,必须明确它们不是链上事实。前端不要把多个来源混成一个无来源的对象;每项数据都应携带 source、chainId、blockNumber 或 observedAt,显示同步延迟,并为关键字段提供 RPC 复核。来源冲突时按业务语义决定权威级别,而不是简单相信响应最快的服务。
RPC 通过节点提供标准链数据和状态查询,适合:
latest、safe、finalized 或明确区块号的判断。它的限制包括请求次数、限流、单次日志区间、历史状态能力和复杂聚合成本。普通节点未必保留任意历史状态;从创世块在浏览器中扫描日志也不现实。RPC 返回的是节点当前看到的链视图,不等于每个节点都处于完全相同高度。
索引器消费区块、交易和事件,把它们转换成适合业务查询的实体。The Graph 的 Subgraph 通过 manifest 指定网络、合约和事件,再由映射逻辑写入 GraphQL 实体。
它适合:
索引器不是链的替代品。它可能尚未同步到最新区块、映射代码存在 bug、部署版本切换失败,或在 reorg 后需要回滚重放。查询时应关注索引高度和错误状态;对“能否立即执行写操作”这类关键判断,最好再用 RPC 读取最新状态。
第三方 API 常用于:
这些数据可能有自己的采样时间、缓存、计价市场、清洗规则和服务条款。图片 URL 或 metadata 即使源自链上 URI,实际内容也可能托管在可变的 HTTP 服务上。UI 应区分“链上字段”“索引派生字段”和“链外估值”,不能用一个绿色对勾暗示它们具有相同确定性。
不要先选供应商再把所有问题塞进去,应先给字段定义契约:
| 数据 | 主来源 | 复核或降级 | 关注点 | | ------------------- | ------------ | ---------------- | ------------------------ | | 当前余额、allowance | RPC | 备用 RPC | chainId、block、节点高度 | | 交易最终状态 | RPC receipt | 区块浏览器仅辅助 | confirmations、reorg | | 历史活动列表 | 索引器 | 分段 getLogs | 索引高度、分页、去重 | | NFT 媒体 | metadata/API | 占位图 | URL 安全、内容可用性 | | 法币价格 | 报价 API | 隐藏估值或备用源 | 时间戳、市场、币种 | | 排行榜 | 索引器/后端 | 显示上次更新时间 | 聚合口径、重算成本 |
不同来源冲突时先判断字段语义。例如余额用于提交交易时,以目标链最新 RPC 状态为准;历史页缺少一笔刚确认交易时,可以临时把本地交易记录与索引结果合并,并标记“同步中”,而不是篡改索引器返回值。
一个可维护的数据层应记录:
chainId 和合约地址。同时监控 RPC 链头、索引器高度和两者差值。降级时宁可展示“数据暂不可用”或“同步到区块 N”,也不要把过期缓存伪装成实时值。
type DataEnvelope<T> = {
data: T;
chainId: number;
source: "rpc" | "indexer" | "third-party" | "local-pending";
blockNumber?: bigint;
observedAt: string;
isStale: boolean;
};
function canAuthorizeWrite(balance: DataEnvelope<bigint>) {
return (
balance.source === "rpc" &&
balance.chainId === expectedChainId &&
!balance.isStale
);
}
这个结构不要求所有页面展示技术字段,但能阻止业务层把一个过期的第三方余额误当成写操作前的链上校验结果。
getLogs。发现这道题有问题? 反馈此题