BIP141, Segregated Witness

Transaction ID

在新的结构下,每个交易将有两个ID.

txid保持不变,Double SHA256哈希以下序列化的数据:

[nVersion][txins][txouts][nLockTime]

新定义一个wtxid,Double SHA256哈希含有witness数据的序列化数据:

[nVersion][marker][flag][txins][txouts][witness][nLockTime]

其中:

  • nVersion, txins, txouts, and nLockTime保持不变
  • marker必须为一个字节的零值:0x00
  • flag必须为一个字节的非零值,目前使用0x01
  • witness为交易的所有见证数据
    • 起始用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
2
3
4
5
6
 1-byte - OP_RETURN (0x6a)
1-byte - Push the following 36 bytes (0x24)
4-byte - Commitment header (0xaa21a9ed)
32-byte - Commitment hash: Double-SHA256(witness root hash|witness reserved value)

39th byte onwards: Optional data with no consensus meaning

如果交易的多个输出符合六个字节前缀,则认为序列最大的输出项为Commitment。

Coinbase交易5b298d2e51d996cf6f8f5b12f2c44fa3203b39e0514025268b55ddc46ac72e73,其Hex内容为:

1
010000000001010000000000000000000000000000000000000000000000000000000000000000ffffffff4d03819a08045cda6c5c2f706f6f6c696e2e636f6d2ffabe6d6db24bb958ea51e4bb25e0975c5ff65071a38f81d6e65a447105e1340b24171bee01000000000000009e2268d82707000000000000ffffffff025cac6d4b0000000017a914b757c3e4653706dd01f7b8345a6d71d96a7b136b870000000000000000266a24aa21a9ed5586b81f398ff1a8f20da1405bc92e6bbd2dda466414ca90bbd8215f77fe0c340120000000000000000000000000000000000000000000000000000000000000000000000000

分解Coinbase TX:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
01000000 - version
00 - marker
01 - flag

Inputs:
01 - 1 input
input[0].prev-txout-hash 0000000000000000000000000000000000000000000000000000000000000000
input[0].prev-txout-position ffffffff
input[0].sigScript:
4d - len, 0x4d=77Bytes
03819a08045cda6c5c2f706f6f6c696e2e636f6d2ffabe6d6db24bb958ea51e4bb25
e0975c5ff65071a38f81d6e65a447105e1340b24171bee01000000000000009e2268
d82707000000000000
input[0].sequence: ffffffff

Outputs:
02 - 2 outputs
output[0].value - 5cac6d4b00000000
output[0].scriptPubKey - 17a914b757c3e4653706dd01f7b8345a6d71d96a7b136b87

output[1].value - 0000000000000000
output[1].scriptPubKey -
266a24aa21a9ed5586b81f398ff1a8f20da1405bc92e6bbd2dda466414ca90bbd821
5f77fe0c34

Witness:
01 - 1 witness item
witness[0].len - 20
witness[0].data -
0000000000000000000000000000000000000000000000000000000000000000

00000000 - locktime

其实就是两套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是0x00witness_program的长度为20或32字节。

比特币脚本中与version可能相关的OP操作编码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
OP_0 = 0x00

OP_1 = 0x51, // Alias OP_TRUE
OP_2 = 0x52,
OP_3 = 0x53,
OP_4 = 0x54,
OP_5 = 0x55,
OP_6 = 0x56,
OP_7 = 0x57,
OP_8 = 0x58,
OP_9 = 0x59,
OP_10 = 0x5a,
OP_11 = 0x5b,
OP_12 = 0x5c,
OP_13 = 0x5d,
OP_14 = 0x5e,
OP_15 = 0x5f,
OP_16 = 0x60

P2SH Witness Program

即通过P2SH进行包装一下:

OP_HASH160 [20 BYTES HASH] OP_EQUAL

其中:

1
2
3
20_BYTES_HASH = HASH160(redeemScript)

redeemScript = [version] + [witness_program]

P2WPKH

P2WPKH,即Pay to Witness Pubkey Hash。Witness Program长度为20字节。

其中:

  • version = 0
  • witness_program = hash160(pubkey)

脚本堆栈为:

1
2
3
4
5
6
7
8
Witness:
[signature] [pubkey]

scriptSig:
(empty)

scriptPubKey:
[0] [20_bytes]

通过执行CHECKSIG来完成签名验证:<signature> <pubkey> CHECKSIG。在验证脚本时,会先封装20bytes的数据为脚本:OP_HASH160 <20bytes> OP_EQUAL,并入栈执行。

若采用P2SH来包装的话,则有:

1
2
3
4
5
     witness: <signature> <pubkey>
scriptSig: <redeem_script>
scriptPubKey: HASH160 <20-byte-script-hash> EQUAL

redeem_script : [version] + [witness_program]

会先验证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
2
3
4
5
6
7
8
9
10
11
Witness:
0 <signature1> <witness_script>

scriptSig:
(empty)

scriptPubKey:
[0] [32_bytes]

其中:
witness_script = 1 <pubkey1> <pubkey2> 2 CHECKMULTISIG

执行与P2SH的redeem_script一致,分为两步:

  1. 验证witness_script的sha256哈希值。
  2. 分解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
2
3
Commitment hash: Double-SHA256(witness root hash|witness reserved value)

witness reserved value: 当前是32 bytes的零值,存在在coinbase交易的witness里

例如我们新加了一个特性,其也有数据的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签名。


参考: