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
。 - 聚合器验证并广播合并好的交易。