CKB Transaction CoBuild Protocol Overview

附录:Custom Union Ids in WitnessLayout

WitnessLayout 结构中,每一个 union variant 都有一个特殊的 custom union id(一个较大的magic number)。这是一个为了保持向前兼容用的技巧:通过这样特殊的取值可以让 WitnessLayout 和之前的 WitnessArgs 互不影响实现共存.

现在广泛使用的 WitnessArgs 是一个包含三个字段的 molecule table,它序列化后的数据大致是这样子的:

<length> <offset 1> <offset 2> <offset 3> ...

其中 lengthoffset 都是 little endian 的 u32 类型。

而一个 molecule union 的序列化结构大致是如下的样子:

<union id> ....

这里的 union id 也是 little endian 的 u32 类型。

对于 WitnessLayout 来说,它目前使用的 union id 是 0xFF000001, 0xFF000002 …。考虑未来扩充,WitnessLayout 应该只使用 0xFF000001 - 0xFFFFFFFF 这个范围作为这个类型允许的 union id 范围(这个范围有超过 16 million 个值,足够使用)。

假设有一个 WitnessLayout 格式序列化后的数据,这段数据前四个字节如果作为 little endian 的 u32 读取出来肯定不小于 0xFF000001。如果尝试把这段数据以 WitnessArgs 的类型进行解析,这段数据的前四个字节会作为整段数据的长度读取出来,e.g. 0xFF000001 == 4278190081 ~= 4080MB。但是 CKB 一个 block 最大只有 600k 左右,即使考虑将来可能的扩充,也很难达到 4000MB。因此实际上不可能构造出一个长度为 0xFF000001 甚至更长的 WitnessArgs 结构。所以如果把 WitnessLayout 格式序列化后的二进制数据,以 WitnessArgs 格式来解析,molecule 验证过程一定失败。

同样的,对于以 WitnessArgs 格式序列化好的数据,前四个字节读出来的值一定远远小于 0xFF000001,不可能是 WitnessLayout 使用的 union id。所以以 WitnessArgs 格式序列化好的数据,如果以 WitnessLayout 的结构来解析,molecule 验证过程也一定会失败。

因此交易 witness 中可以任意塞入 WitnessArgs 格式或是 WitnessLayout 格式的数据。链上合约也可以确定性的判断某一个 witness 使用的是什么格式。WitnessLayout 格式的数据以 WitnessArgs 格式解析校验一定会失败,同样的,WitnessArgs 格式的数据以 WitnessLayout 格式解析校验也一定会失败。未来还可以进一步扩充 WitnessLayout 格式,支持更多的可选类型。

如果只看编码的话,这里的 WitnessLayout union,也很是像先在 witness 上放置一个 4 个 bytes 的 ID,然后再放置实际的 witness 内容。同时靠这个 ID 与现有的 WitnessArgs 结构可以区分开来。WitnessLayout 通过 custome union id 实现了类似 version flag 的功能。