本文介绍了一个在 Nervos CKB 上能实现 Open Transaction 的 lock script。它的灵感来自于之前 Open Tx Brainstorm 的设计,具有在 Open Transaction 中重新排序和重新安排签名组件的新能力。
Open Tx Brainstorm:
https://talk.nervos.org/t/open-tx-protocol-brainstorm-4-an-implementation-proposal/4427
数据结构
哈希阵列
受最初的 Open Tx 头脑风暴的文章的启发,我们在可组合的 OpenTx lock script 使用的签名前面添加了一个新的 hash_array 的数据结构。hash_array 包含一个 hash item 列表,如下所示:
| NAME | Command | Arg1 | Arg2 |
|------|---------|------|------|
| BITS | 8 | 12 | 12 |
一个 Hash item 包含 3 个 32 位(4 字节)长的物件。hash_array 不要求在开始处是有长度的字段,一个特殊的命令将标记哈希阵列的结束。在某种程度上,我们可以将哈希阵列看作是一个小型的虚拟机输入程序。这个虚拟机的目的是为了给 blake2b 哈希函数提供数据。来自哈希函数的哈希将用来作签名用的签名信息。
命令
本节将介绍接受 hash item 的有效命令,以及描述和所接受的参数。
首先,我们有一些常见的命令:
| COMMAND | DESCRIPTION | ARG 1 | ARG 2 |
|---------|-------------------------------------------------------------|-----------------------|--------------|
| 0x00 | Hash the full current transaction hash | ignored | ignored |
| 0x01 | Hash length of input & output cells in current script group | ignored | ignored |
| 0xF0 | Terminate and generate the final blake2b hash | ignored | ignored |
当虚拟机开始执行 hash_array 时,一个 blake2b 的哈希事件(hash instance)会被创建,大多数命令会生成一些数据。这些数据作为要哈希的内容,并放入 blake2b 事件中。例如,命令 0x00 将通过 CKB syscall 获取当前正在运行的交易的哈希值,然后将交易哈希值作为数据片段提供给 blake2b 事件。稍后我们将看到更多为 blake2b 哈希物件生成数据的命令。
看到 hash_array 的另一种方法是,每个哈希物件将生成的数据(除了一些项目不这么做以外,我们可以把这些哈希物件生成空数据),然后将所有数据连接到通过 blake2b 哈希算法的单一数据入口,并用之作为后续签名验证阶段的签名消息。
命令 0x01 会计算当前 lock script 组中输入和输出的 cell 的数量,并用 64 位无符号小端序格式的两个数字提供给 blake2b 事件来进行哈希。这可用于防止 Open tx 聚合器任意添加未处理的 cell。
命令 0xf0 填补了另一个不同的目的:一方面,它标示着 hash_array,另一方面,它通知这个小型虚拟机在此运行所有已经传送到虚拟机的数据,而且我们现在还可以从 blake2b 事件生成相应的哈希。此相应的 hash 也用作签名消息,用于稍后的签名验证阶段。
有了大体的工作流程后,我们就可以使用更多生成数据的命令了:
| COMMAND | DESCRIPTION | ARG 1 | ARG 2 |
|---------|-----------------------------------------------|-----------------------|--------------|
| 0x11 | Hash part or the whole output cell | index of output cell | `Cell mask` |
| 0x12 | Hash part or the whole input cell | index of input cell | `Cell mask` |
| 0x19 | Hash part or the whole output cell | offset of output cell | `Cell mask` |
| 0x1A | Hash part or the whole input ce