案例分析 | 描述 |
BIP65:检查锁定时间验证 | OP_NOP1 到 OP_NOP10 在比特币脚本语言来说原本没有意义。虽然它们被算为一个操作(脚本中有 201 个操作数量限制),但实际上它们在交易验证时被忽略。然而,自 0.10 版本开始,比特币核心中就包含了一个策略规则,在默认情况下拒绝 OP_NOPx 。 BIP65 是比特币核心 0.12 中引入的软分叉,其将 OP_NOP2 重新定义为 OP_CHECKLOCKTIMEVERIFY( OP_CLTV ) 。 OP_CLTV 检查顶层堆栈值是否大于交易的 nLockTime 字段(以及其他的条件)。如果任何条件匹配,交易将被视为无效。否则, OP_CLTV 将像 OP_NOP2 一样被忽略。
新的节点在软分叉激活后将强制执行的新的共识规则。即使在激活激活之前,原来的 OP_NOP2 策略规则已被 OP_CLTV 规则取代。(这是没问题的,因为 OP_CLTV 规则比原来的 OP_NOP2 共识规则更严格)
旧的采矿节点不会执行 nLockTime 检查。但是,只要运行 0.10 或更高版本,默认的 OP_NOP2 策略规则将阻止它们包含任何具有 OP_CLTV 的交易,无论该交易是有效或无效的。因此,对于新的 OP_CLTV 共识规则, 0.10 或以上的旧采矿节点不会主动产出无效区块。
|
BIP68:使用序列号的相对锁定时间 | nSequence 是比特币交易中的一个领域,基本上没有被使用。 BIP68 的概念是使用 nSequence 字段来实现相对锁定时间,这是支付渠道和闪电网络等高级交易的一个非常重要的组成部分。然而,自比特币的第一个版本以来, nSequence 字段就一直被忽略,矿工对任何 nSequence 值的交易都采取接受态度。没有关于 nSequence 值的政策规则,因此不能像 OP_CLTV 那样简单地完成一个安全的软分叉。
诀窍是使用交易版本字段( nVersion )。从版本 0.7 开始,非版本 -1 交易将被政策规则拒绝。为了充分利用这一点, BIP68 要求仅在交易版本为 2 或更高(准确来说低于 0 )的情况下强制执行 nSequence 的新规则。因此,旧的采矿节点不会产出任何违反 BIP68 的区块,因为在默认情况下它们将不包括任何非版本 -1 交易。
攻击者不能通过简单地改变交易版本来“关闭” BIP68 ,因为版本有签名认证。这也是交易版本与共识规则相关联的唯一实例。
|
BIP141:隔离见证 | 隔离见证( segwit )是通过重新定义特定的脚本模式来修复交易可规模化的一种软分叉。 BIP141 的模式是一个以单个 OP_x(x = 0到16)开始的输出脚本(或P2SH redeemscript ),接着是 2 到 40 个字节之间的规范数据推送。但是,这不是最初提出的方案。在第一稿中,见证程序模式是在 2 到 41 个字节之间进行单次推送。
自 v0.6 版本以来已经实施该政策,用来拒绝非常规的脚本(即不是 P2PKH , P2SH 和其他几种类型)的交易。在这方面,第一份见证计划模式草案确实是不规范的。
问题是用 P2SH 编程的见证程序。在 v0.10 之前,政策规则也会拒绝任非常规的 P2SH 脚本。而这个规则在 v0.10 中大大放松了,原来的见证程序设计没有被覆盖。
几个备选方案也在当时的考虑范围:
- 新的交易 nVersion (如 BIP68 )不起作用。如果新的共识规则是“只有当 nVersion 大于 2 时才执行 segwit 规则”,则攻击者可以通过改变 nVersion 来窃取存储在 segwit 输出中的所有加密货币(因为 nVersion 仅由 segwit 签名认证,而当 nVersion 是 2 以下时是不被检查的)。
- OP_NOPx 可以被用来标识见证程序。但是,这会使所有见证程序多出 1 个字节,并占用有限的 OP_NOPx 空间。
最终版本使用了 BIP62 的所谓 “clean stack” 政策规则。虽然 BIP62 现在被撤回了,但其规则仍作为政策被执行。 “Clean stack” 要求脚本评估必须以唯一一个堆栈项目结束。然而,最后的见证程序设计留下了两个堆栈。这基本上是没问题的,但却违反了 “clean stack” 政策。
|
失败案例:BIP16和支付脚本散列
(P2SH)
| BIP16 是第一个计划实行比特币软分叉的。当 55% 的哈希算力表示准备就绪时(当前使用率约 80% 到 95% ),它被激活了。在引入 P2SH 之前,没有政策规定来检查支出输出的形式。因此,相当数量的矿工在软分叉激活数月之后一直在产出无效区块,偶尔会产出长区块链。 |
失败案例:莱特币的隔离见证 | 比特币隔离见证实施后不久,莱特币就开始整合 segwit 的代码。然而,尽管 segwit 在 Bitcoin Core 0.13.1 中发布,但当时的最后一个莱特币版本是 0.10.4 ,其中没有包含 “clean stack” 规则。 莱特币的开发员试图通过给 segwit 增加一个额外的共识规则来解决这个问题,要求区块版本必须至少为 0x20000000 ,希望能强迫矿工升级。事实证明,所有的矿工在激活之前都升级了(最后一个大型矿工在激活几个小时前升级),而并没有造成分叉因为上一个版本中没有 CLEANSTACK 。
如果大型采矿池在最后一分钟没有升级,那么额外的区块版本规则就只能提供很少的保护。这将在下一篇文章中进一步讨论。
|