协议演进 / BIP/比特币改进提案 / BIP-115

BIP-115 用脚本实现的通用防重放保护

新增 OP_CHECKBLOCKATHEIGHT,让交易只能在包含某个指定区块哈希的链上有效,以实现通用防重放保护。本 BIP 目前处于已关闭状态。

一、档案卡

档案卡
编号BIP-115
标题Generic anti-replay protection using Script
作者Luke Dashjr <[email protected]>
指定日期2016-09-23
层级Consensus (soft fork)(共识(软分叉))
类型Specification(规范类)
状态Closed(已关闭)
阅读版https://bips.dev/115
官方原文https://github.com/bitcoin/bips/blob/master/bip-0115.mediawiki

二、放在哪一族

脚本防重放与链分裂应对族。它和时间锁族相邻但不同:BIP-65 的 OP_CHECKLOCKTIMEVERIFY、BIP-112 的 CHECKSEQUENCEVERIFY 约束的是“什么时候能花”,BIP-115 约束的是“在哪条链上能花”——把某个具体区块的哈希钉进花费条件。

它的做法沿用了软分叉的经典手法:重定义一个 OP_NOP 占位操作码(这里是 OP_NOP5),部署方式计划用 BIP-9 的 version bits,部署名写作 “cbah”,但原文中起始时间、超时时间与 bit 位均为 TBD(待定),从未定稿。

与它同属“让脚本能检查链上既有事实”思路的,还有后来的各类内省(introspection)与契约(covenant)提案;BIP-115 是其中较早、目标非常聚焦的一个:只查一个区块高度对应的哈希,不引入通用计算。

三、它要解决什么

3.1 从双花中安全恢复

用户有时会在收款交易尚未确认时就把币花出去(Tx B1)。如果那笔收款交易(Tx A1)被双花,钱包必须改发一笔新的支出交易(Tx B2)。

若双花的版本(Tx A2)仍然付给该钱包,问题不大:换掉输入指向、重新签名即可。但若 Tx A2 根本不付给该钱包,钱包只能在 Tx B2 里改花别的、不冲突的 UTXO——攻击者随后可以重组链、把 Tx A1 的双花再翻回来,使 Tx B1 与 Tx B2 两笔同时确认,钱包被坑两次。

有了 OP_CHECKBLOCKATHEIGHT,钱包发 Tx B2 时可以附加条件:确认 Tx A2 的那个区块必须在本链历史中。这样重组翻转后 Tx B2 自动失效,风险被消除。

3.2 持久链分裂时的防重放

当区块链发生持久分裂,两条链上存在大量共同的 UTXO。用户在一条链上的正常花费,可能被原样搬到另一条链上重放。

解决办法是:选一个只存在于某一条链一侧的区块,把共同 UTXO 的花费“钉”在包含该区块的链上——用 OP_CHECKBLOCKATHEIGHT 检查该区块哈希。另一条链没有这个区块哈希,交易在那边必然无效,重放被挡住。

四、规则本身

4.1 OP_CHECKBLOCKATHEIGHT 的执行规则

该操作码重定义 OP_NOP5。执行时从栈上取两项:栈顶为区块高度(ParamHeight),次顶为区块哈希(ParamBlockHash)。规则依次为:

全部通过时,执行效果等同于执行了一个 NOP。

4.2 为什么高度必须是绝对值

原文特意不用相对高度:相对高度会造出“在第 N 块有效、N+1 块无效”的交易。比特币刻意避免这种交易,因为区块被重组掉时,无恶意的交易应当能简单地在后续区块重新确认。

4.3 为什么只查最近 52596 个区块

更深的区块一律放行,是为了避免全节点无限保存全部区块头:52596 个区块头约占固定 4 MB。原文的假设是:一年时间足够在所有相关链上双花掉共同 UTXO;真需要更深的检查,还可以再软分叉加深,而把检查变浅则需要硬分叉。

4.4 为什么哈希可以只给一部分

链分裂时防重放只需几个字节就够;现实场景中检查完整哈希的少数几个字节,也足以排除重放。允许截短还能省交易数据空间。原文还提醒:ParamBlockHash 若带前导零,要按原样与真实哈希比较;钱包的常规做法是给 16 字节。

4.5 钱包最佳实践

原文给钱包三条建议:条件允许时避开最近 100 个区块(防重组冲突);不得不用近期区块时,应主动监听网络,在交易被重组掉后用更新后的区块哈希重造交易;除非与本地安全策略冲突,应把私钥留在内存中以便重签,直到所钉区块在链中深度达到 100 块以上。

五、谁必须动

普通持币人:无直接动作。只有在链分裂或未确认收款被双花这类特殊场景里,钱包才可能替你使用这种条件。

钱包开发者:若要支持,需按 4.5 的最佳实践构造条件、监听重组并重签;常规 ParamBlockHash 取 16 字节。

全节点与矿工:这是共识层软分叉。矿工必须升级,否则可能接受并在无效区块上继续挖矿;旧节点大概率也不会转发使用该操作码的交易。

共识层:变的是 OP_NOP5 的语义:旧规则下只是空操作,新规则下多了一道“指定区块必须在本链历史中”的校验,规则只收紧、不放松。

六、现在算不算数,以及一个常见误读

状态为 Closed(已关闭)。部署参数在原文中始终是 TBD,该操作码没有在比特币主网上激活,OP_NOP5 至今仍只是保留的空操作。它留下的价值是把“用区块哈希把交易钉在一条链上”这一防重放思路写成了完整的脚本级规范。

常见误读:“链一分裂,靠 BIP-115 就能自动防重放。”不对。它从未激活;而且即便激活,防重放也不是自动的——必须由钱包主动为花费交易附加钉住某个分叉后区块的条件,没有附加条件的普通交易在两条链上照样都能被重放。

七、延伸

本页内容整理自 bitcoin/bips 仓库与 bips.dev,事实已与仓库核对;解读仅供学习参考。