协议演进 / BIP/比特币改进提案 / BIP-337
BIP-337
提出一套交易压缩序列化,利用字段的有限取值、紧凑整数与公钥恢复,把典型交易压到原大小的一半以下。本 BIP 目前处于草案状态。
一、档案卡
| 编号 | BIP-337 |
|---|---|
| 标题 | Compressed Transactions |
| 作者 | Tom Briar <[email protected]> |
| 指定日期 | 2024-02-01 |
| 层级 | API/RPC(接口) |
| 类型 | Specification(规范类) |
| 状态 | Draft(草案) |
| 阅读版 | https://bips.dev/337 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0337.mediawiki |
二、放在哪一族
交易序列化与接口族。本篇被归在 API/RPC 层,参考实现落成的也是两个新的 RPC 端点,而不是新的共识规则或 P2P 消息:它定义的是一种在软件之间搬运交易时可用的紧凑编码,解压后必须还原出原来那笔逐字节的标准交易。
它与既有交易形态的关系是“编码层”的关系:被压缩的对象仍然是普通的比特币交易,涵盖 P2PK、P2PKH、P2SH、P2WPKH、P2WSH、P2TR 等脚本类型,原文的测试向量就分别给出了 Taproot、P2WPKH、P2SH-P2WPKH 与 P2PKH 交易压缩前后的对照。
原文提到的一个应用背景是:已有一个进行中的 app,用隐写术把数据编码进图片、经各类社交媒体群组传递;配合本压缩方案与 elligator squared 加密,可以构造一种非常安全、私密的交易广播方式。本篇本体只定压缩方案,不规范隐写或广播渠道本身。
三、它要解决什么
典型的比特币交易里有大量“空白与填充”:许多字段实际上只取少数几个可能值中的一个,却都按完整的 32 位或固定长度存放。原文主张,利用这一事实与若干类似手法,可以为约 90% 的比特币交易构造一种编码,使其大小约为原来的 25%–50%。
压缩后的交易序列化大小可降到原交易的一半以下。其中一种手法——压缩交易的输出点(outpoint)——在原文表述中,是一种“可能有损”(potentially lossy)的途径,因此被设为可选路径;但要让压缩交易降到原大小的 70% 以下,压缩输出点又是必要的。
四、规则本身
4.1 四种主要手法
原文列出的四种主要压缩方法是:
- 在交易数据之前、以及每个输入与输出之前打包元数据,用元数据决定后续数据结构如何解读;
- 把 32 位数值换成变长整数(VarInt)或紧凑整数(CompactSize)编码;
- 使用压缩后的签名,并在解压时做公钥恢复;
- 把 36 字节的输出点(txid/vout 对)替换为区块高度与索引。
4.2 基本原语
- CompactSize(1–5 字节):0–253 直接用一个字节;254–65535 用 254 加两个小端字节;65536 到 2^32−1 用 255 加四个小端字节。
- CompactSize Flag(2 位):取值 1、2、3 表示字面值;0 表示随后会跟一个 CompactSize 编码的数值。
- VarInt(1 字节以上):7 位小端编码,每字节装 7 位,最高位为 1 表示后面还有字节,为 0 表示最后一字节。
- VLP-Bytestream(2 字节以上):带 VarInt 长度前缀的字节流,先用 VarInt 给出长度,再跟相应长度的数据。
4.3 总体结构与交易元数据
一笔压缩交易依次由:1 字节交易元数据、按元数据决定是否出现的版本/输入计数/输出计数/LockTime(各为 CompactSize 编码)、可选的最低区块高度(VarInt)、全部输入与输出的元数据、输入数据、输出数据组成。
交易元数据这 1 个字节按位拆分:版本占 2 位(CompactSize 标志)、输入计数占 2 位、输出计数占 2 位、LockTime 占 1 位(是否有 LockTime)、最低区块高度占 1 位(是否大于零)。最低区块高度用于压缩输入与 LockTime 的基准。
4.4 输入、输出的元数据与数据
每个输入的元数据包含:签名是否压缩(1 位,仅 P2TR 的密钥路径花费与被包装的 P2SH-P2WPKH 可压缩签名)、签名哈希类型是否标准(1 位,Taproot 的标准值为 0x00,传统/SegWit 为 0x01)、序列号的 CompactSize 标志(2 位,字面值映射为:1 表示 0x00000000,2 表示 0xFFFFFFFE,3 表示 0xFFFFFFFF)、输出点是否压缩(1 位)。
每个输出的元数据是 3 位的脚本类型编码:000 自定义脚本(不压缩)、001 未压缩 P2PK、010 压缩 P2PK、011 P2PKH、100 P2SH、101 P2WPKH、110 P2WSH、111 P2TR。
输入数据部分包括:输出点(压缩时只写“距最低区块高度的偏移”与“该高度下被压平的索引”两个 VarInt,未压缩时写 32 字节 txid 加 CompactSize 编码的 vout)、签名(压缩时为 64 字节签名,P2SH-P2WPKH 还附 20 字节公钥哈希,非标准时附 1 字节哈希类型;未压缩时为带长度前缀的字节流)、以及非标准序列号才出现的 VarInt 序列号。
输出数据部分包括:输出脚本(带长度前缀的字节流)与金额(VarInt)。
4.5 理想交易与预期收益
该方案是为“典型”交易优化的:花费少数几个年龄相近的输入、带一两个输出。原文的表格给出这种交易在各字段上的最高节省量,例如:版本、输入计数、输出计数、LockTime 若满足小取值条件,各可省至多 30 位;序列号取常见值时每个输入可省至多 62 位;压缩输出点时每个输入的 txid 可省 23–31 字节;非自定义脚本的签名每个传统输入可省 40–72 字节;输出脚本每个输出可省 2–5 字节,等等。
4.6 接口与测试向量
参考实现新增两个 RPC 端点:compressrawtransaction 接收十六进制编码的原始交易,返回紧凑的十六进制交易,并附一份警告列表,帮助确认没有出现意料之外的未压缩值;decompressrawtransaction 接收紧凑的十六进制交易,返回解压后的原始交易。参考实现指向原文所列的 Bitcoin Core 合并请求。测试向量部分给出四类交易(Taproot、P2WPKH、P2SH-P2WPKH、P2PKH)各自未压缩与压缩后的完整十六进制串,供实现者对拍。
向后兼容方面,原文明确称没有向后兼容方面的顾虑。
五、谁必须动
普通持币人:通常无感。它是一种可选的编码,只在某个工具或应用选择使用时,才在该环节内出现;链上的交易格式不变。
钱包开发者:若想在存储、传输或特殊广播场景中用压缩编码,需实现编解码器,并注意压缩输出点是可选且可能有损的路径,以及签名压缩只适用于原文列明的输入类型。是否启用、启用哪些路径,由应用自己决定。
全节点与矿工:无事可做。解压还原出的仍是标准交易,验证与打包规则不变;RPC 端点是参考实现给出的接口形态,不是节点必须提供的服务。
共识层:不涉及。本篇不改变交易的合法性定义,不进共识、不进区块。
六、现在算不算数,以及一个常见误读
状态为 Draft(草案)。这套压缩序列化仍是提案阶段的规范,草案状态意味着它尚未成为被普遍实现的标准接口;原文除参考实现外没有给出其他实现的采用情况,本页不臆测。
常见误读:
“BIP-337 能把区块或链上交易本身变小一半。”
不对。它压缩的是交易在接口、存储或带外传输环节中的序列化表示,解压必须还原为原始标准交易才能被网络接受;区块大小、链上数据格式与共识规则都没有因此改变。原文的“原大小一半以下”指的是压缩编码与原序列化相比,不是链上足迹打折。
七、延伸
- 阅读版:https://bips.dev/337
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0337.mediawiki
- 相关:本篇的参考实现与讨论见原文所列的 Bitcoin Core 合并请求(PR 29134)
- 仓库总目录:https://github.com/bitcoin/bips
