作者:Antoine Poinsot
来源:https://delvingbitcoin.org/t/great-consensus-cleanup-revival/710
最近我一直在回顾 Matt Corallo 的 “共识清理” 提议。我的兴趣是弄清楚:
- 该提议想解决的那些 bug 有多严重;
- 被提议的修复措施,对最差情形的改善有多少;
- 多了 5 年的经验之后,我们是否能做得更好;(译者注:Matt 的提议是在 2019 年提出的。)
- 还有没有别的东西,是值得解决的。
长话短说:我认为那些 bug 很糟糕。最差情形下的区块验证时间令人担忧。我也认为,修复时间扭曲漏洞比人们通常认为的要重要得多。最后,我认为,我们可以包含一项修复,以避免在区块高度 198 3702 后执行 BIP30 验证;还有一项对传统交易形式(legacy transactions,指的是隔离见证以前的交易形式)体积上限的额外限制,可以为区块验证时间提供有用的安全边际。
我希望用这篇文章激发对共识清理提议希望解决的协议 bug 的讨论。我希望收集对每一项拟议的缓解措施的评论和意见,以及对更多修复措施的潜在建议。关于区块验证时间的部分有大幅删减:我会公开分享一些数字,但关于制作破环性区块的策略的细节,我只会跟 Bitcoin Core 的常年贡献者以及少数比特币协议开发者分享。
时间扭曲漏洞
时间扭曲漏洞利用了难度调整周期不会重叠的特点。矿工通过将一个目标调整周期的最后一个区块的时间戳尽可能往前拨(也就是现在的 2 个小时之后),同时将所有其它区块的时间戳尽可能往后拨,就可以利用这一特点,人为降低难度。这个 stackexchange 的答案有更详尽的解释。
它有多糟糕?
考虑它到底如何让情形恶化,以及它具体带来了什么,是有趣的事情。不管怎么说,矿工们总是可以按住时间戳,不让它推进,即使不利用时间扭曲漏洞。但如果不将一个难度调整周期的第一个区块的时间戳设定得比上一周期最后一个区块还要早,利用难度调整机制就必然会带来挖矿难度的增加。反之,将一个周期的第一个区块的时间戳设得比上一周期最后一个区块要早,攻击者就可以在利用低难度(本局成果)的同时进一步降低难度。
实际上,攻击者可以在开始这种攻击的一个多月时间里,就对网络造成致命伤害。从时间点 t
、周期 N
开始发动攻击,到周期 N+1
的末尾,攻击者就已经可以让难度降低一半。这又让他们可以在一周内挖出周期 N+2
的所有区块,进一步将难度降低 2.5 倍,等等。在少于 40 天的时间里,攻击者就可以让难度降至 1,从而一下子可以挖出几百万个区块。除了拿走剩余所有的区块补贴,这还会摧毁所有依赖于时间锁的 L2 协议的安全性,并让 DoS 攻击界面恶化(比如,可以跟 UTxO 集的膨胀相结合)。
这里忽略了 MTP(过往时间中值),因为它充其量只是攻击者的一个小麻烦。不过,这也提出了一个问题:尽管这样的攻击以控制大部分挖矿算力为前提,小体量的算力是否可以尝试伺机利用它来牟利?比如,将一个调整周期的最后一个区块的时间戳尽可能向前拨,而将所有其它区块的时间戳(在 MTP 规则允许的范围内)尽可能向后拨。技术上来说,这对矿工来说没有(显著)的代价,而 可能 会给他们(以及其它矿工)稍微多一点点区块奖励(以牺牲未来的矿工为代价)。事实证明,使用这样的策略,对于任何小的挖矿算力来说,边际收益都是微不足道的,所以我们可以合理预计,矿工不会尝试相机而动地利用时间扭曲漏洞。
我们应该修复它吗?
一些人主张,矿工们不会有意搬起石头砸自己的脚。也就是说,他们不会杀死自己要挖的链。相反,他们可能会达成一种均衡,仅仅将出块的速度提高 X% 。关于矿工有能力让可用的区块空间增加而不需要改变节点间的共识规则会带来的政治影响,我交给读者自行评判。但我们要指出的是,如果一个矿工的卡特尔(联盟)可以通过利用时间扭曲漏洞来降低难度,即使只是轻微降低,也可以在几周时间内就让网络持续处在崩溃的边缘。
另一个常见的主张是,这并不紧急,因为攻击很明显,而且要花费很长时间。我非常怀疑需要用户在身处的共识规则之外协调并决定某一高度的某个区块的有效性的论证。此外,要协调和更改比特币的共识规则,一个月并不算长。而且,如前所述,还不确定能不能形成这样做的广泛共识。用户喜欢更低的手续费,矿工喜欢更多的补贴。给定当前对挖矿算力的控制分布以及指数降低的区块补贴,认为可能会形成一个尝试利用时间扭曲漏洞的卡特尔并非无稽之谈。
最后,还有人认为这不紧急,因为攻击需要大部分挖矿算力的参与。我认为这太过轻敌。理由时间扭曲漏洞极大地增加了 51% 攻击可以造成的伤害。原本 51% 攻击 “只能” 暂时地审查交易。但用了时间扭曲攻击,可以摧毁整个网络。
我们能够得出一个更好的修复措施吗?
也许不能。被提议的修复措施是直截了当的:让难度调整周期重叠。Matt 提出的变更是最简单也最显著的:用上一周期最后一个区块的时间戳来约束本周期第一个区块的时间戳。
最差情形下的区块验证时间
众所周知,恶意制作的非隔离见证交易可以是极难验证的。更长的区块验证时间可以让矿工攻击者获得不公平的优势,妨碍区块在网络中的传播(及其一致性),甚至对依赖于区块可得性的软件造成有害的后果。为此,共识清理提议加入了对传统脚本用法的几个额外限制。
有多糟糕?
很糟糕。最差情况下,我可以得出一个在我的最新笔记本电脑的 16 核 CPU 上占满 CPU、花费 3 分钟才能验证的区块;在树莓派 4 上,要花 1.5 小时。出于明显的理由,我在这里删减了这样的区块的细节,以及多种创建类似难以验证的区块的方法。我会用一种半私密的附件帖子跟其他协议开发者分享,用的是 Delving 的私密工作坊特性。如果你认为自己也应知晓,但我忘了把你加进去,请联系我。
提议对最差情形有多大提升?我们可以得出更有效的缓解措施吗?
共识清理提议所提议的缓解措施会让我制作出的区块无效。而在新的限制之下,最糟的区块在我的笔记本电脑上只要 5 秒钟就验证完成了。我认为我们可以进一步引入对传统交易体积的限制,以求稳妥。
关于被提议的缓解措施,也有人担心 “没收” 问题(原本有效的脚本变得花不出去了)。我认为,这些担忧是合理的,也可以解决:仅对某个区块高度之后创建的脚本应用新的规则。
使用 64 字节交易的默克尔树攻击
根据比特币区块中默克尔根的计算方式,(已知)剩余有两种攻击。两种都跟拼接两个 32 字节的哈希值相关,要求该拼接后的字符串能够成功反序列化为比特币交易。(可能最著名的)一种是欺骗一个轻节点接受一笔并没有被某个区块确认的交易:让一笔体积为 64 字节的交易得到区块确认(因此被默克尔树承诺),但其后面的 32 字节却对应于一个支付给受害者、但没有得到区块确认的交易的 txid。另一种是欺骗一个节点,让其将一个有效的区块永远禁止:找出一行树节点,可以全部反序列化为(无效的)64 字节的交易。更多细节请看 Suhas Daftuar 撰写的这篇文章。
共识清理提议将体积小于等于 64 字节的交易判为无效交易,可以同时修复这两个问题。
有多么糟糕?
针对轻节点(或任何接受默克尔证据的东西,比如侧链)的攻击都要求在 61 到(大约)75 比特区间内的暴力搜索,具体取决于专门用于攻击的比特币的数额。这是昂贵的,而且有简单的缓解措施。比如,通过请求对 coinbase 交易的默克尔证据来检查默克尔树的深度,这会告诉你该区块包含了多少交易。
也就是说,这种攻击估计要花费 100 万美元的成本,在 “最新的比特币挖矿 ASIC 算力到达 14TH/s” 的时候。现在,似乎 ASIC 的算力已经上升到 400TH/s 了。此外,这种攻击可以给交易伪造任意数量的确认。而成本只是挖出一个假的区块来欺骗一个 SPV 客户端,现在高了一点(80 比特)。
愚弄比特币节点的攻击在 Bitcoin Core 中已经得到了缓解,办法是不缓存没有上下文的区块检查(CheckBlock()
)。创建有效的交易是不现实的:第一笔必须是 coinbase 交易,需要暴力搜索 224 比特。
因为默克尔根在区块中的计算方式,64 字节的交易是比特币中的一个核心漏洞。虽然因它而起的(已知的)两种攻击都可以被缓解,但如果能避免这个走火风险,同时在 Bitcoin Core 中缓存无上下文的区块检查,那会是好事。
我们能得出更好的修复措施吗?
64 字节的没法是 “安全的”,因为在一笔交易中,64 字节不足以安置一个带有锁定脚本(不是任何人都可以花费、也不会永久锁定)的输出。它们没有已知的用途,而且已经被全网当成非标准交易长达 5 年了。给定它们会带来的漏洞以及它的无用,将它们判为无效交易是非常合理的。
然而,该 BIP 提议将小于 64 字节的交易也判为无效交易。虽然它们是没有(或者不怎么有用)的,这样的交易是无害的。我一直认为,一种交易类型无用,不足以让我们通过软分叉将它们判为无效。
AJ 在他给 Bitcoin-inquisition 的 PR 中也让(确切的)64 字节长的交易无效。
愿望清单
BIP30 验证
BIP34 暂时可以避免对每一个区块连接运行相对昂贵的 BIP30 检查。从区块高度 198 3702 开始,就不能只依赖于 BIP34 了。如果要提议一种软分叉来解决长期存在的协议 bug,那么让每一笔 coinbase 交易从此绝对独一无二,就最好了。
一种简单的解决办法是让 coinbase 交易的 nLockTime
设置成创建它的区块高度。但是,有一种办法更迂回,可能对矿工来说更容易部署:在所有 coinbase 交易中强制要求 witness 承诺(来自 Greg Sanders)。我还没有确定这条规则会不会有例外,但如果一个前隔离见证 coinbase 交易,其输出恰好推送了以 32 个 0x00
字节开头的见证承诺头,我会非常惊讶。
你最 “喜欢” 的 bug!
在这个阶段,我希望收集尽可能多的清理建议,确保如果这样的软分叉被摆上台面,我们已经尽可能细致地分析了所有我们可以加入的修复措施。
当然,建议应该有合理性。例如,“禁止 ordinals” 是一个无趣的提议,而且我很怀疑有多少人会参与。此外,让我们集中在长期的、没有争议的 bug 上。例如,“一个花费长于 30 分钟来验证的区块意味着糟糕情形”、“被打破的默克尔树计算会带来走火风险”,以及 “让 coinbase 交易 真正 独一无二”,似乎是完全没有争议的。而另一方面,虽然 “让我们降低区块体积限制” 可能有合理的理由,但对我来说,有争议得多。
举个例子,这里有两种你无法说服我值得提议的东西:
- 要求隔离见证 v0 交易也具备标准的 SIGHASH 类型字节。
- 限制脚本公钥的体积上限,以减少最差情形下 UTXO 集的增长。