Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

第 18 章 链上索引与可验证数据工作流

Walrus 应用通常有三条数据线:

  • Walrus 数据面:blob_id -> bytes
  • Sui 状态面:对象、交易、事件、epoch。
  • 应用索引面:数据库、搜索、缓存、权限视图。

可靠系统不是只读一个 aggregator,也不是只扫链上对象。它会把三条线对齐:链上状态说明“应该有什么”,Walrus 返回“实际能读到什么”,索引器提供“产品需要怎样查询”。

推荐索引表

一个通用表结构:

字段说明
networkmainnettestnetdevnet
asset_id业务对象 ID
blob_object_idWalrus Blob 对象 ID
blob_idHTTP 读取 ID
owner业务 owner
size字节数
end_epoch存储到期 epoch
tx_digest最近一次写入交易
object_versionSui 对象版本
statusactiveexpiredreplacedmissing
updated_at索引器更新时间

network + asset_id 应该唯一。不要让 mainnet 和 testnet 数据共用同一个主键空间。

事件驱动流程

推荐用事件作为主入口:

  1. 合约在创建或更新 Walrus 引用时发事件。
  2. 索引器按 checkpoint 拉取事件。
  3. 索引器再读取相关对象,确认对象当前版本。
  4. 后台任务调用 aggregator 做抽样读取或完整校验。
  5. 前端只查应用 API,不直接扫链。

事件驱动的好处是成本稳定、延迟可控,而且容易恢复。索引器重启后从最后处理的 checkpoint 继续即可。

可验证读取

读取路径不要只做“HTTP 200 就成功”。至少校验:

  • 返回的内容长度是否等于记录的 size
  • SDK 或协议层是否能验证 Blob 身份。
  • 如果业务层保存了 sha256 或 BLAKE2/3 摘要,下载后重新计算。
  • 读取的 blob_id 是否来自当前网络的索引记录。

后端示意流程:

GET /assets/:id
  -> 查 DB 得到 blob_id、size、hash、end_epoch
  -> 若 end_epoch 已过期,返回需要续期
  -> 向 aggregator 读取
  -> 校验大小和业务哈希
  -> 返回内容或签名 URL / 代理流

如果是大文件,不要在 API 层一次性读入内存。用流式代理、Range 请求或让前端直接读 aggregator,再把校验任务放在前端 worker 或后台任务中。

重组、延迟和幂等

Sui checkpoint 提供稳定的处理边界,但你的应用仍要处理重复投递和延迟:

  • 事件处理必须幂等,以 tx_digest + event_seq 或对象版本去重。
  • 同一对象的旧事件晚到时,不应覆盖新版本。
  • 索引器落库前先比较 object_version
  • 任何“已上传但未上链”的临时记录都要有超时清理。

一个安全的更新规则:

if incoming.object_version > stored.object_version:
    update row
else:
    ignore stale event

如果只按时间戳更新,节点时钟、重试和队列延迟都会制造脏数据。

链上索引对象还是链下数据库

共享对象注册表适合保存协议级目录,例如某个 collection 的根索引、治理控制的官方数据集列表。它不适合承担所有查询需求。

链上索引适合:

  • 少量、必须被合约读取的状态。
  • 需要权限和资产语义的记录。
  • 需要不可抵赖的审计锚点。

链下索引适合:

  • 全文搜索、标签、排序、分页。
  • 大量派生字段。
  • 内容可用性探测结果。
  • 多 aggregator 健康评分。

实践上,两者要组合:链上保存最小可信事实,链下保存产品视图。

续期和过期处理

过期不是偶发错误,而是生命周期的一部分。索引器应定期扫描:

end_epoch - current_epoch <= renew_threshold

然后把记录标记为 renew_required,通知 owner 或触发 sponsor 流程。不要等用户读取失败后才发现文件过期。

如果应用允许自动续期,必须设置预算边界:

  • 单用户每日续期上限。
  • 单 Blob 最大保存期。
  • 项目级 WAL/SUI 余额告警。
  • 续期失败的降级展示。

审计日志

每次引用变化都应保留审计记录:

字段用途
old_blob_object_id回滚和争议处理
new_blob_object_id当前内容定位
actor谁发起变更
tx_digest链上证据
reason可选,业务原因

不要为了“节省表”只保留最新值。Walrus 存的是内容,业务系统还要解释内容为什么变了。