全部文章

阅读约 8 分钟

如何在 Label 309 网关之上构建产品

Label 309 网关是存在性证明产品背后的发布引擎:它负责 Cardano 提交、存储、余额、索引和 webhook,从而让你的产品得以专注掌控用户体验。

要构建存在性证明功能,又不想自己运营一条区块链,那就在网关之上构建。Label 309 网关是存在性证明产品背后的发布引擎:它承担那些繁重的运营工作——报价、上传、Cardano 交易提交、确认、reorg 处理、记录索引、账户余额、存储资金、API 密钥和 webhook——并通过普通 HTTP 把这一切暴露出来。你的产品只需调用这些端点,便能掌控用户真正看到的一切:界面、计费关系、业务流程,以及品牌。

网关内核是开源的,CardanoWall 就是构建在它之上的参考产品。对开发者而言,最有用的一点是这里没有任何私有通道:CardanoWall 通过与你完全相同的公开端点接入网关,因此任何对参考产品有效的模式,对你同样有效。

谁适合在网关之上构建?

如果你想把存在性证明做成产品「内部」的能力,而不是用户在网站上手动执行的一个动作,那就在网关之上构建。

适合的场景包括:

  • 文档公证产品
  • 合规证据归档
  • AI 来源溯源与数据集治理平台
  • 持续集成证明系统
  • 法律证据工具
  • 加密披露门户
  • 媒体真实性服务
  • 企业内部审计工具
  • 出版方证明页面

在所有这些场景里,用户都不想去琢磨 Cardano 交易构造、UTxO 资金、存储积分或链上确认。他们想要的是一套能产出持久、可验证证明的工作流。网关让这套工作流成为可能,而你的团队无需变成 Cardano 基础设施的运营方。

网关负责什么,你的产品又负责什么?

这种分工正是关键所在,因此值得讲清楚。网关负责基础平面——发布流水线,以及其背后所有的资金、链上和存储状态:

  • 报价、上传与发布
  • Cardano 交易的构建、提交、确认、reorg 处理,以及永久失败时的退款
  • 内容与密文上传到存储,以及背后的存储资金
  • 一个覆盖网络上每一条 Label 309 记录的共享链上记录索引
  • 账户余额,以及驱动余额变动的账本条目
  • 外汇定价与利润率
  • API 凭据与 webhook 投递

这是基础设施工作。它在生产环境中必须精确、可观测,并且平淡无奇。除非运营网关本就是你的本职工作,否则你的应用不应去重新实现它——若运营网关确实是你的工作,请参阅运营你自己的网关

你的产品负责供应商平面——一切属于供应商范畴的事务:

  • 用户账户与会话
  • 注册引导与计费
  • 产品权限
  • 你的界面和你的邮件
  • 你向客户展示的定价
  • 诸如「案件」「版本」「数据集」或「证据包」等业务概念
  • 由网关事件构建的读模型
  • 支持工作流

网关无需知道一份证明属于某起诉讼、某次模型训练、某个季度合规材料包,还是某一期杂志。它只需发布正确的 Label 309 记录,并维护围绕这些记录的运营状态。这种分离让两套系统都更整洁:你的产品可以重建或重塑品牌,而不必触及链上或资金状态;网关可以升级,而无需知道你的产品是否存在。

你如何代表用户调用数据平面?

数据平面(/api/v1/*)是面向账户的 API。只要操作是代表某个用户或账户发起的,就使用它:

  • 为一次发布报价
  • 上传内容或密文
  • 发布一条记录
  • 读取余额或账户账本
  • 列出、获取或验证公开记录
  • 注册账户范围的 webhook

在包装式产品中,你的后端为用户的网关账户铸造一个短期有效的账户令牌,客户端只携带它所需的权限范围去调用数据平面。这些权限范围就是权限边界:发布界面需要 poe:create,余额组件需要 account:read,而公开记录端点根本不需要任何凭据——它们服务于匿名调用方,这正是让索引成为公共资源、而非按客户隔离的视图的原因。

令牌在设计上就是短期有效的(默认一小时)。每个会话铸造一个,过期后重新铸造,这样一个泄露的令牌只是一个一小时的小问题,而非一起安全事件。另外,绝不要把运营方凭据发送到浏览器——这正是下一节要守护的那条唯一铁律。

你如何以运营方身份调用控制平面?

控制平面(/control/v1/*)仅供受信任的后端和运营方使用。用它来:

  • 创建网关账户,并启用或禁用它们
  • 在你的计费系统收款后,应用账本调整
  • 设置按账户划分的利润率
  • 铸造账户令牌和 API 密钥
  • 注册运营方 webhook 事件流
  • 注册并管理钱包和存储资金来源
  • 读取审计与运营状态

这个平面藏在你的后端之后。把运营方凭据当作具有支出权限的生产密钥来对待——因为它们确实有支出权限。一个短期有效的运营方令牌(默认 24 小时)处理日常管理;而那个唯一的根密钥,应保存在密钥库中,仅保留给注册钱包和存储来源的少数几项操作使用。

控制平面是你的计费系统与网关预付余额保持连通的方式。一笔付款在你的系统中成功后,你的后端便向网关账户应用一次幂等的账本调整。这就是整条充值通路的全部,接下来的两节会解释它为何要这样设计。

你为什么不该直接查询网关的数据表?

因为契约不是数据库结构,而是 HTTP API 和 webhook。

网关引擎拥有它自己的 Postgres 数据库结构(cw_corecw_api)。即便两套系统共享同一个 Postgres 实例,你的产品也不应读写它们。数据库结构共存是一种受支持的部署形态,但边界在于「数据库结构」,而非数据库本身:这些引擎数据库结构是内部的,可能在没有任何通知的情况下变更,而 HTTP 平面和事件流则是稳定的。如果你越过这道边界,一次例行的网关升级就可能悄无声息地破坏你的产品。

如果你需要 API 尚未暴露的数据,请把它当作一个有待提出的 API 缺口——而不是跨数据库结构做联表查询的许可。

你如何用网关事件构建自己的界面?

每个产品都需要自己的视图:已发送记录、客户历史、余额、发布失败、案件时间线、证据包、审计看板。不要靠轮询每一行数据、或联入网关内部来构建这些视图。

正确的做法是:注册 webhook,把事件投影到你自己的数据表中。网关暴露一个运营方事件流——实例上每一个生命周期事件——外加面向更窄工作流的账户范围 webhook 订阅。「已发送项」视图就是一个典型例子:消费发布状态事件,把它们投影到你自己的数据表里,再从那里渲染。

投递保证至少一次,所以要让你的投影具备幂等性。一个实用的读模型可以以这些字段为键:

  • 事件 id 或投递 id(这样重复投递就是一个空操作)
  • 网关的记录 id
  • 最终的交易哈希
  • 你自己的用户 id
  • 你自己的业务对象 id
  • 状态与时间戳

随后你的界面便从你自己的数据表渲染,而网关始终是支出、发布生命周期和链上事实的权威来源。每一次投递都带有签名;在信任一个事件之前,请验证签名,并强制执行一个时间戳容差窗口。

资金应如何在你的计费系统与网关之间流动?

把模型保持简单:网关余额就是可支出余额,而你的计费系统只是资金到达它的一种途径。

你的计费通路可能收取银行卡、发票、加密货币付款、手动企业额度或赠款。网关无需知道这其中的任何一项。整洁的模式是:

  1. 你的计费系统确认一笔付款。
  2. 你的后端以该付款的 id 为键,向网关账户应用一次幂等的账本调整。
  3. 网关余额增加。
  4. 后续的发布和上传操作从该余额中扣款。
  5. 如果一次发布永久失败,网关会自行冲销这笔扣款。

由此引出两点推论。第一,幂等性至关重要,因为计费流水线的投递保证至少一次:把付款本身的 id 作为调整引用传入,这样同一笔付款投递五次也只会给余额充值一次。第二,不要把网关账本镜像到你自己的数据表里,并把这个镜像当作支出决策的真实依据——若有必要可缓存它用于渲染,但只要决策真正涉及资金变动,就去读取网关。由于网关会发放它自己的退款,你也不应为发布失败构建一条供应商侧的退款通路;那会导致重复退款。

每一类密钥应当存放在哪里?

网关永远不应该需要用户的身份种子。客户端或 SDK 可以在本地计算内容哈希、加密封存载荷、并对记录签名;网关只发布最终的记录字节,并提交 Cardano 交易。(关于这道边界为何从头到尾都重要,参阅为什么密钥永不离开设备。)

一个完整的集成包含若干彼此不同的密钥类别,而要避免的错误是把它们压扁成单一的「API 密钥」。它们的影响范围天差地别:

  • 用户身份种子和接收方私钥——用户的密码学身份,应当留在边缘端
  • 由该身份派生的记录签名密钥
  • 账户 API 密钥和短期有效的账户令牌——应当存放在需要它们的产品或客户端环境中
  • 运营方令牌和根密钥——只应存放在受信任的后端上
  • 网关自有的 Cardano 与存储签名密钥,以及它的 webhook 签名密钥——应当存放在网关密钥环中

把每一类密钥映射到能容纳它的最小范围,单次泄露就会被限制在可控范围内。

你何时应该自托管网关,而不是使用托管网关?

当运营独立性比便利性更重要时,就自托管。

对大多数集成而言,托管网关是最简单的路径:你通过一个现成的服务、用标准 API 接口发布,从不自己运营链上或存储操作。自托管用这份简单换取掌控权——你自己的 Cardano 钱包资金、你自己的存储资金、你自己的运营方策略、你自己的可用性与网络依赖、你自己的利润率、你自己的合规边界,以及在发布上不依赖任何第三方。

但掌控权同时也是责任。自托管意味着你要为 ADA 和存储积分注资、保护密钥环、运营 Postgres、监控链上提供方、处理备份、轮换凭据、管理 webhook,并应对故障事件。它移除了一项供应商依赖;它并不会移除运营工作本身。运营你自己的网关详细讲解了这究竟意味着什么。

你的用户应当在一份证明里看到什么?

大多数用户首先应当看到你的产品概念。他们关心的是「发布证据」「封存这个文件」「证明这份数据集快照」或「锚定这次发版」。他们不应当为了使用产品而去读一份元数据规范。

即便如此,每一个证明视图都应当暴露那些让主张可被独立核验的事实:

  • 交易哈希
  • 区块时间与确认状态
  • 哈希算法与摘要
  • 记录已签名时,签名方的公钥
  • 存在时的存储 URI
  • 相关时的封存接收方状态
  • 记录批量处理多个文件时的 Merkle 根与叶子证明
  • 验证结论本身

这正是产品既保持好用、又不掩盖其底层密码学主张的方式。

你如何避免把产品锁定到单一网关?

网关帮助你发布;它绝不应当「变成」那份证明本身。

链上的记录是 Label 309 元数据,而验证在设计上只需三项输入即可完成:交易元数据、可选的内容字节,以及一个公开的 Cardano 区块浏览器——只有在解密封存记录时才额外需要接收方密钥。没有任何签发方服务器处于这条信任路径中。如果你的网关明天消失了,一条有效的记录仍应能用独立工具验证。同样值得记住的是,这样一份证明断言了什么、又没断言什么:它表明确切的字节在某个公开时间点之前就已存在,但并不表明关于这些字节的任何主张为真、归属于谁,或获得了授权。

围绕这一承诺来构建你的产品:

  • 持久地存储交易哈希
  • 让用户导出验证报告并下载证据包
  • 保留 Merkle 叶子列表及其证明
  • 文档化如何在你的界面之外验证一条记录
  • 避免只有你的后端才能解读的私有字段

这正是「我们有一行数据库记录」与「我们产出了一份任何人都能核验的证明」之间的区别。

延伸阅读

gatewayapidevelopers