本章目标: 2010 年 8 月 15 日,有人凭空造出了 1840 亿枚 BTC。五小时后,它被修复了。这是完整的故事——比特币离死亡最近的一次。多年后回看,它是「验证,而非信任」不是口号、而是生存法则的最干净案例研究。五小时的危机,超过十年的正名。
1. 2010 年 8 月 15 日
比特币十九个月大。网络有几百个用户、几千个节点,币价不到一美分,严肃的对手为零。
UTC 时间 19:13,一个周日下午,一个不明身份的行动者广播了一笔利用比特币验证代码漏洞的交易。这笔交易创造了 184,467,440,737.09551616 BTC——超过本应存在的比特币总量的 8000 倍——并把它发给两个地址,几乎对半分。
下一个矿工把这笔交易打包进了区块 74,638。按当时正在运行的代码,这个区块是有效的。每个节点都接受了它。几个小时里,比特币的供应问题出现在与其设计承诺完全相反的方向上。
这是比特币有史以来离死亡最近的时刻。修复在五小时后到来。值得搞清楚它为什么成功。
2. 漏洞:整数溢出
漏洞位于 CTransaction::CheckTransaction——每个节点验证交易是否合规都要调用的函数。其中一项检查:确认所有输出金额之和不超过 MAX_MONEY(2100 万 BTC,以聪计)。
这段检查代码用一个有符号 64 位整数存放累加和,按顺序累加每个输出金额。如果两个输出的值都接近 2^63,求和就会溢出——越过可表示的最大正数,回绕到负数区。负数当然小于 MAX_MONEY。检查通过。
那笔交易有两个输出,各设为约 9.2 × 10^18 聪——恰好越过溢出阈值。二者之和溢出成一个很小的负数。验证函数说「看起来没问题」。交易被打包上链。
这是一类至少从 1970 年代就被理解透彻的教科书级 bug。C/C++ 允许有符号整数溢出,行为在技术上是未定义的,写出不考虑它的检查代码是众所周知的脚枪。中本聪还是写了。换成我们任何人也会。
3. 区块 74,638
这个区块乍看完全正常:一笔挖矿奖励(50 BTC)、几笔普通交易,外加一笔发行 1840 亿枚 BTC 的交易。
链条接受了它。五个小时里,每个下载了该区块的节点,都运行着一个流通量达到设计供应约 9200 倍的比特币。
如果放任不管,这将永久杀死比特币。2100 万上限是持有它的唯一理由。上限一旦在生产环境中被实际打破过,就没人会再相信它不会被打破第二次。比特币会终结于 2010 年。
4. 中本聪的响应:五小时
漏洞在出现后一小时内被注意到。UTC 19:50,BitcoinTalk 论坛帖子开始标记这笔奇怪的交易。到 UTC 23:30,中本聪已提交修复并发布 0.3.10 版。修法:增加一项检查,在溢出导致校验误通过之前将其拦截。
中本聪在论坛写道:
「那是一个坏区块。0.3.10 及以后版本不会接受它。请尽快升级。」
技术修复本身很小。难的是让节点运营者升级并协调一次链重组,把坏区块移出历史。
5. 那场「不是软分叉的软分叉」
比特币文档常把通胀漏洞的修复描述为一次软分叉。严格说,它不是。它是一次协调速度极快的硬分叉。
软分叉收紧规则:新客户端拒绝旧客户端会接受的区块,但旧客户端仍然接受新客户端产出的一切。链条保持统一。
硬分叉更改规则:新客户端拒绝一些旧客户端接受的区块(或反之)。两版同时运行,链条就分裂。
通胀漏洞的修复拒绝了旧客户端已接受的区块 74,638。按定义:硬分叉。它没有把链永久分裂成两条的原因,是几乎每个节点运营者都在几小时内完成了升级,而更长的那条链(不含 1840 亿枚币的那条)最终成为唯一的一条。
这是比特币历史上唯一一次被全体社区在提出后数小时内接受的硬分叉。原因:另一个选项是灭绝。
6. 重组:53 个区块
要把区块 74,638 从历史中移除,网络需要挖出一条更长的、不含它的链。这就是重组(reorg)——重排「网络认为哪条链是正统」。
等修复部署完毕、采用率达到临界点时,原链已到区块 74,691——坏区块之后 53 个区块。打了补丁的客户端从区块 74,637 开始另起炉灶,无视 74,638 及其后的一切。
坏区块出现约 19 小时后,补丁链追平并反超坏链。节点重组过去。区块 74,638(及其后 53 个区块)被回滚,那 1840 亿枚 BTC 从此不存在。
这是比特币历史上规模最大的一次有意重组。它也持续提醒着:「这条链」就是多数节点选择接受的东西,而在真正的紧急状态下,那个多数可以移动得非常快。
7. BIP 42:另一个无限供应漏洞
2010 年 8 月的事件并不是比特币唯一一次与无限供应擦肩。
2014 年,开发者 Pieter Wuille 发现区块补贴的编码方式——用位移实现每 210,000 区块减半——藏着一个微妙 bug。足够多次减半之后,补贴没有归零,而是回绕成一个巨大的正数。账面上,比特币的供应在技术上是无上限的。
这个 bug 要到约第 13,440,000 个区块、约 2256 年才会触发,所以并不紧急。但 Wuille 写下了 BIP 42——唯一一个陈述目的是「让比特币的货币政策按人们描述的那样工作」的 BIP。
BIP 42 是一次软分叉:增加「位移次数超过 64 后补贴必须为零」的规则。它悄悄激活,多数用户从未听说过它。
这个 BIP 的存在本身,以及它无争议地部署完成,就是关于比特币文化的一个有趣数据点:供应上限被认真到「哪怕 240 年后才触发的 bug,只要规格说明书上写着 2100 万,也要修掉」。(顺带一提:实际上限是 20,999,999.9769,那是另一个故事。)
8. 对「无需信任」的启示
通胀漏洞常被引用为「比特币并非无需信任」的证据——毕竟它有 bug,bug 由中本聪本人修复,链条还被重写了。
诚实的读法更有意思:
软件永远有 bug。 2010 年的比特币代码有 bug。今天的比特币代码藏着尚未被发现的 bug。一切非平凡的软件系统都是如此。
对手会找到 bug。 上线仅十九个月就有人蓄意利用了这个漏洞。赌注越大,找 bug 的激励越大。
救你的是开源。 漏洞是公开可见的,修复是公开可见的,重组也是公开可见的。每一步都公开、可验证、可复查。网络能协调完成修复,正是因为每个人都能看清「提议的是什么、为什么」。
重组是可能的——短暂地、紧急状态下。 「区块不可篡改」的承诺是概率性的。六个确认让重组几乎不可能;但只要紧急程度够高,19 小时累积的链也能被撤销。
「验证,而非信任」包括验证软件本身。 每个全节点按自己那套规则验证链条。2010 年,那套规则里含着溢出 bug。修复是一次规则变更,而每个节点运营者选择接受它。今天也一样:任何未来出现的破坏供应的 bug,只有在节点运营者选择修复时才会被修复。
9. 这套历史买来了什么
通胀漏洞是最有力的案例研究,证明比特币的种种性质是涌现出来的,不是声明出来的。
比特币有 2100 万上限,不是因为白皮书这么写,而是因为每个节点都在执行它、每个区块都被它校验、每个运营者都有清晰的经济动机拒绝任何破坏企图。
2010 年,上限差点被一个 bug 打破。网络的响应——从发现到修复五小时,到重组 19 小时——是系统在正常工作的证明,不是脆弱的证明。上限守住了,因为运行节点的人要它守住。修复成功了,因为它可验证、透明、目标毫无争议。
多年之后,这仍是模型。比特币的承诺由节点运营者主动、警觉的参与来兑现。代码是人写的,纪律是结构性的。
一个在众目睽睽之下带着完整底账挺过自身 bug 的货币系统,比一个从未被测试过的系统,是更可信的长期标的。
划重点: 谁再说比特币「只要开发者决定就能增发」,让他把 2010 年 8 月的事件通读一遍。修复成功是因为运营者选择运行它,不是因为任何人能强迫他们。同一道闸门至今有效,而且每年更结实。