谈asch系统的共识机制与容错性

本文章出自:http://blog.asch.so/,转载请注明出处。

0 前言

我曾分析了DPOS算法的漏洞而且模拟了一个简单的攻击的方法,而后实现了一个简化的PBFT算法模型试图去修复该漏洞,而且对比了效果。javascript


随后在正式的产品中实现了完整版的算法,而且部署了10台机器进行了测试。测试的结果在安全性方面彻底符合预期,即通过频繁的重启、不按常规的广播区块、少数受托人联合做弊的状况下,整个系统依然不会分叉;可是在性能方面,不太理想,在没有任何交易的状况下,网路流量的峰值(广播区块的瞬间)达到了1.5Mbps。java


其实这个流量也不算离谱,为了安全性,付出一些带宽的代价也算合理,但咱们认为还有很大的优化空间,并且asch做为一个开发平台,平台底层的效率和稳定性是很重要的,带宽方面的优化是颇有必要的,咱们马上着手去作了。截止到8月9号,系统已升级到0.9.5版本,在49个节点组成的testnet中,带宽的峰值在600kbps左右。
带宽统计
下面咱们会对比下这几个版本共识算法的差别和基本原理。为了方便起见,咱们把最初实现的dpos with pbft算法称为AC0.5(AC即asch consensus),优化后的版本称为AC1.0。git

1 AC0.5与DPOS

咱们以前分析过,DPOS的主要问题在于受托人的权力太高,而其余节点对区块的有效性验证过于简单,这就很容形成一个局面,即不一样内容、但相同高度的区块共存于网络中的不一样节点,也就是所谓的分叉,进而形成双重支付。github


PBFT算法的本质则是让每个节点都尽量知道其余节点的决策,并以此来肯定本身的决策。算法


所以,PBFT带来额外的流量消耗就能够理解了,其根源也找到了。在AC0.5算法中,这个额外的流量或者说“其余节点的决策”指的就是每一个节点对下一个区块的投票信息,投票信息主要内容有4个部分,即区块高度、区块ID、签名、公钥,其中区块高度和区块ID的长度能够忽略不计,签名的长度为64字节,公钥的长度为32字节,一个区块达成共识须要所有受托人总数的2/3的投票,在asch系统中受托人总数为101人,也就是说须要至少67个投票。一个区块的大小大约是200字节,至关于2个投票的大小,所以AC0.5中流量消耗是原始DPOS的30多倍(在没有交易的空block状况下,若是有交易则交易不会消耗额外的流量)。json

2 AC1.0作了哪些改进

2.1 序列化方法

AC0.5中服务器之间的消息传递使用json格式,二进制字段则是转化为hex编码后再进行传输,投票中的二进制字段包括公钥和签名,以前咱们算的是100字节,转化为hex编码后则翻1倍,变成200字节了。安全


另外json的字段信息和冗余的分隔符所占的字节数也很多。服务器


AC1.0对这一点作了改进,使用了protobuf做为序列化方法,效果很不错,带宽降为原来的60%左右。网络

consensus proto

2.2 算法流程

AC0.5的流程为数据结构

  1. 广播一个待确认区块

  2. 收集选票(以广播的形式)

  3. 收集确认信息(以广播的形式)

  4. 确认区块

AC1.0的流程为

  1. propose (广播一个区块的元信息及当前generator的ip信息)

  2. collect votes (其余节点采用一对一的方式直接将选票发送给当前generator)

  3. commit and broadcast(广播一个已经确认的区块并携带投票信息)

经过对比能够发现,AC0.5须要三次广播,AC1.0仅须要两次广播,而且在propose环节,只广播了区块的元信息,不包括交易信息,只广播元信息有个好处,能够防止在区块没法达成共识的状况下白白浪费流量,由于若是连元信息都没法经过,那就不必广播交易信息了。

2.3 广播协议

AC0.5使用的广播协议为最朴素也最粗暴的gossip算法,即随机选取必定数量的相邻节点而后将消息广播给它们, 这个必定数量固定为100. 任何一个节点在收到一条信息后,会计算这个消息的hash,若是发现没有收到过,就会继续广播给它的相邻节点。也就是说一轮广播须要进行100 * N次通信,在N小于100的状况下,至关于复杂度为O(N^2), 在这里N为整个网络的节点个数。

 

AC1.0把这个固定数量改成sqrt(N), 也就是说假若有100个节点,每一个节点只须要广播给10个相邻节点。


这个改动很小,可是参数的设置倒是很是须要经验的,咱们作过了大量的测试后,认为sqrt(N)能够达到比较理想的效果,一次广播须要的通信次数略高于N * sqrt(N)。

 

除此以外,咱们还实现了一个基于一致性哈希的广播算法,性能达到了极致,算法复杂度下降到了O(N), 可是这个算法须要更多的测试,其稳定性和可靠性也不如更简单的随机算法。


算法的demo版本在这里,有兴趣的能够研究下。
gossip topology

3 容错性

关于容错性,我认为能够从内因和外因两个方面来讲。

 

从内因的角度来讲,系统应该能容忍正常节点出错,这些错误主要是指服务器宕机、硬件错误、网络拥塞等。Asch系统可以容忍最多1/3的受托人节点同时出错,假如某个受托人的节点出错了,那轮到该受托人生产区块的时候,就会缺失一个,并顺延到下一个10秒。假如超过1/3节点同时出错,那么系统将暂停工做,等到足够的节点恢复正常后,系统就能够当即恢复正常。


假如1/3以上的节点永远没法恢复(这种状况是存在的,好比他们的密钥丢了),那么系统必需要经过一次软件升级来恢复,而且这个升级不强制全部节点执行,只要部分节点升级,区块生产恢复正常后,经过受托人投票把那些不正常的节点撤销掉,系统就恢复如常了。

 

从外因的角度来讲,系统应该可以容忍黑客攻击、受托人做弊的状况。这里的黑客攻击不是说DDOS,DDOS形成的后果最可能是部分服务器宕机,咱们已经归到内因里去了,这里的黑客攻击主要是指经过入侵拿到部分受托人密钥并获取权限,而后利用这些权限获利。获利的手段无非是广播多个版本的区块,在短期内形成分叉,而后进行双重支付。在asch系统中,黑客必需要同时得到1/3以上节点的密钥,才可以发动连续攻击,使网络的分叉持续下去,不然系统将经过最长链同步算法迅速消除分叉,分叉之间的差距不会超过1个区块高度,也就是说2次确认以上的交易基本上不可能被回滚了。

 

从现有的使用DPOS算法的系统来看,包括bitshares、crypti、lisk在内,这些系统出现的分叉都是内因形成的,甚至大多数是算法实现上的bug所致使的。黑客攻击DPOS的案例尚未据说过,虽然存在理论上的漏洞,但要想真正的攻击,须要高超的技术和昂贵的资源,成本和收益不对等,所以也不会有人去攻击,当一个DPOS系统的市值慢慢增大,咱们能够继续提升受托人节点的数量,进一步提升攻击的成本,所以外因的风险基本能够忽略。

 

最后,我想解释一下分叉这个词,分叉来源于英文的fork,fork根据上下文的不一样,我认为能够翻译成两种意思,一个是分叉,另外一个是分裂。


分叉指的是在社区成员团结一致的状况下系统由于bug或被攻击形成的不一致性,而分裂是指社区成员因观念分化形成软件走向不一样的方向。
分叉强调的是系统的bug和不一致性,强调了物的因素,分叉后系统可能仍是一个系统,而且是极可能被复原的;而分裂则是强调了人为的因素,一旦社区分裂,则系统一分为二,变成两个系统。


从这个角度来讲,asch对于分叉能够作到事前的预防和过后的修复,但没法应对社区的分裂,任何一个区块链系统也没法解决分裂的问题,包括比特币和任何一个声称能够避免分叉的PBFT系统。

相关文章
相关标签/搜索