协议演进 / BIP/比特币改进提案 / BIP-30
BIP-30
一条堵漏的网络规则:区块不得包含标识符与链上更早一笔“尚未花完”的交易相同的交易,否则重组时已确认交易会被凭空覆盖。本 BIP 目前处于已激活状态。
一、档案卡
| 编号 | BIP-30 |
|---|---|
| 标题 | Duplicate transactions |
| 作者 | Pieter Wuille <[email protected]> |
| 指定日期 | 2012-02-22 |
| 层级 | Consensus (soft fork)(共识(软分叉)) |
| 类型 | Specification(规范类) |
| 状态 | Deployed(已激活) |
| 阅读版 | https://bips.dev/30 |
| 官方原文 | https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki |
二、放在哪一族
共识层(软分叉)的“堵漏”族:不引入新功能,只给已有的交易标识符(txid)唯一性补上一条原本缺失的强制规则。
它的位置要和两个相邻话题分开看:
- 与 coinbase 的关系:重复交易最容易的来源正是 coinbase——币基交易结构简单、早期高度上完全可能逐字节相同,标识符随之相同;搭在重复 coinbase 之上,普通交易也能被复制出相同标识符。BIP-34(区块 v2、coinbase 中写入高度)是另一条线上让 coinbase 天然各不相同的办法,属于“让重复难以产生”;本页走的是另一头——直接规定链不许收。
- 与重组(reorg)的关系:本页真正的保护对象不是 txid 的美观,而是重组时的账本安全(见第三节):规则要保证的“定律”,原文写在 Rationale 里,是任何方案都必须服从的前提。
同族可对照阅读的还有 BIP-16 等同年软分叉:都是“只收紧、不放宽”的规则变更。
三、它要解决什么
起因是参考实现里一个一直没被当真的假设:**它默认重复交易(标识符完全相同的交易)不存在。**原文指出这并不成立:
- coinbase 特别容易被复制出相同的;
- 一旦有了重复的 coinbase,建立在其输出之上的普通交易也可以有重复版本。
更要紧的是,已经有人描述并演示了利用这一处理方式的攻击:
- 回滚已确认交易:攻击可把一笔已完全确认的交易打回只剩一次确认的状态,进而使它有被彻底变成不可花费的风险;
- 分叉子集网络:另一种攻击可以让一部分节点眼中的区块链发生分叉。
原文在 Rationale 里把危害抽象成一条定律:可用交易输出的集合,不得因为“把若干区块加进链、再把它们移除”而改变。这正是重组(reorg)时发生的事,而当时的参考实现在临时加入的区块含有重复交易时,会违反这条定律——重复交易会覆盖掉先前同标识符交易的未花费输出,区块被重组移除后,账也回不到原样。
四、规则本身
4.1 规则一句话
区块不得包含这样的交易:其标识符与同一条链上更早的一笔交易相同,而那笔更早的交易尚未被完全花费。
换个方向读:标识符相同的新交易,只在旧的那笔已经花得一干二净时,才允许再次出现。
4.2 适用范围与历史例外
规则最初适用于时间戳在 2012 年 3 月 15 日 00:00 UTC 之后的所有区块(测试网:2012 年 2 月 20 日 00:00 UTC)。
后来经一次代码提交扩展:规则适用于全部区块,只豁免主链上两个已被“祖父条款”保留的历史违规区块——高度 91842 与 91880。除此之外,不再按时间戳划线。
4.3 为什么选这一条(三种候选方案)
原文列了三个候选,并说明了取舍:
- 保证所有 coinbase 唯一,让重复交易极难产生。这是最完整的方案,还能顺带保证标识符唯一;但它需要多处改动并要全网接受,而且防不住“建立在更早重复 coinbase 之上”的重复交易。
- 记住每个标识符此前剩下的输出,以备同标识符的新交易出现时使用。此路不通:它无法以向前兼容的方式实现,还可能让当前无效的区块变得有效。
- 只允许在前一笔已无可花费输出时重复(即 4.1 的规则)。选它,因为它只需要一个很小的改动,且重组移除区块时能安全地把被移除交易的输出复位为空。
原文还点明了 4.1 中“已完全花费才可重复”这一宽容的用意:若任何交易永远不得重复,将来做剪枝(pruning)时就必须为历史上每一笔交易永久保留证据;允许已花完的交易被重复,才不挡剪枝的路。
4.4 向后兼容性
新增规则只是让一部分原本有效的区块变为无效(单向收紧)。原文由此推论:只要绝大多数矿工执行这条规则,有规则与无规则的节点之间也不可能形成永久性分叉——这正是它被归为软分叉的原因。
五、谁必须动
全节点:验证新区块时执行 4.1 的检查——收到与链上“尚未花完”的旧交易同标识符的交易,该区块判无效。实现上还要正确处理两个被豁免的历史高度。
矿工:不得把违规的重复交易打进自己出的区块;在绝大多数算力执行规则的前提下,违规区块会被网络拒绝。
普通持币人 / 钱包:无任何操作变化,不改变地址、签名或交易构造方式。收益是间接的:已确认的交易不会因重复交易加一次重组就被凭空打回未确认状态。
共识层:这正是本页改动所在——多了一条区块有效性规则;但它只收紧不放宽,未升级节点眼中的新链仍然有效(见 4.4)。
六、现在算不算数,以及一个常见误读
状态为 Deployed,站点标注“已激活”:规则已经进入共识,并且如 4.2 所述,后来被追溯适用于全部区块(两个历史高度除外)。原文记录的实现线索是参考客户端的对应提交(“Do not allow overwriting unspent transactions (BIP 30)”),其后还有若干提交继续打磨该实现。发现并演示问题、协助测试补丁的 Russell O’Connor 在原文 Acknowledgements 中被致谢。
常见误读:
“BIP-30 规定:任何交易标识符在链上永远只能出现一次。”
不对。规则禁止的只是覆盖尚有未花费输出的旧交易。前一笔同标识符交易若已被完全花费,后来出现同标识符交易是被允许的——这是原文有意留的口子,为的是不妨碍未来的剪枝。再加上高度 91842、91880 两个被祖父条款保留的历史区块,说“txid 全局唯一、无一例外”在两个方向上都与原文不符。
七、延伸
- 阅读版:https://bips.dev/30
- 官方原文:https://github.com/bitcoin/bips/blob/master/bip-0030.mediawiki
- 相关:BIP-34 区块 v2:coinbase 中加入高度
- 仓库总目录:https://github.com/bitcoin/bips
