协议演进 / BIP/比特币改进提案 / BIP-144
BIP-144
为隔离见证定义新的 P2P 消息与序列化格式,让节点能通告、请求和中继见证数据,同时不破坏与旧节点的兼容。本 BIP 目前处于已部署状态。
一、档案卡
| 编号 | BIP-144 |
|---|---|
| 标题 | Segregated Witness (Peer Services) |
| 作者 | Eric Lombrozo <[email protected]>, Pieter Wuille <[email protected]> |
| 指定日期 | 2016-01-08 |
| 层级 | Peer Services(对等服务) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已部署) |
| 阅读版 | https://bips.dev/144 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki |
二、放在哪一族
隔离见证(SegWit)的网络传输分册。BIP-141 在共识层定义见证结构、并要求未来区块对它作出承诺;本篇补上对等服务层:节点如何对外宣告自己支持见证、如何索要和转发见证数据。
同族关系:
BIP-141:隔离见证(共识层),定义见证本身
BIP-143:v0 见证程序的签名验证规则
BIP-145:getblocktemplate 的隔离见证更新,面向挖矿接口
本篇只管“线上怎么传”,不改变任何一笔交易是否有效。
三、它要解决什么
见证数据被分离出去之后,老的 tx 与 block 消息格式装不下它。若直接改老格式,不支持见证的旧节点会解析失败甚至误判;若另起一套完全平行的消息,又会让交易、区块以及所有处理原始交易的 RPC 都要做双份。
因此需要一套新机制,同时满足三点:
- 节点能宣告自己可以提供见证数据;
- 对方能按需请求“带见证”的交易与区块;
- 旧节点完全不受影响,仍按老格式收发无见证的数据。
这正是本篇要定义的:新序列化格式、新服务位、新的库存(inv)请求类型。
四、规则本身
4.1 带见证的交易序列化
P2P 协议新增一种交易序列化,在原有字段之间插入两个字节:
- version(4 字节)之后是 marker(1 字节,必须为 0)与 flag(1 字节,必须非零);
- 随后依次是输入数量、输入列表、输出数量、输出列表;
- 再后是 script_witnesses:每个输入各有一份见证结构;
- 最后仍是 lock_time(4 字节)。
见证结构本身是一个栈:先写元素个数(var_int),再逐个写“长度(var_int)+ 字节串”。见证份数不单独编码,由输入个数推定,顺序与输入一一对应;某个输入的见证为空时,编码为一个零字节。
设计上有三个刻意的安排:
- marker 取 0,使不支持本篇的旧解析器绝不会把新格式误读成一笔合法交易(按旧格式读,它会变成“零输入、一输出”,解析不成立);
- 不能只用一个 0x00 作标记,否则“零输入零输出”的空交易(某些测试中用到)会被误判为新格式,所以中间再加 flag 字节;
- flag 可看作位向量,将来若要给交易附加更多未承诺数据,可以继续扩展。
若交易见证为空,必须使用旧序列化格式,不得用新格式。
4.2 服务位:NODE_WITNESS
节点在握手时以服务位宣告自己能提供见证:
NODE_WITNESS = (1 << 3)
4.3 两种哈希并存
用于交易默克尔树与输入 outpoint 的交易哈希,永远按不带见证的旧序列化计算——这就是后来通称的 txid。同时新增一种把见证数据算在内的哈希(即 wtxid 的口径):由新序列化计算。见证为空的交易,新旧两种哈希相等。
4.4 中继:新的 inv 类型
getdata 请求新增两种库存类型:
- MSG_WITNESS_TX(0x40000001,即 (1«30)+MSG_TX);
- MSG_WITNESS_BLOCK(0x40000002,即 (1«30)+MSG_BLOCK);
- 另预留 MSG_FILTERED_WITNESS_BLOCK(0x40000003)供将来使用。
细节规则:
- inv 公告本身仍只用 MSG_TX 与 MSG_BLOCK,不在公告里标明“有没有见证”——原文给出的理由是:现在并非总用 inv(已有 BIP-130 的 sendheaders),而且概念上每笔交易、每个区块都有见证,旧的只是见证为空而已;
- 用 MSG_WITNESS_TX 请求时,要用不带见证的哈希(txid)指名;对方以 tx 消息回应,见证非空则用新序列化发送;
- 用 MSG_WITNESS_BLOCK 请求时,对方返回的 block 消息中,带见证的交易用见证序列化。
4.5 为什么不另设消息类型
原文明确否决了“另设一套独立消息 + 独立序列化”的方案:那将要求 tx 与 block 消息各做一份,所有处理原始交易的 RPC 也要复制一份;否则就只能靠低效、不确定的猜测来判断该用哪种格式。在原消息内扩展序列化,是成本最低的路径。
五、谁必须动
普通持币人:无感。不需要改钱包,也不需要改收款方式;变化发生在节点之间的线路上。
钱包开发者:直连 P2P 网络的轻钱包需要能解析新序列化、按 txid 请求带见证的交易;通过自家节点或服务商接口同步的钱包通常不受影响。
全节点与矿工:要提供和中继见证数据,必须实现新序列化、设置 NODE_WITNESS 服务位,并响应 MSG_WITNESS_TX / MSG_WITNESS_BLOCK 请求。不升级的节点仍可正常收发无见证数据,只是拿不到见证部分。
共识层:本篇不修改共识规则。交易是否有效由 BIP-141 等共识文档决定;本篇只决定这些数据在网络上如何编码与传递。
六、现在算不算数,以及一个常见误读
状态为 Deployed(已部署)。它随隔离见证一起成为节点网络的实际传输方式:今天节点之间索要带见证的交易与区块,走的就是本篇的序列化与 inv 类型。原文的参考实现指向比特币核心的相应合并请求;各客户端的具体实现进度不在原文范围内,本页不另行断言。
常见误读:
“BIP-144 是隔离见证的激活规则。”
不对。本篇没有激活条件,也不定义见证的共识语义;它只是对等服务层的“运输规范”。激活与有效性看 BIP-141 及其部署安排,签名怎么验看 BIP-143。
七、延伸
- 阅读版:https://bips.dev/144
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0144.mediawiki
- 相关:BIP-141 隔离见证(共识层)、BIP-143 v0 见证程序的签名验证、BIP-145 getblocktemplate 的隔离见证更新
- 仓库总目录:https://github.com/bitcoin/bips
