作者:Kalle Rosenbaum & Linnéa Rosenbaum

想要安全地给比特币升级,是极度困难的。这样的变更(即使内容是确定的,也)要许多年才能推出。在这一章,我们会了解围绕比特币升级的常见词汇,并了解历史上的几个升级案例,以及我们能够从中学到的教训。最后,我们要讨论 “区块链链分裂” 以及相关的成本和风险。
想要更好地理解本章的内容,你应该先从 David Harding 论 “和谐与不和谐” 的文章开始:
比特币的专家们经常把 “共识(consensus)” 这个词挂在嘴上,这个意思比较抽象,难以一两句话说清楚。但 “consensus” 的词源是拉丁语 “concentus”,意思是 “和谐地合唱”【1】,所以,我们可以先不讨论 “比特币的共识”,而讨论 “比特币的和谐”。
和谐是让比特币得以运作的东西。数千个全节点,各自独立地工作:验证自己收到的交易是有效的,从而产生出关于比特币账本状态的一个和谐的一致意见,并且无需任何一个节点运营者信任另一个运营者。它就类似于一个合唱团,每个成员都在同一时间唱同一首歌,从而产生比任何一个成员单独歌唱要更加美妙的歌曲。
比特币的和谐的结果是一套系统,在其中,比特币是安全的,不仅能抵抗小偷(只要你保管好了自己的私钥),还能抵御无止境的通胀、大规模的以及有针对性地没收,还能脱离传统金融系统这样地官僚主义泥潭。
—— David Harding,《和谐与不和谐》
本章要讨论地是,比特币如何能够升级而不造成不和谐。保持和谐,也即维持共识,实际上是比特币开发过程中最大的挑战之一。升级的机制有许多细节,最好是通过研究以往升级的实际案例来理解。出于这个理由,本节在历史案例上花费了许多篇幅;为此,我们要从了解一些有用的词汇开始。
5.1 词语
根据维基百科(Wikipedia),“向前兼容性(forward compatibility )” 指的是旧的软件也能处理更新的软件所产生的数据、忽略其不能理解的部分。
如果使用较早的版本编译出来的产品,可以 “优雅地” 处理为同一标准的后续版本而设计的输入、忽略掉其不能理解的部分,我们就说该标准支持 “前向兼容性”。
—— 向前兼容性,维基百科
反之,“向后兼容性(backward compatibility )”,则是指来自旧软件的数据在更新的软件上也可用。如果一项变更既是向前兼容的,又是向后兼容的,我们就说这项变更是 “完全兼容的”。
如果一项对比特币共识规则的变更是完全兼容的,我们就说它是一个 “软分叉”。这是升级比特币最常见的方式,这其中的许多理由,我们会在本章后续小节中探讨。如果一项对比特币共识规则的变更至向后兼容的,但不是向前兼容的,我们就叫它 “硬分叉”。
关于软分叉和硬分叉的技术概述,请阅读《Grokking Bitcoin》的第十一章。该章节解释了这些属术语,也深入讲解了升级的机制。笔者推荐读者在往下阅读之前,先浏览一下该章节,虽然这不是严格必要的。
5.2 历史上的升级
今天的比特币(协议)与它在第一个区块产生时是不一样的。这些年陆续发生了多次升级。在 2017 年,Eric Lombrozo 在 Breaking Bitcoin 大会上讲解比特币的不同升级机制时,指出这些升级机制也发生了许多变化。他甚至解释了中本聪有一次如何通过硬分叉来升级比特币。
实际上,中本聪真的用过一次硬分叉来升级比特币 —— 我们绝不会再这样做了,因为这是一种非常糟糕的办法。看这个 git 提交描述【757f076】,他说这个提交是为了回滚 makefile.unix wx-config,使用版本号 0.3.6 。没了,就是这些。他完全没有说这是一次破坏性变更。他基本上就是把它藏起来了。他也在 bitcoin talk 论坛上发帖,呼吁所有用户尽快升级到 0.3.6 版本;如果你不能立即升级,那么最好是先关闭自己的比特币节点。基于上述信息,我不知道他为什么要这样做 —— 他同时决定在同一段代码中加入一些优化,修复 Bug 和添加一些优化。
—— Eric Lombrozo,《改变共识规则而不破坏比特币》,Breaking Bitcoin 大会(2017)
Lombrozo 还指出,不论是有意还是无意的,这次硬分叉也为未来的软分叉创造了机会,因为它引入了脚本操作码(opcode)OP_NOP1 ~ OP_NOP10 。我们会在章节 9.2.1 中更多了解这次代码变更。到目前为止,这些操作码已经被用于两次软分叉:BIP65(OP_CHECKLOCKTIMEVERIFY)和 BIP113(OP_SEQUENCEVERIFY)。(译者注:两者分别是在脚本中验证绝对时间锁和相对时间锁。)
Lombrozo 还简要介绍了升级机制在这些年中的变化(截至 2017 年)。在此之后,只有一次主要升级 “Taproot” 得到部署(详见章节 5.2.3)。这个漫长而且有些混论的激活过程,帮助我们获得了对于比特币升级机制的更多洞见。
5.2.1 “隔离见证” 升级
虽然 “隔离见证(Segwit)” 升级以前的所有升级,或多或少都可以说是没有痛苦的,但它就不同了。在隔离见证激活代码发布的时候(2016 年 10 月),似乎比特币的用户中的压倒性多数都支持它,但出于一些理由,矿工们并没有表示对这次升级的支持,这导致激活停滞了,而且看起来没有解决办法。
Aaron van Wirdum 在他发表在 Bitcoin Magazine 网站的文章《走向隔离见证的长路》中描述了这道一波三折的路程。他首先解释了 “隔离见证” 升级是什么、它如何卷进了关于变更比特币区块体积限制的争论。然后,Van Wirdum 列举了最终导致它激活的转折性事件。其中的关键是一种叫做 “用户激活软分叉(UASF)” 的升级机制,是由用户 “Schaolinfry” 提出的。
Shaolinfry 提出了一种替代选择:用户激活的软分叉(UASF)。它不是让哈希算力来表态,而是设计一个 “‘激活信号日’,让用户从预定的未来时间点开始强制执行”。只要这样的一次 UASF 被大多数经济主体强制执行,应该就能说服多数矿工遵循(或者说激活)软分叉。
—— Aaron van Wirdum,《走向隔离见证的长路》,Bitcoin Magazine(2017)
此外,Van Wirdum 还引用了 Shaolinfry 发布在 Bitcoin-dev 邮件组中的邮件。在那里,Shaolinfry 表示反对矿工激活的软分叉,并列举了这种激活方式的许多问题。
首先,它要求信任哈希算力会在激活之后诚实地验证。但在 BIP66 软分叉中,明明有 95% 的哈希算力表示已经就绪,实际上却有大约半数并没有真正验证升级后的规则、错误地挖出了一个无效的区块【1】。
其次,矿工信号有一种天然的否决机制,少量哈希算力就能否决节点的升级激活意图,让所有人都得不到升级。到目前为止,软分叉利用了相对中心化的挖矿生态,只有少量的矿池在构造有效的区块;随着我们转向更加去中心化的挖矿生态,我们有可能会越来越多地受困于 “升级惰性”,它会否决绝大多数升级。
—— Shaolinfry,Bitcoin-dev mailing list (2017)
Shaolinfry 还指出了对矿工信号的常见错误解读:人们普遍认为,这是一种工具,由矿工来决定协议要不要升级,而不是一种帮助协调升级的行动。因为这种误解,矿工们可能也觉得有义务在公开场合表达他们对一项软分叉的看法,仿佛这会给这些提议增加说服力。
而 UASF 提议,简单来说,只是一个 “信号日”,节点们开始强制执行特定的新规则。这样一来,矿工们就不必采取集体行动来协调升级,而是 可以 在信号日之前激活升级,只要足够多的区块表态已经就绪。
我的建议是,让我们集两者之所长。因为用户激活的软分叉在激活之前需要一个相对长的预备期,我们可以结合 BIP9 来给出哈希算力协调激活的选项(这样会更快),此外,还能附加一个较慢的信号日激活。不论是哪一种情况,我们都能利用 BIP9 中的警告系统。这项变化是比较简单的,只需添加一个 “激活时间” 参数,它会在 BIP9 部署超时日期之前,将软分叉的 BIP9 状态转为 “锁定(LOCKED_IN)”。
—— Shaolinfry,Bitcoin-dev mailing list (2017)
这个想法引起了许多人的兴趣,但似乎并没有得到所有人的支持,还引起了对它可能引发区块链网络分裂的担心。Aaron van Wirdum 的文章解释了这些争议最后是如何因为 BIP91 而得到解决的。这是由 James Hilliard 提出的比特币升级提议(BIP)。
Hilliard 提出了一个复杂一些但更加聪明的解决方案,让所有东西都能兼容:由
Bitcoin Core开发团队提出的隔离见证升级、BIP148 用户激活软分叉,以及 “纽约共识(New York Agreement)” 激活机制。他的 BIP91 可以保持比特币不分裂 —— 至少在隔离见证激活期间。—— Aaron van Wirdum,《走向隔离见证的长路》,Bitcoin Magazine(2017)
这里面还涉及一些更加复杂的因素(比如,所谓的 “纽约共识”),这个 BIP 也不得不加以考虑。笔者鼓励读者完整地阅读 van Wirdum 的文章,以了解这段故事中的许多有趣的细节。
5.2.2 隔离见证升级之后的讨论
在隔离见证升级激活之后,关于激活机制的讨论还在继续。正如 Eric Lombrozo 在 Breaking Bitcoin 大会上的演讲以及 Shaolinfry 所指出的(见上文 5.2.1 章节),矿工激活软分叉并不是一种理想的升级机制。
有时候我们会想要给比特币协议添加更多特性。这是一个我们要扪心自问的巨大的哲学问题。我们要为下一次升级使用 UASF 吗?还是用一种混合方法?矿工自己激活(这种方法)已经出局了。我们不会再使用 BIP9 了。
—— Eric Lombrozo,《改变共识规则而不破坏比特币》,Breaking Bitcoin 大会(2017)
在 2020 年 1 月,Matt Corallo 在 Bitcoin-dev 邮件组里发送了一封邮件,开始了关于未来软分叉部署机制的讨论。他列举了他认为在升级中至关重要的 5 个目标。David Harding 在一期 Bitcoin Optech 周报中总结为:
- 如果所提议的共识规则变更遭遇了严肃的反对,有能力放弃升级。
- 在发布升级后的软件之前,有足够长的协调时间,让绝大多数的经济节点都能升级到强制执行这些规则。
- 预计在变更之前和之后(以及任何转变期间),网络的哈希率将大致保持相同水平。
- 尽可能地防止创建在新规则下无效的区块,这样的无效区块会导致不升级的节点和 SPV 客户端的区块确认统计出错。
- 确保放弃机制不会被捣乱者滥用、拖延广受期待而没有已知问题的升级。
—— David Harding,Bitcoin Optech newsletter #80 (2020)
Corallo 提出的是一种结合了矿工激活软分叉和用户激活软分叉的机制:
因此,把事情讲得更具体些,我认为,一种能够作为正确先例、妥当地兼顾上述目标的激活方法,应该是这样的:
1)一个标准的 BIP 9 部署流程,以一年的时间窗口准备激活,要求 95% 的矿工准备好;
2)在一年内无法激活的情形中,设定一个长度为 6 个月的静默期,社区可以分析和讨论不激活的理由;
3)在合理的情况下,在最早的部署软件发行版中提供一个简单的 命令行命令/配置文件参数,让用户可以选择一个 BIP 8 部署流程,以 24 个月的时间窗口促成信号日激活(同时,新的
Bitcoin Core发行版自动启用这个标签)。这给更加标准的激活方法提供一个非常长的时间窗口;虽然,在保证依然能够满足第 5 条目标的前提下,需要显著延长时间窗口来保证满足第 3 条目标。开发比特币不是一场赛跑。如果有必要,等待 42 个月可以保证我们不是在建立一个会在日后让我们后悔的负面先例。
—— Matt Corallo,《现代软分叉激活方法》,Bitcoin-dev 邮件组(2020)
5.2.3 “Taproot” 升级与 “Speedy Trial”
当 “Taproot” 在 2020 年 10 月准备好部署的时候,也就是围绕它的共识规则的所有技术细节都已经被实现并且获得了社区内的广泛认可的时候,关于如何部署它的讨论开始发酵。在此之前,这样的讨论一直很低调。
大量关于激活机制的提议开始浮出水面,而 David Harding 在 Bitcoin Wiki 中总结了这些提议。在他的文章中,他解释了 BIP8 的一些属性,那时候为了让它更加灵活而有了一些变化:
在这份文件创制的时候,BIP8 的基础是从 2017 年学到的教训。跟随 BIP 9+148 而出现的一个重大变更是,强制激活的时间度量是区块高度,而不是过往时间中值(median time past);第二个重大变更是,强制激活是一个布尔参数,既可以在初次部署设定软分叉的激活参数时选定,也能在后续部署中更新。
不设强制激活的 BIP8 与 BIP9(带有超时和延迟的版本比特机制)非常相似,唯一的重大区别是,BIP8 使用区块高度,而 BIP9 使用过往时间中值。这一设定允许升级尝试失败(但是可以再次尝试)。
带有强制激活的 BIP8 最终会有一个强制的信号表态期,期间所有产生的区块都必须遵守它的规则 —— 必须表示已经准备好激活这次软分叉 —— 这将使同一软分叉在没有强制激活的早期部署中激活。换句话说,如果已经发行的软件版本 x 没有强制激活机制,而后续发行的版本 y 有,并且成功迫使矿工开始在同一个时间窗口种表示已经就绪,则两个版本的软件都将在同一时间开始强制执行新的共识规则。
修正后的 BIP8 提议的灵活的,使得它可以表达看起来像是 BIP8 的其它想法。这提供了一种区分许多不同提议的通用元素。
—— David Harding,Taproot 激活提议,Bitcoin Wiki(2020)
从这一时间点开始,讨论变得非常热烈,尤其是围绕 lockinontimeout 应设置为 true(从而使用用户激活软分叉,也就是 Harding 所说的 “带有强制激活的 BIP8”)还是 false(从而类同于矿工激活软分叉,也就是 Hardking 说的 “不设强制激活的 BIP8”)的讨论。
在列举出来的提议中,其中一个名为 “不妨看看会发生什么事(Let’s see what happens)”。出于一些原因,这个提议并没有获得很多关注,直到几个月之后。
在这 7 个月时间里,讨论一直在进行,而且似乎没有办法达成广泛的共识(要使用哪一种部署机制)。人们分成两大派别:一些人倾向于 lockinontimeout=true(UASF 派),而其他人倾向于 lockinontimeout=true(“试试看,要是失败了就再想办法” 派)。因为这两个选项都没有获得压倒性的支持,辩论一直在原地打转,看起来没办法走出来了。其中一些讨论是在在线聊天室(IRC)中发生的,在一个名为 “##taproot-activation” 的频道中;但是,到了 2021 年 3 月 5 日,事情有了转变:
06:42 < harding> roconnor: 有人提议 BIP8(3m, false)(为期 3 个月,不设强制激活的 BIP8)吗?我之前提过这个问题,但我没看到有人回答。 [...] 06:43 < willcl_ark_> 应该有,我自己就在想,与此相比,隔离见证的激活机制是非常直接的:直接是 LOT=false ,要是没通过,那就来一次 UASF 。 06:43 < maybehuman> 有趣。如果我没有记错,在这个频道刚刚创建的时候,“Let’s see what happens” (就是 false,3m)是一个热门的选择。 06:44 < roconnor> harding: 我支持。我不知道这有没有价值。根据我对其他人的顾虑的理解,基本上,我认为这会是一个能够得到广泛接受的选择。 06:44 < willcl_ark_> maybehuman: 因为每个人都想要这个升级,甚至矿工们也说自己能在大约两周内升级(至少 f2pool 是这么说的) 06:44 < roconnor> harding: BIP8(3m,false) 加上一个延长的锁定期。 06:45 < harding> roconnor: 哦,不错。从我 7 个月前笫一次在 wiki 上总结这些选项以来,这是我最喜欢的选项。 06:45 <@michaelfolkson> UASF 无法发布 (true,3m),但是 Core 可以发布 (false, 3m) 06:45 < willcl_ark_> harding: 对我来说它真的像是一个好方法。*如果* 它失败了,那我们可以先想想这是为什么,就不用浪费太多时间。—— #taproot-activation IRC 日志
这种 “Let’s see what happens” 方法最终似乎抓住了人们的心。这个过程,后来被说成是 “速战速决(Speedy Trial)”,因为它的表态期很短。David Harding 在一封发布在 Bitcoin-Dev 邮件组的邮件中向广大社区解释了这个想法:
这个提议的较早版本成文于 200 多天以前【3】,而 taproot 的底层代码是在 140 多天以前合并到
Bitcoin Core软件中的【4】。如果我们从代码被合并的同一时间点开始 “速战速决”(这不太现实),我们将要么在未来不到 2 个月的时间里激活 taproot,要么在 1 个多月以前就转向再一次尝试激活。然而,从一年多以前我们开始讨论隔离见证之后的激活方案以来,我们一直在辩论,并且看起来完全没有更加接近于我认为可以得到广泛接受的解决方案【5】。我认为,“速战速决” 是一种快速推进的方法,要么,它能终止争论(如果激活成功,它就能终止截至目前的争论),要么,它给我们一些真实的数据,作为未来的 taproot 激活提议的基础。
—— David Harding,Bitcoin-dev 邮件组
这个激活机制经过了两个月的改进,然后发布在了 Bitcoin Core 版本 0.21.1 里面。矿工们很快开始表态准备好了这次升级,从而将部署状态转变成了 LOCKED_IN;在一段平静的时光之后,“Taproot” 规则于 2021 年 11 月中旬,从区块高度 709632 开始激活。
5.2.4 未来的升级机制
给定近期的软分叉(隔离见证和 Taproot)中出现的问题,尚不清楚未来的升级会如何部署。Speedy Trial 被用来部署 Taproot,但它是因为能够弥合 UASF 派和 MASF 派之间的分歧而被使用的,并不是因为它是我们已知最佳的部署机制。
5.3 风险
在任何分叉 —— 无论是软分叉还是硬分叉、用户激活还是矿工激活 —— 激活期间,都有持续存在的区块链网络分裂风险。持续数个区块的分裂可能导致对围绕比特币的情绪以及价格的严重破坏。但最重要的是,这会造成对 “比特币是什么” 的极大困惑。比特币是这条链、还是那条链?
用户激活软分叉的风险在于,即使大部分的哈希算力都不支持新规则,新规则还是会激活。这种情形将导致长久持续的链分裂,直到绝大部分哈希算力采用新规则才会停止。如果矿工们在发生分裂之后,已经在使用旧规则的链上挖掘了区块,可能就很难让他们迁移到使用新规则的链上。不过,这里也值得提到一个令人印象深刻的事件(详见 9.2.3 章节):在 2013 年 3 月,比特币网络因为意料之外的硬分叉而产生了长时间的区块链分裂,但背反于这种激励因素,两个主要矿池决定放弃他们已经挖出的分支,以重建共识。
另一方面,矿工激活软分叉的风险在于,矿工可能会发送错误的信号,也即是说,真正采用变更的哈希算力的占比,可能比看起来的要小。如果实际支持变更的哈希算力并不形成大多数,我们就有可能看到类似于前面章节所说的长期持续的链分裂。这个问题,至少可以说是一个类似的问题,在 BIP66 部署的时候真的发生了(详见 9.2.4 章节),只是在 6 个区块以内就解决了。
5.3.1 分裂的代价
Jimmy Sone 在巴黎的 Breaking Bitcoin 大会上讲解过跟硬分叉相关的代价,但他说的许多代价,也适用于因为失败的软分叉而导致的链分裂。他讲到了 “负外部性(negative externalities )”,定义是其他人不得不为你的行动支付的代价。
“负外部性” 的一个经典例子是一家工厂。也许它是有生产力的,它是一家石油精炼厂,生产了对经济体有好处的一种商品,但也产生了负外部性,比如污染。它不仅是每个人都必须付出代价的东西 —— 要么清理,要么忍受。它还会有 2 阶 和 3 阶的后续效果,比如随着更多工人要在工厂工作,就有更多的交通流量。工厂周围可能还有野生动物。也有一些时候,并非每个人都要承担代价,而只有一部分人,比如以前使用周边道路的人、生活在工厂周围的野生动物,是由他们来承担工厂的代价的。
—— Jimmy Song,《硬分叉的社会成本》,Breaking Bitcoin 大会(20017)
在比特币的语境下,他将使用 Bitcoin Cash(Bcash)作为负外部性的例子;Bcash 是比特币的硬分叉,就在 2017 年 Breaking Bitcoin 大会举办之前不久创建。Song 还将硬分叉的负外部性区分为一次性的成本和永续的成本。
在一次性成本的许多例子中,他还提到了因为交易所而产生的成本。
市场上有许许多多的交易所,他们都必须承担大量的一次性成本。首当其冲的是,存入和取出资金的窗口必须暂停一到两天,因为他们无法确定会发生什么事。由于用户要求 Bcash,许多这样的交易所不得不动用冷存储。这是他们应尽的信托责任,他们必须这样做。你还必须审计新的软件。这是我们在 itbit 必须做的事。我们想要花费 bcash —— 但是怎么花费呢?我们一定要下载
electron cash软件吗?会不会有恶意软件?因此必须审计。我们可能要 10 天来搞清楚它到底能不能用。然后,同样必须决定的是,仅仅允许用户一次性取款呢,还是要上架这种货币?对于交易所来说,要商家一种新的货币并不是简单的事,它关联着冷存储、签名、存款、取款这整套的流程。或者,你也可以搞一个一次性的活动,把 Bcash 归还给用户,这就一了百了了。但这样做也有问题。最后,不论你怎么做 —— 让用户取走,或是上架新币种 —— 你都需要新的基础设施来操作这种新的货币,哪怕你提供的只是一次性的取款。总得有一种办法来归还它们给用户。而且,你还要搞个临时通知,对吧?时间不多,火急火燎。—— Jimmy Song,《硬分叉的社会成本》,Breaking Bitcoin 大会(20017)
他也列出了在商家、支付处理商、钱包软件、矿工和用户处发生的一次性成本,还有永续成本,比如隐私性损失以及更高的链重组风险。
实际上,在发生区块链分裂的时候,如果使用更松散规则的链比使用更严格规则的链更加强壮,链重组就会发生。这对受损分支上的所有交易都会有严重的影响。出于这些理由,不论什么时候,避免链分裂都是极为重要的。
5.4 结论
比特币随时间生长和演化。在此期间,多种升级机制被采用过,其学习曲线也是陡峭的。随着我们对网络的反应了解越来越多,越来越精巧和健壮的方法不断被发明出来。
为了保持比特币的和谐,软分叉被证明是前进的方向,但是,还有一个大问题依然没有完全得到解决:我们如何能够安全地部署软分叉,而不引起不和谐呢?