一个接口访问多条链,哪些差异不能藏?

一个应用想把两条区块链上的记录放进同一张表。真正开始做时,工作很快超过“多加一个地址”:数据字段不同,查询方式不同,提交交易的步骤也可能不同。应用要反复处理这些差异,用户才能看到看似简单的一行记录。
统一访问层可以让应用少写重复的接入代码,但不能把决定记录含义的差异一起藏掉。 一笔交易来自哪条链、是否只是被提交、是否已经按该链的规则确认,仍然是应用需要保留的信息。
ArcBlock 在 2019 年“织链成网”的文章中介绍了 OCAP(Open Chain Access Protocol,开放链访问协议)的方向:通过共同的访问方式使用不同链的数据。后来授权的 US11676139B2 给出了更具体的适配器、数据整理及交易签名流程。两份材料让我们能讨论“统一”到底发生在哪里;它们不构成今天所有网络与端点的可用清单。
共同的入口,分别处理的链
这里的适配器,可以理解为懂某条链规则的接入模块。应用提交一个格式一致的请求,访问服务根据请求选择适配器,由它与对应网络交互。
专利权利要求 1 的请求中就包含指定区块链协议的参数。所谓与链无关的请求格式,并没有取消“我要操作哪条链”这个选择。它把共用的表达方式和各链的处理方式分开了。
适配器取得账本数据后,服务按该协议解析并存入结构化数据库。把结构化数据用于查询,可以减少每个应用各自整理原始账本的重复工作。也因此,应用读到的可能是服务整理的结果:结果有没有跟上链的状态,整理过程中保留了哪些信息,都需要确认。
用一个入口查询两条链,不意味着两条链之间已经交换消息。两份记录能放在一起,也不意味着其中一条链已经验证了另一条链。
同叫“余额”,未必按同一种方式花费
权利要求 1 分别描述了两种交易构造流程。一种基于 UTXO,也就是尚未花费的交易输出;另一种根据请求者控制的资产数量构造转账。权利要求 3 进一步指定了基于 Bitcoin 和 Ethereum 的网络。
可以把 UTXO 暂时理解为若干张还没花掉的收款记录。构造一笔支出,需要选用合适的记录作为输入,并安排接收方和可能的找零输出。账户余额式的表示则从账户可用的数量出发。这个类比只解释为什么构造交易的工作不同,不覆盖每条链的全部规则。
如果界面把两者都显示为“可用余额”,应用仍不能仅凭同一个数字就假定转账的构造、费用或失败条件一致。适配器可以承担部分差异,但业务仍要知道哪些条件会影响用户这次操作。
一个有用的统一字段,需要有清楚的定义。例如“已确认”是访问服务自定的阈值,还是对应链提供的状态?换一条链之后,这个字段是否仍表达相同程度的确定性?如果没有答案,统一名字只是把差异挪到了读者看不到的地方。
读取、构造、签名、广播不是同一步
这件专利并不只描述读取数据。权利要求 1 中,服务根据整理后的链数据生成未签名交易,将它交给客户端;客户端用相应私钥签名,服务收到签名后的交易,再向对应网络广播。
这个分工把交易准备与私钥签名分开。服务能够准备一份待签名内容,并不等于它因此取得用户的私钥。客户端保留签名步骤,也不意味着用户可以不看内容就放心签。
假设用户准备转出一笔资产。以下是用于检查这类设计的流程,不是某个现有端点的可复制调用:
| 阶段 | 需要确认什么 |
|---|---|
| 发出请求 | 网络、资产、目标地址和数量是否明确 |
| 收到未签名交易 | 实际编码的接收方、金额、费用等是否符合请求 |
| 客户端签名 | 使用的账户是否正确,签名覆盖了哪些内容 |
| 广播 | 交易是否已被送往预期网络,有无可跟踪的标识 |
| 等待结果 | 对应网络是否接纳并执行,应用采用什么确认规则 |
恶意或出错的服务可能提供不符合原请求的待签名内容。客户端或钱包应按目标链规则解读它,让用户或既定策略核对,再决定是否签名。私钥没离开客户端,不能单独证明一次操作符合用户意图。
广播成功也不能直接显示成“业务已完成”。访问服务接收了交易、节点看到了交易、交易被纳入区块、应用认为结果足够确定,是不同的状态。
GraphQL 不替链作证
GraphQL 让客户端描述希望得到哪些字段。GraphQL 官方说明解释的是查询语言与执行机制。它能改善取数方式,却不会因为响应采用这种格式,就给响应内容附上一份区块链真实性证明。
GraphQL 出现在该专利的从属权利要求 5。理解这件专利时,要把它放回请求、适配、结构化存储和交易流程的上下文。用“GraphQL 专利”概括,会丢掉真正需要解释的机制。
对应用而言,值得记录的是数据来自哪个网络、反映哪个区块或时点,以及是否存在索引延迟,也就是服务整理的数据落后于链上状态。如果服务提供可验证的证明,还要知道证明覆盖什么、由谁验证。若没有独立验证,读者至少应清楚自己正在依赖哪个数据服务。
假设两条链都返回“交易成功”。其中一条的记录可能已经满足应用的确认条件,另一条仍可能发生重组,即当前被接受的部分区块被另一条历史替换。统一响应格式不会消除这种差别。最终性讨论的是一段历史在协议条件下何时可被认为不会再改;它来自链的规则,不来自接口名称。
怎样使用这层抽象
适合的起点是一个具体的多链任务,例如汇集若干网络上的账户活动记录。先定义界面上每个字段的意思,再确定哪些工作交给适配器、哪些判断留给应用。不要先做一张字段名一样的表,再假定其中每格都能相互比较。
接入时可以选同一笔已知交易,分别查访问服务的结果与相应网络的记录。比较网络标识、资产单位、状态和时间点。再测索引落后、字段缺失、交易失败时,应用是否仍能给用户准确解释。这些检查评估的是你选用的服务,不是只检查接口长得是否统一。
涉及写入时,用测试账户验证完整的“构造、核对、签名、广播、观察结果”过程。当前支持哪些链、哪些操作、什么签名格式,应以所用版本的实际能力为准。历史文章和专利适合作为理解设计的依据,不宜直接当作当下 API 手册。
OCAP 学习节点提供较短的概念入口;专利记录提供原文和同族文献。
什么时候不值得统一
如果应用只依赖一条链,而且大量使用这条链特有的操作,直接采用原生接口可能更清楚。为了得到统一格式而隐藏业务必要的字段,反而会增加维护成本。
如果任务是把资产从一条链移动到另一条链,还需要单独设计或选择跨链机制。访问层能读取两个网络、向它们分别提交交易,不等于能保证两边操作同时成功,也不自动解决资产锁定、释放或消息验证。
OCAP 值得继续讨论的部分,是让应用复用访问方式,同时把影响正确性的差异留在可检查的位置。统一入口有价值;当用户要据此做决定时,链的身份、数据的新旧和交易的真实状态仍得看得见。
参考
- GraphQL Foundation. Introduction to GraphQL.
- Zhihong Mao, Peiling Ding, Tian Chen. Blockchain adapter, protocol, and access layer, US11676139B2. 2023.