CKB Transaction CoBuild Protocol Overview

附录:CoBuild-Only or CoBuild+Legacy?

CKB script 现在有两种输入数据 (witness) 编码模式:

  • Cobuild 模式:使用本文定义的 WitnessLayout 格式读取数据
  • Legacy 模式:使用 WitnessArgs 格式读取数据

CKB 交易只关心包含的 scripts 和 witnesses 是否能验证通过,并不关心这些 scripts 是如何解析 witnesses 的。这意味着一个交易里面使用不同输入数据编码的 scripts 可以共存。

一个 CKB script 也可以做到两种模式都支持:例如优先寻找 WitnessLayout 格式读取数据,发现WitnessLayout 类型的 witness 缺失时,再从 WitnessArgs 格式中读取数据。

通常我们讨论 CoBuild 模式或者 Legacy 模式时,是指某一个 script 在已经确定了要用哪种输入数据格式后所处的某一个模式。此时这个 script 已经确定:要么只从 WitnessLayout 中读取数据(CoBuild 模式),要么只从 WitnessArgs 中读取数据(Legacy 模式)。

但是在下文中谈到 “一个 script 支持 CoBuild 模式”,是指一个 script 可以运作在 CoBuild 模式下(而不是“只能”或者“已经确定”运作在 CoBuild 模式下),从 WitnessLayout 中读取数据。与此对应的,“一个 script 支持 legacy 模式”,是指这个合约可以运作在 Legacy 模式下(而不是“只能”或者“已经确定”运行在 Legacy 模式下),从 WitnessArgs 中读取数据。

Lock Script

在过渡时期(现在直到 CoBuild 被广泛使用成为默认之前),我们不建议一个 lock script 只支持 CoBuild 模式而不支持 Legacy 模式。

Lock script 要同时支持 CoBuild 模式与 Legacy 模式并不复杂。它们的差异点只在 signing message hash 的局部计算上。除此之外,一个架构良好的 lock script 完全可以在两种模式下共享其余几乎所有的验签代码。

如果一个 lock script / 钱包希望尽可能支持尽可能多的 CKB apps,那么同时支持 CoBuild 模式以及 Legacy 模式是最优解。

Type Script

Type script 的考量点与 lock script 有一些不同。

不考虑 OTX 中一些极端情况,一个只支持 CoBuild 模式的 lock script,是无法与一个只能从 WitnessArgs 类型的 witness 中读取输入数据的 type script 在一个 cell 中一起使用的。

如果反过来呢?一个只支持 CoBuild 模式的 type script,可不可以与一个只能从 WitnessArgs 类型的 witness 中读取签名的 lock script(比如创始块中的单签多签)一起使用?答案是可以。

让我么看下面这个例子:

假设这里 I1 和 I2 都使用了创始块中的单签 lock,同时 I1 中使用了一个只支持 CoBuild 模式的 type script。一个有效的交易可以使用如上布局:witness #0 和 witness #1 使用 WitnessArgs 类型,witness #2 使用 CoBuild 模式的 WitnessLayout::SighashAll 类型,包含 I1 中 type script 所需要的 Action

按照传统意义上 lock script 的 convention,虽然 I1 和 I2 使用的 lock script 不能解析 witness #2 所使用的 WitnessLayout 格式,但是这里的 lock script 依然会把 witness #2 的全部数据签入签名。同时,I1 所使用的 type script 可以从 witness #2 中解析 Message,并找到对应自己的 Action。完成校验。

由此可以看出,只支持 CoBuild 模式不支持 Legacy 模式的 type script 不会有兼容性问题。对于 type script 来说,可以自行选择是只支持 CoBuild 模式,还是两种模式都兼容。我们的建议是实现 type script 时默认只支持 CoBuild 模式,有特别需要再考虑兼容 Legacy 模式。

Action 可能不存在

大部分情况下,CoBuild 交易中都会有 WitnessLayout::SighashAll witness,其中包含 Message,也包含当前交易用到的 type script 所对应的 Actions。但需要注意的是,CoBuild 协议没有要求 WitnessLayout::SighashAll 必须存在。

假设有一个 type script 只支持 CoBuild 模式,它需要面对的一个问题是:它是否应该能够处理因为 WitnessLayout::SighashAll 不存在,导致当前交易中没有对应自己的 Action 的情况呢?

对于这个问题,不同的 type script 需要根据自己的需求做决定。虽然 CoBuild 协议上没有禁止 Action 不存在的情况,但是 type script 可以选择在自己需要的 Action 不存在时,是直接报错退出,还是忽略 Action 继续校验。

应当指出的是,对于大部分场景,Action 的存在可以大大简化链上校验逻辑。不是所有的场景都能通过识别交易而(容易地)反向分析出输入数据。

因此对于 type script, 我们建议增加一条校验规则:一定要能在交易中找到所需的 Action 才能继续执行。

NervosDAO Type Script

NervosDAO type script 对于 CoBuild 流程来说是一个非常特殊的例子,它的特别之处在于其 type script 代码是以一个无法花费的 lock (lock hash = 0x0000…, all zero) 部署在创世块中的,这意味着 NervosDAO type script 无法通过硬分叉之外的方法升级。

如果想要在不做硬分叉不升级 NervosDAO type script 的情况下让它能兼容 CoBuild 流程,需要额外的特殊处理。一种做法是,在支撑 CoBuild 工具中 hardcode 针对 NervosDAO 的特殊逻辑,如果发现一个交易是 Nervos DAO 交易,就先做一些预处理:

  • 如果这个交易不包含 Nervos DAO Action,CoBuild 工具应该利用 raw tx data 构造一个可以用于前端呈现的 Nervos DAO Action
  • 如果这个交易包含 Nervos DAO Action,CoBuild 工具应该对这个 Nervos DAO Action 进行校验,在前端实现本应该是 Nervos DAO type script 要做的工作。

注意前面说过:在过渡时期(现在直到 CoBuild 被广泛使用成为默认之前),我们不建议一个 CKB lock script 只支持 CoBuild 模式而不支持 Legacy 模式。但由于 Nervos DAO type script 的特殊性,我们建议对于所有 Nervos DAO 操作,无论一个 lock 支持 CoBuild 模式与否,都应该只生成使用 WitnessArgs 类型的交易。即使有部分操作因为 Nervos DAO 本身不需要读取 witness,可以用 CoBuild 来做,也不应该用 CoBuild 来做,这样把所有情况都统一成用 WitnessArgs,简化实现。

在这个基础上,等未来某一天 Nervos DAO type script 由于某个原因升级时(目前没有明确计划),再通过升级 Nervos DAO type script,实现对 CoBuild 的完全支持。