Open Tx 协议头脑风暴[4]: 一个实现提案
Cipher Wang
Nervos Core Team正如前几篇系列文章中提到的,我建议 OTX 签名覆盖到原始交易的 范围级别 2,以适应各种用户场景。我们需要一个数据包来指示验证者如何检查一个 OTX 签名所覆盖到的字段。
数据结构
相比于 secp256k1_blake160_sighash_all,本提案在签名签名加了一个 sighash_coverage_array 字段,来识别这个签名覆盖了哪些字段。

sighash_coverage_array 字段包含了一个 tx_component 的列表,是一个 3-byte 的数据包,具有以下结构:

这里的 label 是交易组成中的类别 ID,它也可以作为一个结束标记。
| label | meaning | index_code | mask |
|---|---|---|---|
| 0000 | sighash_all | any | any |
| 1111 | end of list | any | any |
| 0001 | output | index of output | cell mask |
| 0010 | input | index of input (cell) | cell mask |
| 0011 | input | index of input (cell + since) | cell mask |
| 0100 | input | index of input (outpoint) | outpoint mask |
| others | reserved / error | -- | -- |
Cell index 是一个 12 位的无符号整数,它允许在单笔交易中最多有 4096 个输入或者输出。
Cell mask 是一个 8 位的哈希掩码,用于设置一个 cell 中的哪些字段将会被包含在签名中。
| cell mask bit | field in cell |
|---|---|
| 0 | capacity |
| 1 | type.code_hash |
| 2 | type.args |
| 3 | type.hash_type |
| 4 | lock.code_hash |
| 5 | lock.args |
| 6 | lock.hash_type |
| 7 | data |
Outpoint mask 用于设置输入中 outpoint 模式中的字段。
| outpoint mask bit | field in outpoint |
|---|---|
| 0 | tx_hash |
| 1 | index |
| 2 | since |
| others | reserved / error |
验证逻辑
使用此 OTX 协议的 lock 将遵循以下的验证过程。
- 根据 lock 对交易输入进行分组,并为每个组加载 witness
- 读取 witness 中前 3-btye 的数据包,如果
label等于0000,那么将整个交易进行哈希,然后作为签名验证的输入,或者 - 使用特定的 lock 通过输入的 cells 的哈希数据进行初始化
- 读取每一个
tx_compenont直到label等于1111,它是数据包的结尾。 - 使用
tx_compenont定义到的每个 cell 中的字段,更新哈希数据 - 然后继续从 witness 中提取签名
- 验证签名的有效性
多方交互
对于想要彼此交互,将他们的 otx 合并为一笔有效交易的双方或者多方,应该遵循以下的规则。
- 每个人参与者都需要组装他们各自的 open transactions,设置
sighash_coverage_array,并提供签名 - 最后的聚合器组合这些 open transactions,重新排列这些输入和输出,并相应地修改
sighash_coverage_array中的index_code。 - 聚合器验证并广播合并好的交易。