区块链最强大的一个特质就是我们能独立验证其执行中的每一个部分。即使大部分区块链矿工(或者权益证明中的验证者)被攻击,如果该攻击者企图让无效区块上链,网络也会拒绝。哪怕是没有实时验证区块的用户,(在变故发生时)也能够收到正在验证区块的用户的警告(这个过程有可能实现自动化),进而自行验证发现攻击者的链无效,自动拒绝接收这条链,然后与其他节点协调一致接收另一条遵循规则的链。
但在实践中,我们到底需要多少验证者?一百个独立验证的节点?一千个?我们是否需要让世界上每个普通人都运行软件来检查所有交易?回答这些问题是我们的挑战,尤其是,如果我们还想构建出比单一链的中本聪工作量证明更有优势的共识机制的区块链,解决这些问题就格外重要。
为什么要验证
- 51% 攻击者尝试让网络接受一个无效区块,而我们希望网络不会接受无效链!-
用户对区块链进行验证主要有两个好处。首先,这可以在最大程度上让节点参与到决定合法链(也就是被整个社区接受的、具备合法性的链)的过程中。通常来说,合法链被定义为 “有最多矿工或验证者支持的有效区块链”,比如比特币中的 “最长有效链”。无效链根据定义就会被拒绝,如果有多条有效链竞争,则获得最多矿工或验证者支持的链获胜。因此如果你运行一个验证所有区块有效性的节点,你将能检测到哪些链有效哪些无效,从而将最大程度地提高检测出合法链的机会。
但用户对区块链进行验证其实还有一个更深层的益处。假如一个强大的参与者企图让网络接受某个对协议的变更(比如改变发行量),并且有多数矿工支持,在没有其他人对区块链进行验证的情况下,这个攻击很容易就实现了。并且,所有客户端都会默认接受这条新链。等到所有人回过神来意识到这件事时,只能靠反对者通过协调来拒绝这条新链链。但如果普通用户也参与验证,那么情况就完全不同了,企图变更协议的攻击者需要说服验证用户主动下载他们的软件补丁以变更协议。
如果有足够多的用户参与验证,那么当有人尝试对协议进行有争议的更改时,默认情况就不会是成功,而是造成混乱。天然混乱也会对网络产生破坏,需要协议层面外的社会协调来解决,但这也在攻击者面前放置了更大的障碍,让他们无法自信自己可以一击成功然后一走了之,也就大大降低了他们发动攻击的意愿。如果多数用户参与直接或间接的验证,并且攻击者只有多数矿工的支持,那么这次攻击天然会失败,这也是对所有人最好的结果。
定义的视角 vs 协作的视角
要注意的是,上述推理的逻辑跟我们经常听到的另一种推理是很不一样的:他们说,只要是改变协议规则的链 “从定义上来说” 就不会是合法链,而且重要的不是有多少用户愿意接收新的规则集合,而是你永远可以留在使用自己喜欢的旧规则的链上。
看一看这个从 “定义的视角” 来讨论这件事的例子,来自 Gavin Andresen:
我想为比特币提出一个全面的技术上的定义:
“比特币” 是一个交易分类账,以区块链的形式记载带有合法签名、花费此前未花费资金的交易。这条链由创世块开始,其哈希为 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f,它按照预定的时间表、在积累了最多 double-SHA256 工作量证明的链上发行 2100 万枚比特币。
来自 Wasabi 钱包的另一个定义,从解释全节点的价值来说,这个定义更直接了当:
在运行比特币全节点时,你可以定义自己所认同的确切的货币规则。没有人能强加于你。因此,任何追求金融自由的自治个体都应该运行全节点。在确定了自己的规则后,全节点软件就能在比特币点对点网络中找到符合我们规则的节点。这些节点根据它们的规则,向我们发送它们判定有效的交易,我们再根据自己的规则进行验证。如果我们收到一个不符合规则的交易,我们大可以将其标记为无效交易,并且断开跟无效交易来源节点的连接。
伸张你的货币主权
使用全节点让我们享有定义、验证并执行我们比特币货币规则的权利。
我们要注意一下 “定义” 的视角中的两个核心:
一条链如果不符合你定义下的基本的、没得商量的规则,无论多少其他人接受该链,从定义上说这条链就不是比特币(或以太坊或者其他)链。
最重要的是你坚守在符合自己规则的链上。
然而,我认为这个 “个人主义” 观点是很有问题的。在解释我的理由前,我们先来想一想我们不愿意看到的情形:绝大多数参与者都接受了一个你不愿意接受的协议。比如,有一天交易费变得非常便宜,为了维护链的安全,几乎所有人都同意更改规则,增发新币。而你固执地跑着老规则下的链,自己一个人从大部队中分叉出去了。
从你的角度来说,你的确还拥有在你所认同的规则基础上构建出来的系统中的货币,但那又如何?其他人都不再接受你的货币了。交易所不会接受,网站上可能会显示新货币的价格节节高涨,但这新币指的是拥有多数用户的链上的货币,你的货币会变得一文不值。密码学货币与区块链从根本上来说乃是社会建构。如果没有其他人相信,它们将变得毫无意义。
那么我们应该从什么角度来看这个问题呢?这个角度的核心是将区块链看成利用协调问题来实现安全性的例子。
通常来说,真实世界的协调问题都很难:虽然对大部分人来说,如果英语改变其高度复杂而不规则的拼写系统,改成语音拼写会更好;虽然如果美国改用公制会更好;虽然在经济衰退的时候我们立即将所有价格和工资一起降低 10% 会更好,然而实际上这需要每个人同时同意这些转变,是非常难达成的。
但在区块链的应用上,协调问题反而成了我们的优势。我们利用协调问题造成的不顺畅来阻止核心参与者的渎职行为。我们能够构建具有 X 属性的系统,并且保证这个 X 属性能够被保留下来,因为将规则从 X 属性更改为非 X 属性需要一堆人同意并且同时更新他们的软件。即使有一个参与者可以强制推动更改,他也非常难做到,要比反对者积极协调抵制更改难得多。
我们应该注意到持这个观点的特殊后果:运行全节点的目的不仅仅是为了保护自己的利益,在发生争议硬分叉时,运行全节点的用户很安全,而没有全节点则不安全。这在更大程度上可以看成一种群体免疫,验证的人越多,每个人都越安全,而且即使只有一部分人验证,每个人都可以获得较高程度的保护。
深入讨论 “验证”
我们现在进入下一个话题,这个话题对轻客户端与分片之类的话题非常重要:验证的时候我们到底是在做什么?要理解这一点,我们需要回到更早的时间点。对于一次攻击,我有以下的偏好顺序:
默认造成失败 > 默认导致混乱 > 默认取得成功
这里的 “大于号” 意思是前者比后者更优。最优的情况是攻击直接失败,次优的情况是攻击导致混乱,造成大家无法就合法链达成一致,而最坏的情况则是攻击成功。为什么说造成混乱要大大优于攻击成功?这可以归结为激励机制,混乱也会给攻击者带来成本,使他们无法确信攻击能成功,因此能削减攻击者发起攻击的动力。天然导致混乱的环境对攻击者来说,意味着他们需要赢得区块链战争(成功发起 51% 攻击)还要赢得 “舆论战”,说服整个社区跟进攻击链。相较于仅仅发动 51% 攻击就必然成功,上述情况将使攻击变得异常困难,也没那么有利可图了。
进行验证的目标就是让攻击从天然取得成功的状态变为天然失败的状态(最优),或者变为天然导致混乱的状态(次优)。如果你运行一个完全验证所有区块的节点,攻击者试图让网络接受一条规则不同的链,攻击就会失败。如果部分用户运行验证全节点而还有很多人没有,攻击则会导致混乱。但我们还要思考,有没有别的方法可以达到相同的效果呢?
轻客户端与欺诈证明(Fraud Proof)
一个更好的办法自然是使用带有欺诈证明的轻客户端。当前的大多数区块链轻客户端仅仅验证是否大多数矿工都支持特定区块,而不会验证协议规则是否得到满足。这些客户端的正常运行假设了大部分矿工都是诚实的。一旦出现有争议的分叉,这类客户端会天然随大流,用户需要主动采取措施才能留在旧规则下的少数方链上。因此,对于当前的轻客户端发起攻击,攻击者可以天然成功。但有了欺诈证明技术,情况就大不相同了。
简单来说,欺诈证明的工作原理如下。通常来说,区块链中的单个区块仅仅会涉及到区块链 “状态”(账户余额、智能合约代码……)的一小部分。如果一个全节点处理完一个区块发现其无效,就可以生成一个数据包(即欺诈证明),并广播给轻客户端。数据包内仅包括该区块及足够处理该区块的数据,轻客户端拿到数据包后则可以自行验证该区块,而无需链上的其他数据。
- 单一区块仅仅涉及几个账户,欺诈证明能够包含这些账户的数据,并连同其默克尔证明,来证明数据的正确性 -
这项技术有时也称为无状态验证,客户端可以只记录区块头,而无需记录完整的区块链状态数据,而且可以通过向其他节点请求任意状态条目的默克尔证明来实时验证正在处理的区块。
该技术的强大之处在于,轻客户端只有在收到警报(警报也是可验证的,如果轻客户端发现虚假警报,它们可以停止监听该节点的警报)后才会去验证单个区块,因此在正常情况下,轻客户端依然轻量,只检查哪些区块获得了大多数矿工或验证者的支持。但在特殊情况下,若多数人所在的链包含了一个该轻客户端不接受的区块,只要有至少一个诚实的全节点验证到了这个有问题的区块,就可以知道其无效,并广播欺诈证明,从而使网络中的其他节点也拒绝它。
分片
分片是在此基础上的一个自然的拓展,在分片系统中,系统中的交易太多,多数用户无法一直直接验证,但如果系统设计良好,那么任何无效区块都能被检验出来,而且其无效性可以由欺诈证明来验证,该证明就可以在全网广播。分片网络可以看作每个用户都是一个轻客户端,只要每个分片的参与者都在某个门槛之上,网络就能获得群体免疫。
另外,还有一点非常重要:在分片系统中,区块的生成(不仅仅是验证)门槛是很低的,甚至可以在家用笔记本上完成。网络的核心并不依靠高性能硬件,确保了反对派作为少数一方的门槛足够低,这就使得以多数人主导的协议更难以被攻击者变为 “天然攻击成功” 的状态(迫使其他人服从于其攻击)。
这也是现实世界中审计的意义:并不是每个人都随时在验证所有内容的,而是第一,每个特定部分都有足够的人在检查,任何错误都一定能被发现,第二,一旦检查出错误,所有人都可以清楚看到错误所在。
话说回来,从长期来看区块链肯定能在这方面更进一步。进步的一个来源是 ZK-SNARKs(或称 “有效性证明”),是一种高效且可验证的密码学证明,使区块生产者能够向客户端证明区块满足某些任意复杂的有效性条件。有效性证明比欺诈证明更强大,因为它不依赖于交互博弈才能捕获欺骗行为。另一种重要技术是 “数据可用性检查”,可以侦测出没有完全公开内容的区块。数据可用性证明确实依赖一些安全假设,但这个假设非常保守:网络中还存在少量可用的节点是诚实的(“愿意遵守协议”);好消息是,这个诚实验证者的最低数量要求很低,而且即使攻击者数量非常大也不怎么需要提高要求。
时机与 51% 攻击
现在,我们来看看 “天然造成混乱” 的模式中最强大的后果:51% 攻击开始攻击自己。在当前许多社区中,如果发生 51% 攻击且攻击者取胜,那么 51% 攻击链就会成为合法链。这个规范被大家严格遵守。近期对以太坊经典的 51% 攻击就说明了这一点。攻击者回退了 3000 多个区块,在这个过程中用双花攻击窃取了 807,260 ETC。由于以太坊经典的两个客户端之一(OpenEthereun)技术上无法退回攻击链的历史高度,导致 Geth 节点能够在攻击链上运行,而 OpenEthereum 则只能被困在原本的链上。
我们可以说这次攻击的确导致了混乱,但这是偶然事件而不是以太坊经典社区有意设计如此。可惜的是社区随后选择接受了(更长的)攻击链为合法链。以太坊经典推特账户称其为 “像我们的初衷一样严格遵循工作量证明”。因此,该社区规范竟积极帮助攻击者获胜。
但其实我们可以就合法链的定义达成另外一种共识,比如说建立一个规则,某个区块具有超过 100 个后代区块之后,其合法性就不能颠覆。或者是,一个具有终局性的权益证明(比如以太坊 2.0 就是如此),规则是,一旦一个区块获得终局性,就永远不会被回退掉。
- 仅为图解方便,限制最多回退 5 个区块示意图。实际操作中可以将回退限制在 100-1000 个区块范围内 -
我们要明确,这对链的合法性的定义引入了重大变更:客户端不仅仅要查看它们收到的数据,还需要检查何时收到的数据。这也会引入一个新情况,由于网络延迟,在一次大规模攻击时,两个冲突块 A 和 B 同时获得终局性,一些客户端先看到 A,另一些先看到 B,那他们就无法达成一致。但我认为这未尝不是好事,因为这意味着攻击没有天然获得成功,甚至仅仅回退区块的 51% 攻击都会天然导致混乱,社区层面的紧急响应就能在两条链之间选择继续哪一条。如果协议设计合理,要使事件达到需要社区层面的紧急响应应该是非常昂贵的,在权益证明中,这意味着 1/3 的验证者要牺牲他们的保证金且被惩罚。
这种方法还有发展的潜能。我们可以尝试制造 51% 攻击来专门审查会导致混乱的交易。对于及时性验证器的研究也在让所有类型的攻击朝着天然失败的方向发展。尽管如此,仍会有一些混乱发生,因为及时性验证器无法帮到那些离线或者网络连接不好的节点。
对于重视不可篡改性的区块链社区而言,可以说这种限制回退的措施是不错的选择,如果无论网络在多久之前接受了某一个交易,但它仍有可能在意外中被回退,那么区块链就无法自诩享有不可篡改性了。当然,我相信即使是 BTC 和 ETC 也已经限制了极端情况下的回退,如果某个攻击试图回退数周的区块历史,社区也可以发起一个需要用户主动参与的软分叉来拒绝攻击者的链。但更明确地达成一致并正规化这一措施才能更进一步。
结论
那么这个故事教会了我们什么?首先,如果我们接受社会协作的合法性,并且接受以 “1-of-N” 信任模型为假设的间接验证的合法性,也就是说,假设网络中总有某一个诚实参与者,而不是假设某一个参与者(比如 Infura)总是诚实的,那么我们就可以创建出可扩展性更强的区块链。
其次,客户端验证是上述提及的内容至关重要的一步。一个只有少数人运行(验证)节点而其他人都依赖对于验证节点的信任的网络,在涉及特殊利益时是非常容易被攻击的。但要避免这样的命运也不意味着矫枉过正,让所有人随时都要验证一切。让单个区块可以被隔离验证,用户因而只需要验证受到警报的区块,这样的系统也是合理且可以达到相同效果的。但这就需要我们用前文提到的 “协作的视角” 来看待验证的作用。
第三,如果我们将 “时机” 也纳入合法链的定义范围,那么我们抵御 51% 攻击的技能树将会打开。最好接受的属性是弱主观性,也就是要求客户端至少每三个月在线一次,且拒绝任何比三个月时间更长的回退,我们就能在权益证明里加上惩罚机制,使攻击成本变得高昂。我们还可以更进一步,我们可以拒绝回退所有获得终局性的区块,由此保护不可篡改性,也可以防止被审查。因为网络不可预测,依赖 “时机” 在一些情况下的确意味着攻击会天然导致混乱,但带来的好处也是显而易见的。
记住以上这几点,我们就可以避免以下陷阱:1. 过度中心化;2. 验证过度冗余而导致网络效率低下;3. 误导性规则意外导致攻击变得更容易;并朝向更具韧性、更强性能和更安全的区块链。
(完)