关于共识机制的讨论已经有许多,但这些分析大多不全。在碳链价值举办的「碳话」线下沙龙第一期活动中,Conflux研究总监杨光博士用一万三千余字,全面分析了POW与POS共识机制的原理、运行时遇到的问题,以及两者的优劣比较。
首先给大家简单介绍一下我们的 Conflux 团队:我们团队的核心是姚班的几个同学以及师弟,并且有幸请到姚期智先生担任我们的首席科学家和顾问。我们之所以投入到区块链这个行业中来,是因为这个行业里边有很多非常重要也很有意义的新问题——以我最熟悉的密码学和博弈论为例,区块链面对的和要解决的很多问题已经是学术界最前沿的研究方向了。这些问题不是单靠工程师就可以解决的,而是需要更多学术界的力量参与进来,大家一起合作才能推动整个区块链行业往前发展得更好。
1. 女巫攻击与区块链共识协议
今天我来讲一下 PoW 和 PoS 的对比。我们先来回顾一下最典型的区块链共识协议:大家把交易打包成块,通过哈希引用把块连接成一条链,就得到了一个共享的账本。但是直接这样用一个账本肯定是很不安全的,因为坏人也可以造一个账本,然后把两个账本同时摆在你面前,哪个是真的哪个是假的,我们应该相信哪一个,这就成了一个问题。
如果是中心化的,当然这个问题非常好解决——我用支付宝,支付宝说我账户有多少钱,那就是多少钱。如果和事实不一致的话,我有不同意见可以去法院告他。但如果是去中心化的,这件事就很难说了。去中心化的时候,大家没有一个这样一锤定音的机构,需要通过其他方式达成共识,才能有一个公正的账本。那么在去中心化的环境下,应该怎样做共识呢?一个很容易想到的办法就是我们投票,大家共同投票,投出来一个账本,然后都相信这个就行。
但是,既然说到投票,那么首先就有一个投票的公平性问题:投票权要怎么分配?比如今天我们大家一起投票,然后我手里有一百票,在坐的各位每人一票,我们这个不叫投票,我有一百票,基本上我说什么想投什么,结果就是什么样的。如果我们真的想达到一个共识,就不可能用这种特别不公平的方式去投票。所以投票权的分配是共识协议里面最核心最重要的部分之一。在线下投票权分配的问题其实比较容易解决:我们就简单的一人一票即可。大家都有身份证,然后投票的时候登记一下就行了。但是线上的话,要想实现一人一票就非常困难。
首先,你在线上的环境中,特别是去中心化的环境中,如何定义「什么叫做一个人」,这就是一个很大的问题。你是把一个账户当一个人还是一个ip当一个人,还是说你用别的什么方法去确定?在网上的话,大家都是以匿名的方式存在的,你在聊天的时候,你甚至都无法判断网络另一边跟你聊天的到底是一个抠脚大汉还是一条狗。因此,我们就需要一个抗女巫攻击的机制。
我们先简单讲一下什么是女巫攻击:它是说攻击者可以低成本地制造很多账户,然后控制这些账户一块儿去行动,让别人看上去以为人多势众的样子。 比如说在论坛上大家会见到有水军引导舆论,再比如电影评分的网站也会有人专门去组织去在上面刷评论刷分。如果说有很多这种水军马甲的账号在攻击的话,你最后投票得到的结果就不是真实的。有可能某个人通过这种方式投出非常多的票,最后投票的结果就是完全受这一个人控制的。在传统的互联网环境下,我们有很多对抗女巫攻击的方式,比如增加每个账户的注册成本。大家在网上要注册一个账号的时候,常常需要输入一个验证码,这件事就是计算机实现起来比较麻烦,即使能写程序做也比较困难,但人去做的话就很简单;还有的网站注册的时候要求绑定一个手机号,或者检测ip地址,这都是比较常见的抗女巫攻击的方式。但是在去中心化的环境下,以上那些方式就不好用了。因为去中心化的环境下,谁去发布这个验证码,谁去判断验证码填得对不对?然后谁去验证手机号?即使用ip地址的话,其实也是一个非常不公平的方式。因为我们知道并不是每个人都平等地享有一个静态的ip地址的。
所以在区块链中,我们实际上用到的解决方案最常见的就是一个工作量证明(PoW),一个是权益证明(PoS),后者包括代理的权益证明(DPoS)。还有一些其他的证明方式,比如说证明你拥有多少空间,或者证明你燃烧了多少货币,还有别的一些方法,但是目前最主要最常见的还是 PoW 和 PoS 这两种。这里我还要稍微强调一下,无论 PoW 还是 PoS 或者别的什么 PoX,都是抗女巫攻击的机制,是共识算法(协议)里边一个重要的组成部分,但它们本身不等价于共识算法。
2. 工作量证明
接下来我先讲一下大家都比较熟悉的工作量证明。
工作量证明的基本思想就是算力决定出块权。如果你能解出一个 PoW 计算难题,你就可以出块。粗糙地概括下,可以理解为一个CPU一票,或者一个GPU、一台矿机一票,大概是这么个意思。它的好处首先是这个系统是无许可的。参与者不需要任何人许可,只要有机器有算力就可以参与——理论上甚至都不一定需要机器。如果说你可以手动算出一个区块的哈希,并及时把这个上传上去,别人也会承认这是一个合法的区块。还有一个是PoW投票行为本身成本是比较高的,不管用CPU、GPU还是用矿机,机器的成本和电力的成本,都是要实打实地花出去的。这就跟我们之前说的验证码,其实形式上有一点像,对吧?有一些验证码,人看了以后还是要花一点时间去识别里边的数字或者字母到底是什么,然后才能打上去通过验证。工作量证明一个最大的优点,我认为就是所投的票和投票权是绑定的:一旦投票成功以后,即使是投票者本人也修改不了投票的内容。
按照工作量证明的一般逻辑,投票的时候需要先打包出一个块,然后再对这个块做工作量证明,如果做出来证明就相当于投出去一票,但是这个时候打包的块已经没有办法修改了。例如我的矿机跑一天可以投出很多票,但是如果我想把之前一天的算力集中到新的一个块上,这是办不到的;另一方面,如果我想要回滚掉自己出的块,我也必须付出和回滚别人的块时候所需的同等的算力。这是PoW一个特别好的特点。
当然基于PoW机制去做共识算法也有一些缺点。首先这个缺点就是延迟比较高,因为我们把交易打包到区块以后,这个区块不是马上就成为一个有效的候选区块的,至少还要完成一个工作量证明这个区块才能称为候选区块。这里工作量证明的时间不能设得特别短,等一下我会讲为什么不能太短。于是,至少从打包好区块到做完区块的工作量证明这一段时间内,你这个交易是不可能被人确认的。所以说即便比特币不是等六个块确认,而是看到一个块就确认,确认一笔交易平均也要等十分钟时间。PoW机制另一个被人诟病的点就是能耗特别高、不环保。对于这一点,工作量证明的能耗是否必要,我觉得是见仁见智的,可以持保留意见。但是我们既然是在谈工作量证明,那么这个工作量怎么也是没办法省掉的,如果省掉的话它就叫别的名了。
我们看一下如何解决基于PoW的共识的主要问题。
第一个是说确认速度慢。以比特币为例,出一个块平均要十分钟,确认的话还要再等六个块,就平均要一个小时。第二个是吞吐量比较低,大家都很清楚,比特币在这点上已经被人批评好几年了。然后第三点就是能耗高不环保。但是第三点,既然我们要用PoW,这点能耗是避免不了的,所以我们也就不想着去解决这个问题了。
对前面两个问题,确认速度慢和吞吐量低。其实这两个问题看上去都有一个很简单的解决方法——降低PoW问题的目标难度,提高出块速度。实际上莱特币就是这么做的。它把目标难度从比特币的10分钟降到2.5分钟,然后一下子出块速度就比特币快四倍。还有一个提高吞吐量的方法就是增大块容量,比如BCH就把每个块从1M先扩大到8M,然后又扩大到32M,甚至后来还有提议说要改到128M。很直观地,同样的出块速度下,块越大吞吐量也就越大。
是不是这么简单就可以解决比特币确认速度慢和存储量低的问题呢?当然不会。要真这么简单的话,比特币也不会现在是十分钟1M的设定了。为什么刚才说的方法不能解决问题呢?因为当我们出块速度快了以后,区块链就会很频繁地出现分叉,特别是当你出块的速度超过广播速度的时候,分叉的情况就会特别严重。
如果我们降低PoW问题的难度,提高出块速度,然后增大区块容量,实际上在网络条件一定的情况下,肯定是会降低广播速度的。因为区块越大,广播得就越慢。然后如果说你出块速度快但是广播速度慢,也就是说我在收到别人新出的一个块之前,自己也能挖到一个块,这样的话就会出现分叉。然后如果说这个差距比较大的话,分叉就会特别多。
分叉多了以后有什么不好?最大的不好就是会降低安全性。在比特币里边我们常说坏人攻击需要51%的算力。 这个前提是说好人都集中在一条主链上。这样的话,好人有49%集中在上面,坏人有51%才能攻击。但如果真的出现这种频繁分叉的情况,比如说我在分叉A上有30%的算力,在分叉B上有40%的算力。这个时候坏人想把分叉B给回滚改到分叉A,它不需要很多,它只需要11%算力就可以。只要比全世界的诚实的算力最多的两个分叉之间的差稍微多一点,攻击者就可以让最长链在这两个上面分支上跳来跳去。所以如果真的简单粗暴地去改比特币的参数,最后安全性肯定会降低。
但是我认为这个安全性降低其实不能怪PoW。PoW在这里边只是一个抗女巫攻击的机制,而且它的难度是可以调的。这里安全性降低的罪魁祸首这个锅得让“最长链”而不是PoW去背。为什么会分叉多安全性低?其实是因为比特币采用了最长链共识。在最长链机制下,如果出现分叉,诚实的算力很可能会跟着分叉,也就意味着诚实的人投票就会分叉,这样的话坏人就更容易操纵最后的结果。
然后下一个问题:基于PoW的最长链共识为什么会分叉?是不是说如果大家都是好人,就不会分叉?
这个也不是的。我们用图里边每条线表示是一个节点,向右的这个箭头表示的是时间。当这个节点产生一个区块的时候,它需要把区块广播出去,但是广播出去要消耗时间,所以会形成一个“事件光锥”。距离产生区块的节点越远,收到广播过去的区块所花的时间也越久,相应的要等到更晚的时间以后才能看到刚才生成的新区块。也就是说只有在这个黄色区域及以后其他的节点才能看到你这边产生的一个区块。既然有光锥,相应的也就有光锥外的区域,也就是图上绿色的部分。当一个节点处在这个光锥外区域的时候,他是不可能知道你这边刚刚产生了一个区块的,因为还没有广播过来。也就是说,如果网络里产生的下一个区块是在后边黄色的这部分,那么当然很安全,因为这个时候所有的节点都看到最新的区块了,然后他们再生产区块都会跟在后面就不会出现分叉——如果大家都是好人的话。
但是如果说出块的速度比较快,我在绿色的光锥外区域就产生区块,那就必然会出现分叉,然后最后会出现孤块,对吧?因为这两个区块互相都是不可能引用的。所以简单的来估计一下,孤块率大致是等于光锥外这个区域的面积除以期望的出块间隔的总面积。因为出块的事件在期望的区块间隔内是以相等的概率随机出现的。另一方面,绿色的光锥外区域面积所占的比例越小,就表示出现孤块的可能性就越低。
但实际中我们肯定不会只有四个节点,我们节点会非常多,而节点多了以后,广播的时间自然就会变长。广播的时间变长,就意味着光锥外的区域面积会变大,我们的出块间隔也需要变长,这样才能保证孤块会被控制在一个比较小的范围以内。因为其实孤块本身也是对安全性有影响的,比如有20%的孤块率的话,只需要41%而不是51%的算力就可以完成攻击了。因此,为了提高安全性,为了降低孤块,我们必须拉长出块的间隔。比如比特币就定在了十分钟。这个十分钟当然不是完全不能改的,只是改过以后安全性肯定会受到一点影响。
拉长出块间隔以后,整个系统的效率都会降低,特别是对吞吐量造成的影响很大。我们在这儿看一下整个系统的带宽,其实可以把它分成三部分:一部分带宽(蓝色部分)是大家在传输最终会加到共识里边的交易;还有一部分带宽(红色部分)是大家在传输一些不加入共识的数据,包括整个协议的开销,还有一些可能是最终没有被加入共识的作废的块和交易;最后一部分(白色),就是没有被用到浪费掉的带宽。如果说我们用 PoW 做抗女巫攻击机制,再用最长链的协议去计算最后的共识的话,我们对带宽的利用率其实是非常低的。
以比特币为例,我们600秒产生1MB有效的区块,期望600秒才有1MB有效的这一块,就算我这一个区块再扩大几次,整个网络里面600秒的时间,我有效利用的存储的信息量可能还不到20MB吧?但现在网络的平均速度已经是600秒传几个GB了。所以它对整个网络带宽的利用率也就在1%左右,浪费还是非常严重的。如果说我们用一些技术把广播的速度变快,比如说用致密区块的技术,那么绿色的光锥外的区域这段时间就会变短。这样我们也就可以等比例地把出块间隔也缩短,在保持和之前相同的安全性的同时把带宽的利用提高一点。但是即使是这么提高,只要我们是用最长链并且要控制孤块率,带宽的利用率依然高不到哪儿去。一般来说,一个公链网络可能会有几千甚至上万个节点,如果要广播的话,平均可能要十次甚至更多次转发。以需要十次转发为例,从出块的这个节点开始,发送给下一个节点,然后这个节点接受到区块并且验证过以后再发送给下一个节点,就这种过程要重复十次。在这十次转发的全过程以内,如果我要降低孤块率,就需要全网别的节点不要在这段时间内产生第二个区块,或者说只有很低的概率产生第二个区块。也就是说,这么长的时间,大家其实只在广播一个区块。第一个人传给第二个人以后,第二个人传给第三个人的时候,第一个人就处于一个闲着的状态了,对吧?所以最终的带宽利用率自然不高。可能会比之前有一个常数倍的改进,但也是远远不可能把整个带宽用满的,能用到1/10就已经算很不错了。
既然这样的话,如果说我们想避免分叉,不可避免的带宽就用不满,带宽用不满的话,TPS就不可能高到哪去。因为你一共同步的数据就那么多,那它里边能放的交易就是有一个上限的——如果交易的尺寸不变的话(交易尺寸缩小也是可以提高TPS的,但是其他所有区块链也可以用同样的技术,相对的劣势依然不变)。
其实刚才要解决的问题,就是说出现分叉以后诚实算力不集中,会降低安全性。但这个解决方案并不是说只有降低分叉概率这一种方案去解决。比如我们也可以用基于 DAG 的有向无环图去解决。
以太坊选择分叉的时候用的不是最长链而是 GHOST 协议。其实以太坊用的是一个稍微修改过的版本,这个协议核心思想是遇到分叉时候选择拥有最重子树的分支而不是有最长子链的。这样的话就不管你有没有分叉,有多少分叉,安全性的问题都不大。因为即使是分叉的诚实的矿工,依然会对之前的选择贡献安全性。比如说矿工在靠后的一个区块分叉,但是对于分叉之前的某个地方的分支应该如何选择,矿工依然是贡献安全性的。它会在应该选择的分支的子树上贡献一个重量。
但是 GHOST 协议有一个缺点:虽然说它可以把带宽用得比较充分,但同时浪费也很严重。 因为那些最终没有被确定在最重子树那条链上的区块,它们里面的交易都是不算数的。大家挖到了一些区块,但是最后都没有加入共识,这些区块的吞吐量就被浪费掉了。而我们的Conflux 其实和 GHOST 用了比较相似的方式去确定一条枢轴链,等确定好以后,我们再把所有的区块排一个顺序,这样所有区块里边的交易都会对整个系统的吞吐量作出贡献。当然排过顺序以后,还需要把里边有冲突的或者重复的交易去做一些处理,冲突的交易肯定不能都执行。如果我们从带宽的角度去解释的话, GHOST 这个协议可以把带宽利用得非常好,但它整个系统的开销比较大,因为传输过很多没有被加入共识的区块,会浪费掉一些带宽。
Conflux 虽然说也会有一些重复的交易,但是因为它对整个带宽的利用比较充分,而且在这个前提下,有效的带宽利用率也远比 GHOST 更高,所以就可以把整个系统的吞吐量提高。如果做对比的话,由于比特币的总带宽利用率特别低(~1%),所以即使它再怎么降低协议开销,吞吐量上跟 Conflux 的差距依然非常明显。
这些是关于PoW的一些简单的介绍,下面我们再看一下权益证明。
3. 权益证明(PoS)
权益证明基本的思想是:当你持有币(有时人们也管这个叫 stake),你就有记账权,然后有投票权。你的投票权和你持币的数量是成正比的,这就是一个币一票。简单来说,就是钱越多,投票的权力就越大。
PoS 协议的基本框架是按所有的参与者的持币量,去分配打包权和投票权。在PoS的系统里边打包和投票两件事是分开的,它也可以分开——PoW 系统里这两个其实是一回事儿。分配完打包权以后,拿到打包权的人就有资格出一个候选区块。这个区块里面包含要处理的交易,并且有他自己的签名。候选区块并不意味着就会被加入共识,在广播候选区块以后还需要由那些有投票权的人去投票。
投票的形式可以就是在被投票的区块上做个签名。在投票后得到比较多票支持,候选区块才会最终被加入共识,变成一个有效的区块。当然投票的过程我们可以用很多方式执行,比较常见的就是可以用一个少数服从多数的共识算法去做。因为现在我们知道一共有多少人有资格投票、一共有多少票,所以用这个共识算法我们很容易算出来多数,比如超过1/2或者2/3。这一点跟 PoW 非常不一样,因为在 PoW 系统里你根本不知道全网的算力有多少,只能靠估计,而且一般还估计不准。所以 PoW 系统里不可能说用一个确定的阈值去判断什么是多数。
在去中心化机制中,我们需要选举谁负责打包,谁负责投票。有时候为了效率,大家会先选举一个比较小的委员会,然后由他们负责投票。如果不是用代理权益证明的 DPoS 机制的话,这样的委员会通常是随机选取的,而且为了公平性还要经常轮换。
在 PoS 系统中,如果检测到有的参与者违反了 PoS 共识的协议,就可以对他们做出一些惩罚。比如有的人把自己的一票投给很多个块,或者说他有票,但是就是不投,这些会对系统的安全性造成影响的行为都可以惩罚。
我们再来看一下权益证明的优点是什么。
第一个优点:矿工和持币者的动机是一致的。PoS 的矿工都必须持币,在整个的生态环境里减少了一个不持币但靠机器来挖矿的角色。在 PoW 的社区中,经常会出现有钱人、开发者、以及矿工三方的利益不是完全一致的情况,然后就会吵,以至于最后很多事很难办成。到了PoS 中,现在至少矿工和资本家的利益会更为一致,一定程度上减少了冲突和分歧。
第二个优点:PoS 的延迟可以做得非常低,确认可以非常快。在 PoS 系统里,拿到一个交易就可以马上打包,打包以后就可以广播,这个时间是不需要等待的,不像 PoW,必须等至少做一个 PoW 问题的时间。实际上,PoS 共识的延迟主要是受限于网络和参与投票的人数。因为你投票的人越多,肯定要等的时间也就越久。
第三个优点:PoS 比较环保,因为它不需要做工作量证明。投票实际上就是做个签名,最多再做一些简单的运算,比求解 PoW 难题容易多了。
但它的缺点也是跟上面相对的,PoW 系统的一些优点它失去了。
第一,与无许可的 PoW 系统相比,PoS 的系统在匿名性和许可性上稍微差一些。因为我作为一个人,我要加入一个 PoS 的系统,想进去投票,我首先要持有币。这个币我是不可能通过其他方式得到的,我必须跟已经有币的那些人去做交易,他们把币给我以后我才有权利。这就不像 PoW,只要拿一台机器接入系统,就可以直接挖到币。
第二,投票行为本身成本非常低,只需要做个签名就可以生成一个有效的投票。这样的话在安全性上会有一些问题。比如 PoS 系统常见的无利害攻击问题。
另外,投票权可以复用,可以转让,这也是不好的。如果我把自己的私钥卖给别人,那么我以前投出的那些票,在历史上每个分支做出的选择,这时候拿到我私钥的人,他都可以再去投一遍。可以重复使用以前的投票权会在安全性上带来一些问题。等一会儿我们讲到长程攻击的时候再详细讨论。
还有就是投票机制带来的一些问题。刚刚我们说了 PoS 共识的优势是确认快,可以做到不分叉,但这个不分叉的前提是需要假设大多数节点是诚实的。这里说的有2/3以上的节点诚实,实际上严格来说是要求2/3以上的币和投票权都在诚实的人手里,坏人只有不到1/3的投票权。——这样对于一个得到2/3以上投票的块来说,就算是有一些坏人可以给不同的块投票,他们联合上剩下还没签名的好人,全加在一块也不会超过2/3。这样的话只要有足够多的节点签名,且整个系统里大部分节点都诚实的话,这个系统就完全不会分叉,又可以做得非常快,大家确认得也会很快。例如 EOS 现在就实现了出块很快,确认很快。
但是 PoS 共识的话也有一些新的问题。
第一个就是通讯复杂度跟投票的人数相关,而且通常是平方的关系。参与投票的人数越多,通讯越复杂,然后大家要等的就越久。就像是如果说我们要一人一票选一下美国总统,整个投票的过程就非常复杂非常慢;而政治局里边投票决定一件事就快得多,因为他们人少。
还有一个PoS的共识的比较本质的问题,就是投票权的决定时间是早于生成候选区块的。在有这个区块以前,我就知道谁有投票权、谁没有投票权了。因为投票权的决定方式,所以实际上决定投票权和行使这个权利的动作是分离的,没有绑定在一起的。我拿到投票权的时候,别人谁也没有办法说,就规定我这个票必须投给谁。所以拿到投票权以后,我可以随便地去投,而不会因为我投票的行为决定我有没有投票权。但这样的话投票权使用是更灵活了,也意味着我可以选择的策略空间更大,整个博弈会变得更复杂。通常来说,策略空间大对于安全性是不好的,因为给攻击者留出了更大的操作空间。一个诚实的人通常只会按照规则去,他每一次就确定了做一个动作,但是攻击者如果操作空间大,能干的事儿就很多了,想保证安全性也会变得更难。结果就是在 PoS 系统里面会有更多的攻击方式,比如无利害攻击、长程攻击等。
那么为什么在 PoS 系统里,我们不能像在 PoW 系统里那样,先生成区块,然后再决定投票权呢?因为我们需要确保对投票权大家是有共识的。不管投票者把票投给哪个候选区块,对于谁有权投票,是必须确保所有人都知道的。不然的话就会有可能退化成类似于 PoW 的情况——这个在 PoS 系统里边叫 stake grinding,就是说每次尝试产生很多新的区块,然后从这些区块里挑选对自己最有利的一个广播出去,然后由这个区块去决定后边的投票权。如果真的先出区块,后决定投票权,我们就可能会看到一个分叉分出去若干个分支,然后每一个分支的区块后边都跟着一个亲友团一样的委员会,亲友团里边多数人都说这个区块是对的。但是因为每个区块后边跟着亲友团都不一样,他们再怎么投票也还是达不到整个系统的共识。
还有一个 PoS 共识的问题,就是需要假设大部分节点是诚实的。“诚实”这件事儿一般是在密码学里边提得多一些。但是在博弈论和经济学里面,很少会说一个人是诚实的,更多是说一个人是理性的——如果说谎可以多赚钱,很多人会选择说谎。所以说,如果假设这些节点都是诚实的,实际上是一个非常强的假设。意味着他们即使能够通过说谎、通过做恶多赚钱,也依然会选择遵守协议。这点还需要看具体协议,对诚实要求到什么程度,才能知道它是不是一个合理的假设。
下面我来讲讲如何解决 PoS 共识带来的这些新的问题。
第一个是说通讯复杂度很高的问题,这个其实是最容易解决的。大家可以随机选取出一个比较小的委员会,由这些人作为代表负责投票,或者也可以用代理投票,就是我把我的票先投票去选一个代表,例如 EOS 里边的超级节点,然后这些选上的代表再代替我去投票。这样的好处就是实际参与出块共识投票的人数比较少,可以降低投票的复杂度。现实中的人民代表大会、国外的议会或者陪审团,都是用到了类似的逻辑。
然后如何对抗攻击呢?一个方式是我们假设大多数人都是诚实的,再假设网络有非常好的同步性——即广播出去一个区块以后,在一段确定的时间内,比如说一分钟或者30秒内,整个网络绝大部分节点都可以收到。在这个前提下就非常容易做到共识。但是这样的假设实际上是非常强的,现实中并不容易保证。如果说我们要解决某一个攻击的问题的时候,直接假设这个攻击不存在,然后问题解决了,这肯定不是一个让人信服的方法。
我们再来讨论一下几种比较常见的针对 PoS 系统的攻击方式。
第一个是无利害攻击,其实也就是一票多投。如果说在一个 PoW 的系统里边,矿工看到有两个区块这样的分叉,他的算力只能跟在一个后面去挖,不可能同时在两个后面。当然真要同时挖两个块的话也不是不行,只是那样就意味着分配到每个块上的算力肯定是要减少的,两边挖矿的算力加在一起是一个定值,所以一般不会有人这么干。在PoS的系统里边就不一样了:我看见左边有一个分叉,好,我给他投一票;看见右边有一个分叉,我又投一票。这样不管哪个分叉称为共识,我都可以分到投票的奖励。这样的话坏人就很开心。坏人说反正我做一个分叉,你们这些理性的矿工也都会给我投票,那么我只要比剩下那些“不那么理性的好人”掌握的投票权多一点就可以把之前的主链给回滚掉。这样的话就很不安全。
对于无利害攻击,常见的对抗方式是说一旦检测到这种一票多投的行为,就对这种人做出一个惩罚。你如果真的一票多投,别人可以拿到你投票的信息,然后提交到链上,说“这个人一票多投了,扣他钱”。但是这种方法实际上也可能会遇到一些问题,就是有可能会出现我在两边一票多投了,但是最后只在一边会被扣钱,但在另一边有可能会得到更大的收益。
还有一个是贿赂攻击。投票的时候,大部分参与者实际上都更接近理性人。比如说你持有一百块钱,每次投票的收益是一块钱,然后我跟你说只要你把票投给我的这个区块,我就给你两块钱。可能很多人都会接受我的提议。这样的话,坏人可以用非常低的成本,去买到更多的票支持自己的分支,比如说用两块钱买到相当于一百块钱资产的投票权。这肯定会对安全性造成影响。现在对贿赂的问题已经有一些解决方案了,虽然还不是特别完美,但是已经比较让人信服了。比如像 Algorand 提出解决的方案,就是投票权的分配是通过私有的随机数去算的。在投票者把这个投票权的证明公开出来以前,大家都不知道到底哪些人有投票权。这样的话,至少在投票之前不会有人知道我有投票权,他们也没办法来贿赂我。公开投票以后,因为 Algorand 的方式是每完成一轮投票就把委员会所有的人全都换一遍,然后重新选一批人去投票,所以在别人知道我有投票权的时候我的票已经投出去了,没办法再去贿赂去修改了。这里对共识参与者的诚实性有一个比较高的假设:不能说我有投票权以后就跑到网上到处问,我有哪些轮次的投票权,有没有人要出钱买。现实中如果真的有人大规模的去问这件事,其实很容易被社区发现,大家就会知道有人在做这种攻击了,也就比较容易做出应对。所以这至少是一个降低被攻击风险的方法。
还有一个是关于长程攻击的安全性。这个说的是什么呢?就是说A在创世区块有20%的币或者20%的股权,他就可以在正常的区块上出块去投票。然而,A可以在某个时间把他在链上的币全都卖掉,也就是套现跑路。现在他在链上没有任何钱,以后别人不可能在链上惩罚他。这时候他把自己的私钥卖给攻击者。攻击者可以去收购A的,B的、C的、很多人的很多私钥。收购到那些私钥以后,这些私钥在创世块里面控制的权利可能是超过50%的,甚至超过80%都有可能。然后攻击者拿到这些私钥以后再做出一个恶意区块,代替A,B,C 他们各投一票支持恶意区块。
在第三方看来,这个区块和真正的主链区块看上去都是同样合法的,因为都有很多人去投票。如果坏人的这条链足够长,以后新加入的人会发现现在有两条链,每一条都是有很多人投票投出来的,我该信哪一个?这时候共识已经出现问题了。所以怎么应对这种攻击呢?一种方法是说要保证一个弱活跃性,即要求每一个诚实的矿工至少隔一段时间就上去看看,同步一下最新的状态。如果有人告诉你说你那个状态不对,应该从一年前的某一个状态分叉过来,通常来说你不应该接受这样的一个建议,因为回滚的时间太久了。
还有一个方式就是锁定押金,然后再加上回滚的长度限制。以太坊的 Casper PoS 协议里边就是这么设置的。如果你非要把用于投票的钱卖掉,可以,但你必须要等一段时间。这个时间足够久,久到等其他的人再看到你用之前的投票权去投票的时候已经不会承认了。因为别的人已经跟着合法的链往后走很远了。这个是以太坊的解决方案。
Algorand 在这一点上解决的方案是,既然你们是诚实的,作为一个诚实的人,你每一轮投票以后,你应该把当轮投票用的私钥删掉,在你删掉了以后,就不会有人再拿这个私钥去干坏事。这个解决方案说得没错,但是它对参与者的道德水平提出了比较高的要求。
基于 PoS 的共识系统还有一些其他问题。通常我们如果选择一个小的委员会,如果不用 DPoS 的话,在 PoS 系统里我们需要随机地去选。PoW 投票里的随机性主要是由大家分布式并行挖矿时候的运气带来的,因为求解 PoW 问题本身有内在的随机性。但如果说我们要用随机性去选择一个投票委员会的话,就又要解决一个新的问题:怎么样去产生一个公平的随机数?
如何产生公平的随机数在密码学上也是一个讨论了很多年的问题,目前也有相对比较好的方案去解决。这个方案虽说不能产生绝对均匀的完美的随机数,但偏差可以控制到一个范围以内。另一方面,产生完全均匀的完美的随机数是很难办到的。因为我们知道,如果有 2/3 以上的币攻击者就可以完全控制整条链,产生的随机数也可以随便挑。所以你如果有 67% 的币就可以控制百分之百的随机数,那么有10%的币能控制个 11% 的随机数听起来也不是特别不可接受。其实基于 PoW 的比特币也有类似的性质:比如说有 51% 的算力就可以控制链上百分之百的收益;少一些的话,实际上有百分之二十几算力就可以通过自私挖矿,获得比实际算力所占的百分比高一点的收益。这是一个非线性的关系,但是只要它不是偏离得太多,大家一般还是勉强可以接受。
PoS 共识的安全性假设是比 PoW 要强的。PoW 我们要求是要有51%以上的诚实算力,PoS的 Algorand 他们对 Staker 的要求是 80% 以上的钱控制在诚实的人手里,而且这些人需要非常诚实:他们不会提前告诉别人自己有投票权;投票以后要把当轮的私钥删掉,不能卖给别人;而且他们还必须定期上线去同步一下状态,算一下接下来的一段时间内自己是不是有投票权,如果有的话还要按时上线投票。如果像我们现在很多人那样,钱存在银行后就不管了,不到花钱的时候就不会去登录系统,那么坏人只要在最后实际投票的活跃的人里边超过一定的比例就可以了。不活跃不投票的人实际上不对安全性产生任何贡献。当然即使一般的 PoS 至少也会要求 2/3 以上的多数钱是掌握在的诚实的人手里,而且还要有一定的对于活跃性的假设或者说要求。至少诚实的人要经常上线去看一下,去投个票什么的。
另外,基于 PoS 共识的系统在启动的时候会有一些问题。因为一个项目往往刚开始启动的时候,是它的资产分布的最不去中心化的时候。就像比特币刚开始的时候,中本聪会有很多的币。如果是 PoS 的系统,他一个人就可以完全控制整个系统。其他项目的开发团队以及早期的几个大的投资机构,可能就已经拿到大部分的币了,他们对 PoS 的话语权会变得非常非常大。所以如何启动一个 PoS 的公链也是一个比较大的问题。EOS 启动前也是花了很久时间才做得比较好的。所以对于这一点,我们团队认为至少在项目启动的时候,用 PoW 是比 PoS 要方便很多的。PoW 方式才能做到无许可,然后一开始的币在发行的时候也会比较公平。
最后,虽然 PoS 可以检查一些违规行为,然后在链上对这些人做惩罚,但是有可能攻击者的利益并不全在链上,他在链下还有其他的收益。比如说我在以太坊上发起攻击,在上面被惩罚损失很多以太币;但是同时币价也很可能会降低,如果我在另外的市场做空以太币,就可以通过做空得到更高的收益。这样的话,链外的动机会导致一些在链上有很多钱的人依然有动力去攻击这条链。这也是 PoS 比较难解决的一个问题。
4. PoW VS. PoS
我们最后简单看一下基于 PoW 和 PoS 机制的共识的比较。
一个是准入机制。即它到底是不是有许可的?投票是不是匿名的?参与的人数有没有限制?投票的形式是并行还是要通过广播的方式?还有一个投票结果确认的方式?投票的边际成本?
一个是安全性。我觉得最大的两个区别就是先有投票权,还是先有候选区块?投票行为和投票权利是不是绑定的?从这些角度上看,PoW 在安全性方面做得比较好。
但是,PoW 的投票结果需要等一个分支上累积的优势足够大才能确认,所以其实不是等一个块,他还要再等诚实的算力集中在这一块后面工作一段时间以后才能确认。因此 PoW 系统只能说通过一些优化把确认速度尽可能加快,但是很难做到像有的 PoS 那样秒级确认。
说到投票的边际成本,因为要有机器和电费,PoW 是没办法避免的。但其他的方面做得都比较好。相对的,PoS 在性能方面做得比较好,主要差在安全性上。就是因为它先决定了投票权,所以大家拿着这个投票权可以随便投。而且你投过一次票以后还可以拿着这个权利再投。至于 PoS 其他的一些问题,实际上我们用委员会或者用代理的权益证明都可以把那些问题减轻或者解决掉,只有投票权的问题很难解决。投票权和投票行为不绑定的问题是 PoS 的一个本质难题。
PoW 的缺点是确认慢,吞吐量一般会相对比较低一点。PoS 主要缺点是要考虑如何应对贿赂攻击、长程攻击、无利害攻击等各种攻击手段。为了应对这些攻击,PoS 的协议就要处理很多情况,于是就会变得比较复杂。众所周知,越复杂的系统的安全性也越难保证,一方面是分析证明起来会更困难,另一方面是攻击者也更容易在复杂的系统找到漏洞。
还有一种现在可能用的还不是很多的方式是 PoW 和 PoS 混合在一起做共识。因为 PoW 的优点主要就是安全可靠,而 PoS 的优点是效率高,特别是确认快,而且能耗比较低。如果能把这两个的优点结合在一起,就有可能设计出一个更理想的共识协议。同时大家还可以考虑用 DAG 的方式而不是链的方式组织区块。因为 DAG 的方式不怕分叉,不需要过分限制出块速度,所以大家可以出块出得比较快,只要带宽能同步就可以。
当吞吐量做到带宽和网络容量的上限以后,如果要进一步的扩容,就需要从其他方面动脑筋了。一个比较简单的思路是采用第二层的扩容方案:每笔交易不要传到全网去验证,比如像sharding,一个交易只在 shard 内部局部地验证,这样的话就可以节省全网的带宽,提高整个系统吞吐量。闪电网络也用到了类似的逻辑。另外一种比较难的方式要用到一些“黑科技”,比如可验证计算、简短的零知识证明、概率可验证证明等等,这里不展开讲了。
但设计 PoW 和 PoS 混合的系统最难的一点是怎么样把两者的优势结合在一起,而不是把它们的劣势结合在一起。我听说过有一些设计是先用 PoW 的方式挖到一个票,然后用这个票去对候选区块进行投票。在我看来这种方式就不是很好,因为它放弃了 PoW 投票和投票权绑定的优势,安全性更接近于 PoS 系统。
如果能把 PoW 和 PoS 的优势结合起来,就有可能做到一个安全性又高,确认又快,吞吐量大,而且能耗还比较合理的系统。目前为止我还没有看到特别好的解决方案,期待以后能出现这样一个完美的解决方案。