Transaction ID
在新的结构下,每个交易将有两个ID.
txid保持不变,Double SHA256哈希以下序列化的数据:
[nVersion][txins][txouts][nLockTime]
新定义一个wtxid,Double SHA256哈希含有witness数据的序列化数据:
[nVersion][marker][flag][txins][txouts][witness][nLockTime]
其中:
nVersion,txins,txouts, andnLockTime保持不变marker必须为一个字节的零值:0x00flag必须为一个字节的非零值,目前使用0x01witness为交易的所有见证数据- 起始用
var_int表示有几个输入 - 然后每个项的起始用
var_int标识其数据长度 - Witness数据并不是脚本
- 起始用
如果一个交易输入不含有任何的witness program(可以视为不带OP操作码的scriptPubKey),则交易的wtxid等于txid。
Commitment
新增一个规则,coinbase交易的wtxid认为是0x0000...0000。
新增一个witness root hash,每个交易的wtxid作为叶子计算而来。类似原块头中的merkle root hash。
这个Commitment存在在coinbase交易的某个输出scriptPubKey中,长度必须至少为38Bytes,前六个字节内容固定是0x6a24aa21a9ed:
1 | 1-byte - OP_RETURN (0x6a) |
如果交易的多个输出符合六个字节前缀,则认为序列最大的输出项为Commitment。
Coinbase交易5b298d2e51d996cf6f8f5b12f2c44fa3203b39e0514025268b55ddc46ac72e73,其Hex内容为:
1 | 010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4d03819a08045cda6c5c2f706f6f6c696e2e636f6d2ffabe6d6db24bb958ea51e4bb25e0975c5ff65071a38f81d6e65a447105e1340b24171bee01000000000000009e2268d82707000000000000ffffffff025cac6d4b0000000017a914b757c3e4653706dd01f7b8345a6d71d96a7b136b870000000000000000266a24aa21a9ed5586b81f398ff1a8f20da1405bc92e6bbd2dda466414ca90bbd8215f77fe0c340120000000000000000000000000000000000000000000000000000000000000000000000000 |
分解Coinbase TX:
1 | 01000000 - version |
其实就是两套Merkle树,一套由txid作为叶子,一套由wtxid作为叶子。保持软分叉,块头不动,新的一套Merkle树根值,放入Coinbase交易里。Coinbase交易呢,走原来的Merkle树,根值放入块头。
Witness Program
Native Witness Program
此时输出的scriptPubKey内容为:
[version][witness_program]
version:1 bytes,表示版本,值范围是:[0, 16]witness_program: 数据,长度2~40 Bytes
当前,version是0x00,witness_program的长度为20或32字节。
比特币脚本中与version可能相关的OP操作编码:
1 | OP_0 = 0x00 |
P2SH Witness Program
即通过P2SH进行包装一下:
OP_HASH160 [20 BYTES HASH] OP_EQUAL
其中:
1 | 20_BYTES_HASH = HASH160(redeemScript) |
P2WPKH
P2WPKH,即Pay to Witness Pubkey Hash。Witness Program长度为20字节。
其中:
- version = 0
- witness_program = hash160(pubkey)
脚本堆栈为:
1 | Witness: |
通过执行CHECKSIG来完成签名验证:<signature> <pubkey> CHECKSIG。在验证脚本时,会先封装20bytes的数据为脚本:OP_HASH160 <20bytes> OP_EQUAL,并入栈执行。
若采用P2SH来包装的话,则有:
1 | witness: <signature> <pubkey> |
会先验证redeem_script的hash160,然后再分解redeem_script得到20Bytes,再包装为OP_HASH160 <20bytes> OP_EQUAL,并入栈执行。
P2WSH
P2WSH,即Pay to Witness Script Hash。Witness Program长度为32字节。
其中:
- version = 0
- witness_program = sha256(witnessScript)
脚本堆栈为(1/2多重签名):
1 | Witness: |
执行与P2SH的redeem_script一致,分为两步:
- 验证witness_script的sha256哈希值。
- 分解witness_script为子脚本,重新入栈并执行脚本。
其他共识规则
Block size 区块大小
原来的规则是单个区块大小最大值为1,000,000 Bytes,因剥离出Witness数据,这里提出一个新的单位Weight进行改进:
Block_Weight = Base_Size * 3 + Total_Size
Base_Size,基础大小,定义是:剥离witness相关数据后的大小,即未升级节点所看到的数据部分。Total_Size,全大小,定义是:包含witness相关数据的所有数据大小。Base_Size <= 4,000,000
Sigops 操作数
Sigops当前单个区块限制是 20,000,修改为:
用于pubkey script, signature script, 以及 P2SH check script的Sigops重新定义为原来的4倍。块限制亦同样的变为四倍 80,000.
Commitment结构可扩展性
现有commitment计算过程:
1 | Commitment hash: Double-SHA256(witness root hash|witness reserved value) |
例如我们新加了一个特性,其也有数据的commitment值,那么可以将原来的witness reserved value更新为:Hash(new commitment|witness reserved value),那么并不影响旧节点对commitment的校验。
1 | Double-SHA256(Witness root hash|Hash(new commitment|witness reserved value)) |
这个方法可以扩展为多个commitment,未来可以用于其他的软分叉升级。
未来的扩展
减少SPV欺骗
SPV节点目前依然有几个问题无法验证:
- 无法验证矿工是否在coinbase交易里增发币。不下载完整区块,就无法的得知所有交易的手续费,就无法得知块手续费。
- 无法验证是否违反其他共识规则,例如块大小限制、sigops限制。
- 无法验证输入交易是否存在,除非拿到直至coinbase交易的前向交易链条。
额外的数据可以采用commitment方式填入,借助软分叉升级。
新的脚本系统
scriptPubKey采用的版本号,若老节点看不懂这个新版本号,但会认为是任何人都可以花费的(因为脚本堆栈执行总是True),所以将来可以采用这种机制来新增脚本系统,并且都将是软分叉。
而witness部分目前是没有任何限制的,也就是说可以完全绕开520字节的脚本大小限制。未来也可以轻松引入新的签名机制,例如Schnorr签名。
参考: