协议演进 / BIP/比特币改进提案 / BIP-141
BIP-141
把签名等见证数据从交易本体分离、单独构成 witness 结构并承诺进区块,使 txid 不再包含签名,并以区块权重取代原 1MB 区块大小上限。本 BIP 目前处于已激活状态。
一、档案卡
| 编号 | BIP-141 |
|---|---|
| 标题 | Segregated Witness (Consensus layer) |
| 作者 | Eric Lombrozo <[email protected]>, Johnson Lau <[email protected]>, Pieter Wuille <[email protected]> |
| 指定日期 | 2015-12-21 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已激活) |
| 阅读版 | https://bips.dev/141 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki |
二、放在哪一族
SegWit 家族的总纲,共识层这一份。本 BIP 只定共识规则,同族的其他文档各管一段,读本篇时应把它们当作配套件:
BIP-143:版本 0 见证程序的签名验证新摘要算法。本 BIP 多处指明,P2WPKH 与 P2WSH 的签名校验细节以 BIP-143 为准,包括只接受压缩公钥等限制。
BIP-144:隔离见证(对等服务)。含见证数据的交易与区块如何序列化、如何在节点间传输,本 BIP 的总大小与交易权重定义都引用它的序列化。
BIP-173:原生 v0–16 见证输出的 Base32 地址格式。本 BIP 参考文献所列的地址出口;本族另有 BIP-142 曾提出 Base58 方案,现已关闭。
BIP-16:P2SH。见证程序可以原生出现,也可以嵌套进 P2SH 输出出现,两种触发方式都写在本 BIP 里。
再往前看问题来源:BIP-62 用规范签名处理可塑性。本 BIP 在动机里逐条比较后认为,把签名移出交易哈希是比规范签名路线更彻底的解法。理解本族,先分清三层:共识(本篇)、签名摘要(143)、网络传输(144),不要把三份的规则混在一起。
三、它要解决什么
出发点是一个区分:交易的全部效果由什么决定?原文的回答是:由输出的消耗(花费)与新输出的创建决定。其他交易数据、尤其是签名,只用于验证区块链状态是否合法,不用于决定状态本身。
既然签名不决定效果,把它从被交易默克尔树承诺的交易结构里移出去,可以同时修好几件事。原文列了三组:
3.1 非自愿可塑性变得不可能
签名数据不再是交易哈希的一部分,签名方式怎么变,都不再影响交易标识。原文逐条对照规范签名路线(BIP-62)的优势:
- 只要全部输入都至少带一次 CHECKSIG 或 CHECKMULTISIG 类签名,任何脚本类型都不会被非自愿延展;
- m-of-n 多签情形下,一笔交易要被延展需要 m 个私钥持有人同意,而不是 BIP-62 下的 1 个;
- 未知 ECDSA 签名可塑性也不会再造成非自愿延展;
- 可以无对手方风险地构造未确认交易依赖链,这是闪电网络等链下协议的重要前提。
3.2 签名传输变为可选
见证数据只在对等节点要验证交易时才需要,只查交易是否存在时可以不传。这减小了 SPV 证明的体积,同样带宽下 SPV 客户端能下载更多交易,对其隐私也可能有改善。
3.3 为软分叉留出绕开旧约束的通道
把部分交易数据移到当前协议不认识的新结构里,一些约束可以用软分叉重新处理。原文举例:
- 计算区块大小时可忽略或折扣见证大小,实际上把区块容量放大一些;
- 硬编码常量,如最大数据推送 520 字节、sigops 上限,可以重新评估或去掉;
- 可以引入不受既有脚本语义限制的新脚本系统,例如 BIP-143 的新签名摘要算法就是这样引入的。
四、规则本身
4.1 两个 ID:txid 与 wtxid
新结构名为 witness。每笔交易从此有 2 个 ID:
txid 定义不变,仍是传统序列化 [nVersion][txins][txouts][nLockTime] 的双重 SHA256,不含见证。
wtxid 是新序列化 [nVersion][marker][flag][txins][txouts][witness][nLockTime] 的双重 SHA256。其中 marker 必须为 1 字节 0x00,flag 必须为 1 字节非零值,现规定用 0x01。
witness 是全部输入的见证字段的序列化:每个输入对应一个见证字段,先以 var_int 给出该输入的栈元素个数,随后逐个给出带 var_int 长度前缀的栈元素。见证数据不是脚本。非见证程序输入必须带空见证字段,记为 0x00;若全部输入都不是见证程序,该交易的 wtxid 等于其 txid。
4.2 承诺结构:见证怎样进区块
新区块规则要求对 wtxid 作承诺。coinbase 交易的 wtxid 假定为全零。
先以全部 wtxid 为叶子、按与区块头默克尔根相似的方式算出 witness root hash;承诺记在 coinbase 交易的一个 scriptPubKey 中:它至少 38 字节,前 6 字节为 0x6a24aa21a9ed——即 OP_RETURN、推送其后 36 字节、4 字节承诺头 0xaa21a9ed——随后 32 字节承诺哈希,等于双重 SHA256(witness root hash 与 witness reserved value 的拼接)。第 39 字节起为可选数据,无共识含义。
coinbase 输入的见证必须恰由一个 32 字节数组构成,即 witness reserved value。若有多个 scriptPubKey 符合该模式,取输出索引最高的一个为承诺。若区块内全部交易都没有见证数据,该承诺可有可无。
这套承诺嵌进既有默克尔根经 coinbase 交易完成,正是为了软分叉兼容;原文说将来的硬分叉可以把这棵树放进它自己的分支。reserved value 与承诺后的可选空间都是给未来软分叉预留的扩展位,非共识关键的承诺(如合并挖矿)不得占用 reserved value。
4.3 见证程序
一个 scriptPubKey(或 P2SH 的 redeemScript)若恰由“1 字节版本推送操作码(OP_0 到 OP_16)加一段 2 到 40 字节的直接数据推送”构成,就获得新含义:第一个推送的值叫版本字节,其后推送的字节向量叫见证程序。
触发验证逻辑有两种情形:
- 原生见证程序:scriptPubKey 本身就是版本字节加见证程序,scriptSig 必须恰为空;
- P2SH 见证程序:scriptPubKey 是 P2SH 脚本,scriptSig 中推入的 redeemScript 恰为版本字节加见证程序,scriptSig 必须恰为该 redeemScript 的一次推送。
版本字节为 0 且程序为 20 字节时,解释为 P2WPKH:见证必须恰有 2 个元素(各不超过 520 字节),依次为签名与公钥,公钥的 HASH160 必须等于这 20 字节程序,最后按 CHECKSIG 验签并以栈上单个 TRUE 收尾。相比传统 P2PKH,其 scriptPubKey 少 3 字节,签名与公钥从 scriptSig 移入见证。
版本字节为 0 且程序为 32 字节时,解释为 P2WSH:见证最后一项是序列化脚本 witnessScript,其 SHA256 必须等于这 32 字节程序;witnessScript 不超过 10000 字节,取出后用剩余见证栈执行,每栈元素仍受 520 字节之限,脚本不得失败且以单个 TRUE 收尾。这等于把 P2SH 的花费脚本移进见证,并绕开了 520 字节推送上限,脚本总长上限放大到 10000 字节。
版本字节为 0 但程序既非 20 也非 32 字节,脚本必须失败。版本字节为 1 到 16 时,不对见证程序与见证栈作进一步解释,见证栈也无大小限制,留作未来扩展;原文的可扩展性一节正是由此展开:未知版本一律按任何人可花费处理,因而任何新脚本系统都能以软分叉借新版本引入。
嵌套进 P2SH 的写法同样有例:P2WPKH 嵌套时 scriptPubKey 是普通 P2SH 形式,地址对旧钱包完全透明、自 0.6.0 起的参考客户端都兼容,代价是 scriptPubKey 多 1 字节、scriptSig 多 23 字节;P2WSH 嵌套则 scriptPubKey 小 11 字节(哈希由 32 字节降为 20 字节,安全性随之降低),另需 35 字节 scriptSig。
4.4 区块权重与 sigops
区块大小上限从 1000000 字节改为复合约束:
区块权重 = 基础大小乘 3 加总大小,上限 4000000。其中基础大小是去掉一切见证相关数据的旧序列化体积,总大小是按 BIP-144 序列化(含基础与见证)的体积。
原文注脚解释了为何用单一复合约束而不设“1MB 基础加 3MB 见证”双上限:双上限会让矿工选交易与钱包估费都变成复杂的非线性问题,且基础塞满后见证空间的边际成本会趋近于零,产生搭便车。
交易层面同理:交易权重等于基础交易大小乘 3 加总交易大小,虚拟交易大小等于交易权重除以 4 并向上取整。
Sigops 上限同步调整:既有公钥脚本、签名脚本、P2SH 检查脚本中的 sigops 按 4 倍计数,区块上限也翻 4 倍至 80000。每个 P2WPKH 输入计 1 个 sigop;P2WSH 的 witnessScript 内操作码按其在 P2SH redeemScript 中的旧计数法计,CHECKSIG 计 1,CHECKMULTISIG 按其前 OP_1 到 OP_16 计 1 到 16、无此前缀计 20。此规则对原生与 P2SH 两种见证程序都适用。
4.5 新脚本语义的三条策略提醒
版本 0 见证程序的签名摘要算法由 BIP-143 另定,与旧脚本貌似相同而细节不同,原文警告不得假定旧脚本可直接搬作 P2WPKH 或 P2WSH 花费。
首个参考实现(0.13.1)还附带三条转发与挖矿策略,原文要求用户认真遵守,以免在以这些策略为基础的潜在软分叉中出现确认无限延迟或资金永久丢失:
- P2WPKH 与 P2WSH 只接受压缩公钥;
- P2WSH 中 OP_IF 与 OP_NOTIF 的参数必须为最小形式;
- OP_CHECKSIG 或 OP_CHECKMULTISIG 失败时,签名必须为空向量——此条对隔离见证之前的脚本与 P2WSH 都适用,见 BIP-146。
无须信任的未确认依赖链是原文用整节示例说明的落点:双方先不签资金交易,就能先造出并互签一笔花费其 2-of-2 多签输出的后续交易,核验无误后再签并上链资金交易。这种构造在 BIP-62 路线下做不到,因为不先收齐资金交易签名就造不出后续交易,先交签名的一方可能被对方无限期锁住资金。
五、谁必须动
普通持币人:不必改动共识设置。是否用 SegWit 输出取决于钱包;原文列明未升级钱包仍可与升级钱包互收互付,只是用传统 P2PKH 地址时享受不到 SegWit 的好处,向升级钱包付款可用 P2SH 地址或经 BIP-70 支付协议使用原生见证程序。
钱包开发者:必须动才能造与认 SegWit 输出。要构造版本字节加见证程序的 scriptPubKey、把签名与公钥放进见证而非 scriptSig、遵守压缩公钥等新语义,并对任何人可花费脚本保持警惕。
全节点与矿工:升级节点才能看见并验证见证数据、按区块权重组块;矿工还要在 coinbase 中写入见证承诺。未升级节点不会看到也不验证见证,会把见证程序一律当作任何人可花费脚本(程序等于 0 等少数边缘情形须失败除外)。
共识层:本 BIP 本身即共识层软分叉。原文部署一节规定用 BIP-9 version bits 部署,名称 segwit、用 bit 1,并给出主网与测试网各自的 starttime 与 timeout(主网 starttime 为 2016 年 11 月 15 日零时 UTC、timeout 为 2017 年 11 月 15 日零时 UTC;测试网分别为 2016 年 5 月 1 日与 2017 年 5 月 1 日零时 UTC)。
六、现在算不算数,以及一个常见误读
状态为 Deployed,索引中文状态标为已激活。它是比特币现行共识的一部分:wtxid、见证承诺、见证程序与区块权重都是今天验证区块时真实执行的规则。向后兼容一节同时提醒软分叉的另一面:旧软件无须修改仍可运行,但它不验证见证、默认 SegWit 交易恒为有效,因此原文强烈鼓励未升级节点升级,以获得新功能与完整验证。
原文展望的后续也已写在正文里:见证结构可经软分叉再加承诺以支持 SPV 的紧凑欺诈证明;新脚本系统可借新版本字节引入,原文举的例子包括 Schnorr 签名、抗量子计算的 Lamport 签名与默克尔化抽象语法树;每输入锁定时间与相对锁定时间也可借新的见证结构引入。这些在原文中是“将来可做”的清单,本页不把它们说成已经实现。
常见误读:
“SegWit 是把区块从 1MB 改成 4MB 的扩容分叉。”
不对。它改的是计量方式:新规是区块权重不超过 4000000,基础数据按 3 倍折算、见证数据按 1 倍计入,总字节数取决于交易构成,并不存在一个统一的 4MB 上限。把它只读成扩容,也会漏掉它真正的主业——txid 不再含签名、可塑性修复与见证程序这套新脚本入口。
七、延伸
- 阅读版:https://bips.dev/141
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0141.mediawiki
- 相关:BIP-143 版本 0 见证程序签名验证、BIP-144 隔离见证(对等服务)、BIP-173 原生见证地址格式、BIP-142 隔离见证地址格式(已关闭)、BIP-16 P2SH
- 仓库总目录:https://github.com/bitcoin/bips
