背景图

BIP-141 隔离见证

抽象

这个BIP定义了一个称为“见证”的新结构,它承诺与交易处理树分开的块。该结构包含检查交易有效性所需的数据,但不需要确定交易影响。特别是,脚本和签名被移到这个新的结构中。

目击者是通过coinbase交易嵌入到块的现有merkle根目录中的树,以使BIP软叉兼容。未来的硬分叉可以将这棵树放在它自己的分支中。

动机

整个交易的效果由输出消费(花费)和新输出创造决定。其他交易数据,特别是签名仅用于验证区块链状态,而不是确定区块链状态。

通过从交易结构中删除这些数据,这些数据被提交给交易处理树,几个问题得到解决:

  • 无意的延展性变得不可能。由于签名数据不再是交易散列的一部分,因此交易签名方式的变化不再与交易标识相关。作为交易可延展性的解决方案,这比典型签名方法(BIP62)要优越:
    • 它可以防止任何类型脚本的非自愿交易可塑性,只要所有输入都被签名(至少使用一次CHECKSIG或CHECKMULTISIG操作)
    • 如果是m-n CHECKMULTISIG脚本,只有经过m个私钥持有者的同意才能进行交易(相对于只有1个拥有BIP62的私钥持有者)(注:隔离见证是需要比特币协议的支持的
    • 它防止由于未知的ECDSA签名延展性而导致的非自愿交易延展性(我觉得应该是指scriptSig不签名而导致的问题)
    • 它允许创建未经证实的交易依赖链而没有交易对手风险,这是离线协议的重要特征,如Lightning Network.
  • 签名数据的传输变为可选。仅当对等方试图验证事务而不是仅仅检查其存在时才需要它。这样可以减少SPV证明的大小,并有可能提高SPV客户端的隐私,因为他们可以使用相同的带宽下载更多的事务。
  • 通过将一部分交易数据移动到当前协议未知的结构中,可以通过软分支绕过某些约束,例如:
    • 在计算块大小时,见证的大小可以忽略/打折,在一定程度上有效地增加块大小
    • 可以重新评估或删除硬编码常量,例如最大数据推送大小(520字节)或信号限制
    • 可以引入新的脚本系统,而不受现有脚本语义的任何限制。例如,在BIP143中描述了用于交易签名验证的新的交易摘要算法

规范

交易ID

一个新的数据结构witness被定义。每笔交易将有2个ID。

定义txid保持不变:传统序列化格式的双SHA256:

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

wtxid定义了一个新的:具有目击者数据的新序列化的双SHA256:

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

  • nVersion,txins,txouts和nLockTime的格式是像传统的序列化。
  • marker必须是一个1字节的零值:0x00。
  • flag必须是1个字节的非零值。目前,必须使用0x01。
  • witness是交易的所有见证数据的序列化。每个txin都与witness字段相关联。witness字段以var_int开始,以指示txin的堆栈项目的数目。随后是堆栈项目,每个项目以var_int开头以指示长度。见证数据不是脚本。

非见证人程序(定义于下文)txin必须与空的见证字段相关联,使用0x00表示。如果所有的txins都不是witness程序,交易wtxid就等于它的交易txid。

承诺结构

添加了一个新的区块规则,它需要对wtxid做出承诺(翻译是这样意思不太懂,也许是指要有wtxid字段吧)。coinbase交易的wtxid被认为是0x0000….0000。

witness根hash的计算方法与所有wtxid叶子一样,以类似于hashMerkleRoot块头中的方式计算。(其实就是与交易的默克尔树是一样的。)

该承诺记录在coinbase交易的scriptPubKey中。它必须至少有38个字节,其中前6个字节0x6a24aa21a9ed是:

  • 1个字节 - OP_RETURN(0x6a)
  • 1字节 - 推送以下36个字节(0x24)
  • 4字节 - 承诺(Commitment)头(0xaa21a9ed)
  • 32字节 - 承诺哈希:Double-SHA256(见证根哈希|见证保留值)
  • 第39个字节向前:可选数据,没有共识意义

并且coinbase的输入见证必须由一个32字节的数组组成witness reserved value

如果有多个scriptPubKey匹配的模式,那么具有最高输出的索引的scriptPubKey被假定为承诺(commitment)。

如果块中的所有交易都没有见证数据,则该承诺(commitment)是可选的。

见证程序(就是脚本啦)

由1字节推送(push)操作码(0至16)组成的scriptPubKey(或redeemScript如BIP16/P2SH中定义的),然后是2至40字节之间的数据推送,具有新的特殊含义。第一次推送的值被称为“版本字节”。下面推送的字节向量称为“见证程序”。(这个意思就是指NVersion + Script序列化后的数据吧!)

witness验证逻辑被触发有两种情况。每种情况都决定了witness版本字节和程序的位置,以及scriptSig的形式:

  1. 触发scriptPubKey一个版本字节,再加上一个witness程序。scriptSig必须完全为空或验证失败。(“本地witness程序”)
  2. 当scriptPubKey是P2SH脚本时被触发,并且redeemScript推入的BIP16 scriptSig恰好是推送版本字节加推送见证程序。在scriptSig必须是完全的BIP-16的redeemScript或验证失败。(“P2SH witness程序”)

如果版本字节是0,见证程序是20字节:

  • 它被解释为pay-to-witness-public-key-hash(P2WPKH)程序。
  • witness必须包含2个项目(每个≤520个字节)。第一个是签名,第二个是公钥。
  • 公钥的HASH160必须与20字节的见证程序相匹配。(不知这条的作用是啥,但是感觉很有用的样子)
  • 在正常的脚本评估之后,使用CHECKSIG操作对照公钥验证签名。验证必须在堆栈上导致一个TRUE。

如果版本字节为0(版本为0代表什么意思呢),见证程序为32字节:

  • 它被解释为pay-to-witness-script-hash(P2WSH)程序。
  • witness必须包含一个输入堆栈以供给脚本,然后是序列化脚本(witnessScript)。
  • witnessScript(≤10,000字节)从初始witness堆栈弹出。witnessScript的SHA256加密必须与32字节的见证程序相匹配。
  • witnessScript是反序列化的,并且在对其余见证堆栈(对于每个堆栈项≤520字节)的正常脚本评估之后执行。
  • 该脚本不能失败,并且在堆栈中导致完全一个TRUE。

如果版本字节为0,但见证程序既不是20也不是32字节,则脚本必须失败。
如果版本字节为1到16,则不会再有对witness程序或witness堆栈的进一步解释,并且证人堆栈没有大小限制。这些版本保留给未来的扩展.

其他共识关键限制

块大小

目前块的总大小限制为1,000,000字节(1MB)。我们改变这个限制如下:

块重量定义为基本大小 * 3 + 总尺寸。

基本大小是原始交易序列化时的块大小(以字节为单位),没有任何见证相关数据,如未升级的节点所示。

总大小是按BIP144所述序列化交易的块大小(以字节为单位),包括基本数据和见证数据。

新规则是块重 ≤4,000,000。

SIGOPS

每块的信息量目前仅限于20,000个。我们改变这个限制如下:

当前pubkey脚本,签名脚本和P2SH检查脚本中的Sigops的计数是其先前值的4倍。sigop限制同样翻两番,达到80,000。

每个P2WPKH输入都被计为1 sigop。另外,P2WSH内的操作码witnessScript与先前在P2SH内的操作码相同redeemScript。也就是说,CHECKSIG被认为只有1个sigop,根据参数CHECKMULTISIG被计为1到20个sigops。该规则适用于本地证人计划和P2SH证人计划。

附加定义

以下定义不用于达成共识限制,但建议提供符合上述术语的语言。

事务大小计算

交易权重定义为基本交易规模 * 3 + 总交易规模(即与从基本规模和总规模计算分块权重相同的方法)。

虚拟交易大小定义为交易权重/4(四舍五入到下一个整数)。

基本交易大小是剥离见证数据的序列化交易的大小。

总交易大小是按BIP144中所述序列化的交易大小(以字节为单位),包括基本数据和见证数据。

新的脚本语义

尽管P2WPKH和P2WSH的脚本语言看起来与预先隔离的witness脚本非常相似,但有几处显着的差异。用户不得假定在预先隔离的witness系统中花费的脚本也可以用作P2WPKH或P2WSH脚本。在生产网络中进行大规模部署之前,开发人员应该在testnet上测试脚本,并启用默认的中继策略,并在主网络上激活BIP141之后用少量资金进行测试。

在BIP143中描述了共识级别的一个主要区别,即作为0版见证程序中用于签名验证的新的交易摘要算法。

在参考实施版本0.13.1的第​​一版隔离见证中还包括三项接力和采矿政策。基于这些政策的软分叉很可能会在不久的将来提出。为了避免无限期延迟交易确认和永久性资金损失,用户必须仔细观察新的语义:

  • 在P2WPKH和P2WSH中只接受压缩的公钥(见BIP143
  • P2WSH中OP_IF/NOTIF的参数必须最小
  • 如果OP_CHECKSIG或OP_CHECKMULTISIG失败(对于预先隔离的证人脚本和P2WSH,则签名必须为空矢量(参见BIP146

例子

P2WPKH

以下示例是版本0的pay-to-witness-public-key-hash(P2WPKH):

1
2
3
4
witness:      <signature> <pubkey>
scriptSig: (empty)
scriptPubKey: 0 <20-byte-key-hash>
(0x0014{20-byte-key-hash})

scriptPubKey中的’0’表示以下推送是版本0见证程序。见证计划的长度表明它是一种P2WPKH类型。证人必须包含2件物品。witness中公钥的HASH160必须与witness程序相匹配。

签名被验证为

1
<signature> <pubkey> CHECKSIG

<b style=””color:red>与传统P2PKH输出相比,P2WPKH等价物在scriptPubKey中占用3个字节,并将签名和公钥从ScriptSig移动到见证。(找到数据应该是通过wtxid)

P2WPKH嵌套在BIP16 P2SH中

以下示例与P2WPKH相同,但嵌套在BIP16 P2SH输出中。

1
2
3
4
5
witness:      <signature> <pubkey>
scriptSig: <0 <20-byte-key-hash>>
(0x160014{20-byte-key-hash})
scriptPubKey: HASH160 <20-byte-script-hash> EQUAL
(0xA914{20-byte-script-hash}87)

scriptSig中的唯一项目与HASH160进行哈希处理,与scriptPubKey中的20字节脚本哈希进行比较,并解释为:

1
0 <20-byte-key-hash>

然后按照前面例子中的描述验证公钥和签名。

与前面的例子相比,scriptPubKey大1个字节,scriptSig大23个字节。尽管嵌套见证程序的效率较低,但对于自0.6.0版本以来的所有比特币参考客户端,其支付地址都是完全透明且向后兼容的。

P2WSH

以下示例是1-of-2多重签名版本0付钱证人脚本哈希(P2WSH)。

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

scriptPubKey中的’0’表示以下推送是版本0见证程序。见证程序的长度表明它是一个P2WSH类型。证人中的最后一项(“witnessScript”)被弹出,用SHA256散列,与scriptPubKey中的32字节散列相比较,并反序列化:

1
1 <pubkey1> <pubkey2> 2 CHECKMULTISIG

该脚本使用来自witness的其余数据执行:

1
0 <signature1> 1 <pubkey1> <pubkey2> 2 CHECKMULTISIG

P2WSH允许10,000字节的最大脚本大小,因为520字节的推动限制被绕过。

scriptPubKey占用34个字节,而不是23个字节的BIP16 P2SH。大小的增加提高了可能发生的碰撞攻击的安全性,因为280工作不再可行(截至2015年底,自比特币创建以来,已有284次哈希计算在比特币挖矿中)。支出脚本与等效的BIP16 P2SH输出相同,但被移至见证。

P2WSH嵌套在BIP16 P2SH中

以下示例是相同的1对2多重签名P2WSH脚本,但嵌套在BIP16 P2SH输出中。

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

scriptSig中的唯一项目与HASH160进行哈希处理,与scriptPubKey中的20字节哈希进行比较,并解释为:

1
0 <32-byte-hash>

P2WSH witnessScript然后按照前面例子中的描述执行。

与前面的例子相比,scriptPubKey小11个字节(安全性降低),而证人是相同的。但是,它也需要scriptSig中的35个字节。

可扩展的承诺结构

在coinbase交易的新承诺是witness root hash和witness reserved value的hash。在witness reserved value目前还没有达成共识的意义,但是将来会为未来的softforks允许新的承诺值。例如,如果未来需要一项新的共识批评(consensus-critical)承诺,则基础承诺将变为:

1
Double-SHA256(Witness root hash|Hash(new commitment|witness reserved value))

为了向后兼容,Hash(new commitment|witness reserved value)将会转到coinbase见证,并且witness reserved value将被记录在将来的softfork指定的另一个位置。可以通过这种方式添加任何数量的新承诺。

对比特币没有共识至关重要性的任何承诺,例如合并挖掘,都不得使用该功能witness reserved value来保留升级比特币共识协议的能力。

承诺之后的可选数据空间也为将来软叉的元数据留有余地,并且不得用于其他目的。

无信任的未确认交易依赖链

隔离见证从根本上解决了交易延展性问题,从而以无信任的方式构建未经证实的交易依赖链。

Alice和Bob两方可能会同意将一定比特币发送到2比2的多重输出(“资金交易”)。如果没有签署资金交易,他们可能会创建另一个交易,在未来时间锁定,将2比2的多重输出投入到第三个账户(“支出交易”)。Alice和Bob将签署消费交易并交换签名。在审查签名后,他们将签署资金交易并将其交易给区块链。如果没有采取进一步行动,支出交易将在锁定时间后确认,并根据原始合同发放资金。它还保留了在锁定时间之前撤销原始合同的灵活性,通过锁定时间更短的另一笔支出交易,但只有在双方达成共识的情况下。

BIP62不可能将此类设置作为延展性修复,因为如果双方首次签署资金交易,则无法创建支出交易。如果Alice在Bob之前披露资金交易签名,Bob可以无限期锁定资金,而无需签署支出交易。

未经证实的交易依赖链是更复杂的支付网络的基本组成部分,比如双工微支付渠道和闪电网络,它们有可能极大地提高比特币系统的可扩展性和效率。

未来的扩展

适用于SPV节点的紧凑型欺诈证明

比特币现在只有两种真正的安全模式。用户或者运行一个全节点来验证系统中所有规则的每个块,或者一个SPV(简单支付验证)客户端,它只验证头部作为一些交易发布的证明。比特币白皮书建议,当SPV节点检测到无效块时,可以接受来自完整节点的警报,提示SPV节点下​​载有问题的块和交易进行验证。但是,这种方法可能会成为DoS攻击媒介,因为几乎不会产生虚警。警报必须具有紧凑但确定性的欺诈证据。

在目前的比特币协议中,除了少数几个规则外,几乎所有规则都可以生成紧凑的欺诈证据:

  1. 无法证明矿工在coinbase交易输出中引入了太多比特币,而没有显示整个块本身和所有输入交易。
  2. 不可能证明违反任何块特定的约束条件,例如大小和sigop限制,而不显示整个块(以及在sigop限制情况下的所有输入交易)
  3. 如果没有从区块链上回溯到创世区块的所有交易ID,则无法证明花费了一些不存在的输入。

可以提交额外的见证数据,以允许SPV节点可以快速验证的块无效的简短证明:

  1. 交易费的总和树可以用来构建简短的证明,证明矿工不会为coinbase交易增加额外的费用。类似于块大小和sigop计数限制。
  2. 可以提供交易输入所花费输出的反向链接。这些反向链接包含块散列和瘦客户端可轻松查询和检查以验证输出是否存在的偏移量。

这些承诺可以通过软分叉包含在可扩展的承诺结构中,并且对不了解这些新规则的节点是透明的。

新的脚本系统

由于version字节在witness程序之前被推送,并且版本未知的程序总是被视为任何人可以花费的脚本,所以可以通过软分叉来引入任何新的脚本系统。作为结构的见证不受任何现有脚本语义和约束的限制,特别是520字节的推送限制,因此允许任意大的脚本和签名。

新的脚本系统的例子包括Schnorr签名,可以显着减少多重交易处理的大小,Lamport签名是量子计算阻力,Merklized抽象语法树允许非常复杂的条件脚本的非常紧凑的见证。

每个输入锁定时间(Per-input lock-time)和相对锁定时间(relative-lock-time)

目前交易中只有一个nLockTime字段,并且所有输入必须共享相同的值。BIP68使用nSequence字段启用每个输入的相对锁定时间,但锁定时间段和分辨率有限。

通过软分叉,可以引入单独的见证结构以允许每个输入的锁定时间和相对锁定时间,以及可以签署和操作新数据的新脚本系统(如BIP65和BIP112)。

向后兼容

作为一个软分叉,较旧的软件将继续无需修改即可运行。但是,未升级的节点将不会看到也不会验证证人数据,并将所有见证程序视为任何人可以花费的脚本(除了几个证据程序等于0的边缘情况,脚本必须失败)。钱包应该时刻警惕任何人可以花钱的脚本,并怀疑地对待它们。强烈建议未升级的节点升级以利用新功能。

未升级的钱包可以做什么

  1. 从未升级和升级的钱包接收比特币
  2. 使用传统P2PKH地址将比特币发送给未升级和升级的钱包(没有任何隔离见证的好处)
  3. 使用P2SH地址将比特币发送到升级的钱包
  4. 通过BIP70支付协议使用本地见证程序将比特币发送至升级的钱包

非升级的钱包不能做什么

  • 验证隔离的证人交易。它假定这样的交易总是有效的

部署

该BIP将通过名称为“segwit”的“版本位”BIP9并使用位1进行部署。

对于比特币主网络,BIP9启动时间将为2016年11月15日午夜UTC(时代邮戳时间戳1479168000),并且BIP9超时时间将为2017年11月15日午夜UTC(时代邮戳时间戳1510704000)。

对于比特币测试网,BIP9开始时间将为UTC时间2016年5月1日午夜(时间戳1462060800)和BIP9超时时间为UTC时间2017年5月1日(时间戳1493596800)。

积分

特别感谢Gregory Maxwell在本BIP和Luke-Jr中提出了许多想法,以便弄清楚如何将其作为软分叉来部署。

脚注

^ 例如,带OP_0的scriptPubKey后跟40字节的非零数据推送将由于程序大小不正确而失败。但是,带OP_0后跟41字节非零数据推送的scriptPubKey将会通过,因为它不被视为见证程序
^ 为了向后兼容,对于从0到16的任何版本字节,如果证明程序的CastToBool值为零,则脚本必须失败。然而,像这样的哈希是一个成功的对哈希函数的原像攻击,风险可以忽略不计。
^ 使用单个复合约束的原理,而不是两个单独的限制,例如1MB基础数据和3MB见证数据:使用两个单独的限制将使挖掘和费用估计几乎不可能。矿工们需要解决一个复杂的非线性优化问题,以找到在给定两个约束条件的情况下使费用最大化的一组交易,并且钱包将不能知道该支付什么,因为它取决于两个条件中的哪一个最受到实时的矿工们试图用他们的交易来生产积木。这种方法的另一个问题是闲聊。一旦一组事务处理达到基本数据1MB约束条件,通过最低限度地增加费用就可以向证人添加高达3MB的额外数据。在这种情况下,额外见证空间的边际成本实际上变为零。
^ https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2016-August/013014.html

参考实现

https://github.com/bitcoin/bitcoin/pull/8149

参考

BIP16支付脚本散列
BIP143版本0witness程序的交易签名验证
BIP144隔离见证(同伴节点服务)

版权

该文件置于公共领域。

阅读资料

bitcoin 源码解析 - 交易 Transaction(三) - Script
bips/bip-0141.mediawiki

0%