加密货币和区块链(二):分布式共识与去中心化

我先回答一些上一篇文章发布后看到的一些问题。我在第一篇文章里避免了对具体技术的讨论,因为加密货币和区块链是复杂和多面的问题,各种媒体经常把概念混淆,要解释清楚不容易,所以就先写一写对普通投资者有用的一些事实。

我收到的很多反馈其实也证明了这种混淆。有的人告诉我相信比特币的长期价格会越来越高,有的人告诉我区块链就像互联网早期、有很高的应用价值,等等。我上一篇文章里其实并没有涉及这些话题。反对意见中有一点和我的原文略有关系,就是不管泡沫如何,股票最终没有被放弃,电子技术没有被放弃,互联网也没有被放弃。不错,南海泡沫危机后一百多年其他公司又可以重新发新股了,但是危机发生时的那些公司大都消失了,那些投资它们的人也没有翻盘的机会。互联网是发展起来了,但是和 2000 年时那些倾家荡产的人没什么关系,对大部分人来说失去了的东西没有回来。相反很多在 .com bubble 里受损失的投资者后来很长时间都不敢再碰互联网公司股票,错过了这个行业高速发展的阶段。每一次这样的事件都会摧垮很多公司(还记得朗讯和北电吗),毁灭很多财富和投资者。活下来的公司在之后的很长时间里也很艰难,有很多走向衰败。

上一篇文章要警告的是抱着快速致富或者所谓跨越阶层的心态把自己输不起的财产投入进去的人。说到底各种加密币和 token 只不过是有着特定预期回报率和风险的 asset class。如果你做了充分的了解后认为它们应该是你投资组合的一部分,当然没问题。毕竟每个人对同样资产的回报率和风险评估不一样,偏好也不一样,否则金融市场就活跃不起来了。但是从我看到的反馈看,大部分人的了解很有限,并不属于这种情况。

我本想在这篇文章里把技术和应用方面都写完,结果写着写着发现内容太多,只能先说一部分技术话题了。加密货币和区块链是不同概念,我尽可能把两者分开讨论,但因为是加密货币让区块链概念产生和得到关注,目前也是区块链上最主要的应用。所以举例难免还是以主流加密货币所使用的区块链为主。

三分钟理解区块链

我用一点篇幅介绍一下基本概念。区块链英文是 blockchain,顾名思义就是由 block 组成的 chain。我不知道区块链的「区」是怎么来的,直译的话应该叫「块链」才对。每个 block 就是一些数据,对于比特币来说就是一些交易记录,然后有一个机制把这些 block 连成一个列表。普遍采用的办法是用一个哈希函数 H,把每个 block Bi的哈希值 H(Bi) 包含在下一个 block Bi+1 里。H 具有单向性,也就是知道 B 就很容易算出 H(B),但是反过来如果只知道 H(B) 的值很难构造出一个满足条件的 B。下面这个图表示了一个基本的区块链结构。

最简单的区块链

最简单的区块链

学过程序设计的人很容易看出它其实就是一个链表,只不过程序中用内存地址来标识一个节点,而区块链里用哈希值来标识一个块。这么做的结果是如果其中任何一块被修改了,很容易被检测出来,因为原来的哈希值在下一个块里。比如在上图中如果 B0 变了,H(B0) 就会变。而因为 H(B0) 是 B1 的一部分,所以导致 H(B1) 也要跟着变。如果有人要修改记录在这个链上的数据,就需要修改后面所有的块。

这个结构和它的原理对很多人来说并不陌生,它早在 1980 年就被发表了,以发明人的名字命名为 Merkle List。如果你是一位软件工程师,你多半用过 Git,它存储数据的方式就是基于 Merkle List(其实是更为通用的 DAG,不过原理一样).

现在说区块链大多是指在互联网上可以由很多人读取和写入的分布式的区块链,链上新的数据块会被广播到全网让所有人能看到。这就需要解决两个问题,第一是一致性,因为会有很多人同时往这个链上增加新的块,这样就会产生很多不同的分支,为了让所有的节点能看到一致的历史(达成共识),大部分区块链系统采用一个简单的策略,就是每个节点看到两个不同的分支时,就认为比较长的那一个是正确的分支,另一个分支上的数据需要重新打包成正确分支上的块。这样就带来了第二个问题,就是恶意的节点可以通过生成新块来在整个系统中保持多个长时间存活的分支。如果这是一个货币系统的话,恶意节点就可以把自己的钱多次消费(double spending)或者在很长时间后再把交易取消把自己的钱拿回来。解决的办法是给增加新块设定一个门槛。比特币(以及大部分区块链系统)的方案是在每个块里增加一个叫 nonce 的部分:

增加了 nonce 的区块链

增加了 nonce 的区块链

当一个节点想把一个新块 B2 加到链上的时候,它需要为这个块的 nonce2 找到一个值使得这个块的哈希值 H(B2) 满足一定的条件(比如以特定数量的 0 开头)。前面说过 H 有单向性,所以找到一个满足条件的 nonce 值需要进行很多计算。这样一来假设整个区块链系统里的计算能力分布比较均匀,恶意的节点就不能随心所欲地增加新的块了。这个方式被叫做 Proof of Work(PoW)。按照区块链的设计,链上的数据不能被修改,新的数据只能增加到后面,所以也叫分布式账本。

当一个节点成功地把一个 block 添加到链上后,它能得到一定的奖励。这个计算 nonce 的过程,就是所谓的挖矿。而 nonce 的存在只是为了解决让区块链在互联网上运转所面临的其中一个问题(没有解决的问题后面会说到)。2017 年比特币挖矿消耗的电能相当于一个欧洲中等国家的耗电量,全球 195 个国家里,有 159 个国家的耗电量低于比特币挖矿的耗能

安全性和可靠性

区块链最大的问题是大部分人对它在互联网环境下的安全性和可靠性过于乐观。比特币的原始论文里只考虑了多次消费的问题,而且给出的不是严谨的证明,而是用一个 C 程序模拟了几个不同参数下的运行结果。多次消费只是一种可能的攻击,很多其它在评估一个分布式系统时需要考虑的问题,区块链都没有给出答案。很多其他类型的攻击并不需要攻击者拥有 50% 以上的算力。

在一个不完全可靠的网络中,去中心化的分布式系统能可靠地完成的事情是非常有限的。不少在中心化的系统里看起来很容易的事,在需要考虑错误的分布式环境下就成为了难题,要么不可能,要么代价很高、效率很低。很多文章说区块链解决了分布式共识的问题,其实这是个有些误导人的说法。在异步系统里,只要有一个不可靠的节点,共识就是不可能达到的。这个很早就被证明的结论叫 FLP Impossibility(FLP 为三位作者的名字缩写,其中 F 是我的导师)。过去三十多年里,分布式系统领域的基础研究有很大部分都是关于如何绕过 FLP 的结论来在一些特定的假设下实现共识问题的某个弱化的变种。

第一类是允许有阶段性「假共识」的协议。整个系统在满足一些条件的前提下,最终会达成共识。需要的时间取决于网络状况和坏节点的行为,没有绝对上限。每个节点都无法准确判断整个系统是否已经达成共识,只知道时间过得越久,可能性越高。有大量节点参与的共识协议大部分属于这一类。我自己在博士期间的一部分工作是这方面的协议。比特币和以太坊的区块链也是一个这样的系统。

第二类不允许假共识,也就是好节点能判断共识是否达成,但有网络故障或恶意攻击时协议的执行进展会停滞,直至恢复到可接受的状态。这类协议比较适合参与共识协议的节点较少,并且相互能直接通信的情况。Google 的 Chubby 和 Apache 下的 ZooKeeper 是这类的系统。因为容错带来的性能损失很大,所以一般都是在网络状况良好可控的数据中心运行,也不会在其中同步大量数据,他们的作用是帮助其他集群完成主节点选举(leader election)之类的事,或者可靠地存储关键的配置数据。

现实中的分布式系统往往都是先选举主节点,然后以中心化的方式来做效率要求高的协调和数据交换,依靠及时发现主节点故障并重新进行选举来实现高可用。这样可以把分布式容错的复杂度和性能代价限制在一定时间和节点数的范围内,也让分布式系统的设计开发大大简化。所以主节点选举作为核心话题在分布式系统的论文里占相当大的比例。

也有一些人说区块链可以容忍拜占庭错误(Byzantine failure)。这句话听着高级但也是错的。Byzantine failure 一般在分布式计算模型里用来描述不受限制的恶意节点。因为恶意节点的行为不可预知,对它们的能力(包括计算能力)做任何假设都是危险的,会导致忽略现实中的一些可能性,比如攻击者可以通过 social engineering 拿到其他人的密钥。因为系统模型不可能涵盖所有情况,所以通常把 Byzantine failure 看作是可以有任何行为的 oracle。像区块链这样依赖于密码学的系统只能容忍计算力受限的敌手(computationally-bounded adversary),即使是在这个模型下,区块链的容错能力也是很模糊的。

就拿多次消费的问题来说,很多人喜欢把这类攻击叫做 51% 攻击,其实这是很误导人的。因为这种说法潜在意思是说只要攻击者的算力不超过 50%,这个系统就是可靠的。如果攻击者算力超过 50%,他就可以控制链上的数据,但是在现实当中的多次消费攻击并不需要做到这一点。2014 年时确实曾经有一个矿池 GHash 的算力超过了比特币网络的 50% 长达至少 12 个小时,后来因为其他人的 DDOS 攻击让 GHash 的算力降回到 38% 左右。但是不要以为这就安全了,用比特币论文作者 Nakamoto 自己的程序计算,如果有一个算力占 38% 左右的攻击者,一笔交易不被撤销的概率要达到 99.9%, 需要等待它后面的大约 80 个 块被加到链上。即使是在正常情况下,没有数据拥堵,没有恶意攻击,增加 80 个块也需要 14 小时的时间,没有人会等待那么久。也就是说交易者承担很高的风险是比特币网络的常态。

很多人喜欢说区块链是 secured by math,意思是说它的安全性是有数学定理保证的,坚不可破的。让我们先忽略逆向计算哈希函数的难度是个猜想而不是定理这个细节,基于 PoW 的区块链的根本假设是恶意攻击者没法比所有诚实矿工都算得更快,所以它们的安全性是基于经济学而不是数学,然而垄断在市场中并不是异常现象。比特币在发展的过程中由于规模经济的原因(规模越大越容易降低挖矿成本)自然地走向了中心化。 在 2016 年底的时候 75% 的比特币算力来自于新疆的一座建筑,Bitmain 回应质疑时称这座建筑有多个主人,所以并没有一家独大。2017 年中时,三个矿池控制了 50% 的算力,六个矿池控制了 75% 的算力,并且很可能多个大矿池被同样的人实际控制,这么少的人也很容易结成联盟。后来有人提出了用 Proof of Stake (PoS) 来替代 PoW,以解决浪费能源以及算力中心化的问题。PoS 本质上是一种寻租机制,让财富的流动更倾向于集中,所以同样不能防止控制力的中心化。现在加密货币的分布已经非常集中。经济学上用基尼系数来衡量一个社会的财富分布,0 是完全平均,1 是所有财富在一个人手里。 到 2017 年为止比特币和以太坊的基尼系数都在 0.85 到 0.9 之间。中国的基尼系数是 0.422。虽然大家都在抱怨中国社会贫富分化严重,但是其实中国离共产主义比离加密货币的世界还是更近些。

还有个在其他分布式系统里讨论很多,但是在比特币社区很少被谈及的问题是网络分区(network partitioning)。网络分区是指整个网络被暂时分为互不相连的两部分的情况,这在现实中是发生过也会继续发生的事,比如海底光缆故障,或者是某个国家的防火墙暂时切断了国际流量。如果被分隔开的是整个网络的一小部分,比如新西兰到澳大利亚之间的光缆断了,那么这个小的部分(新西兰)会因为缺乏算力而无法确认任何交易,直到重新和外界连接起来。如果是整个网络分成了算力相差不大的两部分,比如中国和其他国家,那么区块链会在这两部分分别有不同的分支。当恢复正常后,就会导致其中较短的分支被丢弃,而此时这个分支很可能已经很长,很多用户以为已经确认的交易会被取消。

除了故障导致的网络分区外,还有人为攻击可以造成类似的效果,这种情况下因为攻击者有明确目的,对受害者往往造成更加恶劣的结果。因为这类攻击通常针对少数节点,所以被称为 月食攻击(eclipse attack)。简单地说,就是恶意节点在区块链网络中利用重连机制把一个或多个节点完全包围,在这种情况下恶意节点可以完全过滤或延迟被攻击的节点收到和发出的所有数据。这是一个很现实的场景,从某家店里偷东西的人并不需要具有攻击整个金融系统的能力。这类攻击不但可以在区块链网络层面进行,也可以在路由和 DNS 层面实现。

一些区块链社区新提出的协议,比如 Algorand 等,开始试图解决区块链的一些弊端。Algorand 通过随机选取少量节点参与共识协议来缓解去中心化和效率之间的矛盾,从而可以防止假共识的出现,可以更有效防止重复消费,但攻击者还是可以推迟甚至在局部阻止共识的达成。Algorand 的论文虽然提供了一些很有意思的想法,但因为全文里充满了各种假设,我对于它在现实中的适用性是有很大怀疑的。互联网离理论模型往往很远,互联网上的系统都运行在一个协议栈上,在上一层协议里是邻居的节点,多半在下一层协议里并不能直接通讯,而要通过多个设备转发。所以现实中的攻击往往来自完全不同的层面,很多理论模型中的假设并不成立。这里只举一个例子,在 Algorand 的众多假设中,其中一条是所有用户的时钟是同步的,作者说只要用 NTP 服务来保证就好了。然而即使你信任所有 NTP 服务器、网络设备制造商、运营商, 远程攻击 NTP 服务,使得一部分节点的时钟发生大范围偏移是一件相对容易的事。通过 DNS 污染让部分节点使用攻击者指定的 NTP 服务器也不困难。此外 Algorand 还要求货币分布足够均匀,绝大部分节点之间的通讯具有强同步性,不能有网络分区等,就不一一细说了。

要不要去中心化?

去中心化好吗?好。

去中心化可行吗?看你愿不愿牺牲其他更好的东西。

比特币可以说是被一种意识形态创造和推动发展的。在比特币诞生之初的阶段,很多人参与和支持它的发展是因为他们认为自由是至上的,政府是邪恶的;集中导致腐败,所以去中心化是好的,货币应该和政府分离。

从技术人的角度,对于去中心化的系统会有一种痴迷,因为对称的结构确实总是显得很优雅,也不会因为单点的问题导致整个系统的失败。然而正如上面所说,一旦加入在互联网环境下需要考虑的各种风险,去中心化会让很多看起来简单的事情变得很难、很低效,或者不可能。

就拿自然界的进化来说,最早有神经系统的生物,比如水母,神经系统是网状去中心化的。然而随着生物体越来越复杂,出现了神经中枢、大脑,因为当生物要完成更加复杂的行为,在竞争中建立优势,就需要把整个身体收集到的信息集中到一个器官来处理,进化过程也产生了特殊的骨骼结构来保护这个核心器官。

人类社会的发展历程也可以看作是一个逐步形成中心化组织的过程。人类之所以成为地球的主宰,是因为他们掌握了灵活地进行大规模协作的能力。其他动物的协作方式只能通过进化的缓慢过程来改变。而人类在短短几千年里通过建立部落、国家、公司等多种不同的组织形式来达到分解和处理复杂问题的目的。当然,后来人类发现中心化的组织虽然效率高,但是一旦中心机构失败就会影响整体,所以发明了民主制度来平衡权力集中带来的问题。一定程度上可以把民主制度看作一种在中心节点失败时重新进行选举的机制,而这个机制本身也需要中心化的组织来执行,所以现代国家一般都会有多个中心化组织的相互制衡,当这种制衡失效的时候,民主机制也往往随之失效。

另外对于基于区块链的去中心化的系统来说,每次有人想要对协议进行改动都会产生分支:第一,因为难以让所有人都认可要做的改动;第二,因为无法协调所有节点同时切换到新的协议。每次有改动几乎必然会产生一个新的分支,时间一久这也是一个很大的问题。

在其他因素不变的情况下,去中心是一个很有益的性质,然而它不是一个独立的变量。在计算和通讯技术没有突破性的发展之前,难以在互联网环境下实现大规模的高效、安全、可靠的去中心化系统。比特币、以太坊和目前主流的区块链在设计上选择了完全去中心化,所以每秒能处理的交易量基本都在个位数或小几十,安全性如本文所说存在着很大的问号,去中心化也因为规模效应被破坏。在去中心化的假设下设计的系统由于原来的假设不成立而变得中心化以后,意味着这些中心得不到应有的监管和保护,结果往往是集两者缺点于一身。

尽管传统的机构和组织存在着各种各样的问题,但区块链的原理和设计假设难以说服我基于它的大规模去中心化系统会比受到监管、保护、制衡的中心机构更加可靠。我认为区块链未来在一些特定领域可能会成为创造出很高实际价值的工具,但是成功的系统会是多个设计维度平衡妥协的结果。对于去中心化有过于浪漫的想法,或者认为区块链会像互联网一样改变一切的人恐怕是会失望的。如果一个区块链的项目说他们在做一个完全去中心化,并且可以安全可靠地每秒处理十万交易的平台,请牢记一句被证明了无数遍的话:

If something is too good to be true, it is too good to be true.

目前试图提高区块链效率的项目几乎全是通过在一定程度上放弃去中心化来换取效率(我知道有人要举 Lightning 作为反例,这个话题太大,请参考 这篇别人的文章吧),而对很多应用场景来说这又有违使用区块链的初衷,并且一旦削弱了对去中心化的要求,往往会有其它更加简单可靠的方案。具体应用场景的话题就留待下一篇吧。智能合约也是一个很大的话题,我也计划单独用一篇文章来探讨。


目录