超级详解隔离见证(segregation witness)

隔离见证(segretation witness)

起源

隔离见证由比特币BIP141提出,将比特币区块中交易的数据结构稍加修改,以解决如下问题:

  1. transaction malleability 问题。
  2. SPV证明中传输交易的签名成为可选项,能够减少Merkle proof传输的数据量。
  3. 变相增加区块容量。

针对transaction malleabiity(交易延展性),有必要介绍一些背景知识。
在BIP141之前,比特币中一笔交易的数据结构如下:

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

nVersion表示交易的版本号,txins表示交易的输入,txouts表示交易的输出,nLockTime表示锁定时间,如果对交易数据结构感兴趣,可以参考比特币交易数据结构。比特币的txins中需要说明需要花费的是那一笔交易,比特币系统中对每一笔交易做两次sha256算法得到的32个字节的数据称之为txid,在txin中用txid来指明要花费的交易,同时还得提供相应的签名。比特币txins中具体的数据结构如下所示:

超级详解隔离见证(segregation witness)_第1张图片

以txin字段中的ScriptSig为例,scriptSig字段中需要提供签名和相应的公钥,一般形式为:[signature public key]的形式。
假如Alice向从Bob处购买了一件产品,向Bob发起了一笔交易TX,Alice的交易TX中会提供Alice的签名和公钥,如果Bob是一个恶意节点,Bob收到了TX之后可以对TX中的scriptSig进行修改,假如修改为如下形式:
[PUSH POP, signature, public key]
即在ScriptSig字段中先加入一些数据,然后再将这些数据POP,这样不影响交易的合法性,但是整个交易的txid已经发生了改变。如果Bob把转发修改后的交易,并且修改后的交易成功打包进入区块链,那么Bob不仅可以拿到Alice的转账,而且Alice还不能发现转账成功的事实,Alice可能再次向Bob发送转账交易,这种攻击方式就叫做transaction mallebility attack(交易延展性攻击)。
如果对比特币中交易的签名方式感兴趣,可以参考这篇比特币中对交易进行签名的详细过程。

比特币中用transaction 的全部内容做两次哈希得到的txid来区分不同的交易,交易txin中ScriptSig的可修改性给了恶意节点可乘之机。为了解决这个问题,BIP141 中提出修改transaction 的数据结构,即在每个Transaction的末尾追加一个字段“witness”,专门用于存储ScriptSig中的签名和公钥数据,ScriptSig中不再存储数据。带有隔离见证的交易的数据结构如下:
[nVersion][marker][flag][txins][txouts][witness][nLockTime]

  • nVersion、txins、txouts、nLockTime的涵义和之前交易数据结构中的涵义相同。
  • marker是1字节的数据,而且必须是0x00。
  • flag必须是1字节的非空值,当前默认为0x01。
  • witness字段是单独存储交易中所有txin中的ScriptSig,而原来交易中txin中的ScriptSig不再存储任何数据。
    对新的交易进行哈希求txid时,不再包含witness内容部分,此时恶意节点对witness内容的修改不会影响到txid,因此就可以解决交易延展性问题。因为witness的出现,产生了另一种transaction ID,称做wtxID,即对包括witness在内的全部交易内容做哈希值,得到的称之为tx hash。如果是一个non-segwit transaction,因为根本没有witness data所以他的txid会和tx hash完全相同,但如果是segwit transaction的话,两者的值则会不同。

注意:不管transaction是不是segwit,input去reference到前一个output的时候都是用txID而不是tx hash。

另外,尽管segwit 巧妙地解决了transaction malleability 的问题,但事实上,经过了多次的patch,现行的Bitcoin 系统在没有使用segwit 的transaction 仍然不会遭受到transaction malleability 的攻击了。

既然计算txid的时候不包括witness部分的数据,那么如何保证区块数据的唯一性呢?在BIP141中提出了解决办法:
类似于对所有txid计算merkle root一样,对所有wtxid,也计算一个merkle root,并且把这个数据放在coinbase的输出锁定脚本中,这个锁定脚本至少38个字节,其中前6个字节必须是0x6a24aa21a9ed,其含义如下:

超级详解隔离见证(segregation witness)_第2张图片

如果在coinbase中有多个scriptPubKey匹配这个规则,则把输出索引最高的认为是wtxid的merkle root值。这笔交易就是一个示例.

Witness program

为了在一般transaction 的架构下能支持segwit,因此BIP141 就选择在前一笔output 的locking script 动点手脚,只要看到scriptPubKey 是0x00 开头,他就被赋予了新的意义。

P2WPKH

witness:
scriptSig: (empty)
scriptPubKey: 0 <20-byte-key-hash>
(0x0014{20-byte-key-hash})

全名是pay to witness public key hash,和原本的P2PKH 一样,需要有一个长度为20 bytes 的public key hash,用来之后验证signature。而当花费这个output 时,本来要放入input scriptSig 的signature 和public key 被放入到了witness program,因此input 的scriptSig 就可以是空的。简单来说,scriptPubKey 的开头为0 让script engine 知道这是一个segwit transaction.数字0是版本号,有了版本号,未来脚本升级就能更容易的向前兼容。
接下来的20 bytes 让script engine 更明确知道这是一个P2WPKH output,因此script engine 就会去witness program 拿signature 和public key ,最后的验证就和普通P2PKH 一样了。

P2WPKH的解锁脚本为空,而真正的解锁脚本内容被移到了原交易之外的witness部分。

P2WSH

witness: 0 <1 2 CHECKMULTISIG>
scriptSig: (empty)
scriptPubKey: 0 <32-byte-hash> (0x0020{32-byte-hash})

全名是pay to witness script hash,和P2SH 很类似,witness program 装的内容基本上就是我们熟知的redeem script。和上面一样,scriptPubKey 的0 让script engine 知道这是一个segwit transaction,而接下来的32 bytes 让script engine 更明确知道这是一个P2WSH output,先透过验证witness program 的最后一个东西做sha256,要等于scriptPubKey的32-byte-hash,再来单独验证witness program 即可。

P2WPKH和P2WSH中分别用了不同的哈希函数,这是为了区分两种支付方式而做的设定。

注:上述脚本中小括号中是包含前缀内容的脚本,比如scriptPubKey中在32位的哈希值前面会有0x0020的前缀,16进制转换就是32,表示哈希长度有32位。

隔离见证的兼容性

考虑两种场景:
(1)付款人的客户端支持隔离见证,而收款人不支持
(2)付款人的客户端不支持隔离见证,而收款人支持
对于第一种情况,如果收款人不支持隔离见证,那最终发布的地址将会是普通地址(P2PKH或P2SH),那所有交易按照原有的规则进行即可。
而对于第二种情况,聪明的社区开发者想出了一个过渡方案,即将P2WPKH或P2WSH植入P2SH。

P2WPKH植入P2SH

witness:
scriptSig: <0 <20-byte-public-key-hash>> (0x160014{20-byte-key-hash})
scriptPubKey: HASH160 <20-byte-script-hash> EQUAL (0xA914{ 20-byte-script-hash}87)

此处的脚本Hash值为RIPEMD160(SHA256(0 <20-byte-public-key-hash>))的结果,将该脚本Hash转换为P2SH地址,就是一个兼容segwit的地址,不支持隔离见证的客户端可以正常支付比特币给这种P2SH地址。

而对于支持隔离见证的客户端,仍可以将验证信息放在witness结构中,当然这种过渡方案的交易会较完全形态的方案稍大一些,但比无隔离见证的情况要小。

P2WSH 植入P2SH

witness: 0 <1 2 CHECKMULTISIG>
scriptSig: <0 <32-byte-hash>>
(0x220020{32-byte-hash})
scriptPubKey: HASH160 <20-byte-hash> EQUAL
(0xA914{20-byte-hash}87)

和上面一样,P2WSH 也可以包在P2SH 里面。因为这本质是一个P2SH output,所以segwit 的识别就移到了input scriptSig 去,而witness 的内容也和原生的P2WSH 相同。

隔离见证地址

当隔离见证被大范围接受后,钱包将开始使用一种新的专门针对Segwit原生的地址类型,这种地址将使用Base32编码,而不再使用Base58,即全部使用小写字母和数字表达。
如果你看到以bc1开头的地址,就是使用隔离见证地址进行的交易,这就是一个隔离见证的示例

第一笔隔离见证交易

支持隔离见证的交易在481824个区块开始正式激活,
第一笔p2wpkh交易的id为:
dfcec48bb8491856c353306ab5febeb7e99e4d783eedf3de98f3ee0812b92bad
第一笔p2wsh交易的txid为:
461e8a4aa0a0e75c06602c505bd7aa06e7116ba5cd98fd6e046e8cbeb00379d6

隔离见证受到区块大小限制吗

有限制。
比特币的区块大小限制为1000000bytes,由于witness数据不包含在这个限制中,为了防止witness数据被滥用,仍然对总的区块大小做了限制。
引入了一个新概念叫块重量(Block weight)
Block weight = Base size * 3 + Total size
Base size是不包含witness数据的块大小
Total size是包含了witness数据的总大小
隔离见证限制Block weight <= 4000000。

隔离见证VS区块链扩容

隔离见证+闪电网络是区块链扩容的一种形式,这种技术看起来很好,然而从隔离见证的提出(2015年)到最终激活,经历了两年的时间,具体其中的内容,可以参考下面的链接:

比特币扩容战争始末
比特币扩容与分叉

引用

  • 深入了解segregated witness (segwit)
  • 深入比特币原理(十五)——隔离见证(Segregated Witness)
  • BIP141
  • BIP143
  • Bitcoin Transaction
  • transaction malleability

你可能感兴趣的:(区块链)