附录: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> ...
其中 length
和 offset
都是 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 的功能。