上一期《最重链规则的优势与隐患》,我们介绍了最重链规则在缩短确认时间这件事情上的强大潜力。
但其中我们也提到了,在最重链规则判断一个区块是否被确认时,前提条件之一是这个区块是“公共祖先”(注:如果诚实矿工认同一个区块在自己的主链中,那么我们就称这个是所有诚实矿工的“公共祖先”)。
在树图结构中,我们不要求待确认区块是公共祖先,但要求待确认区块所在epoch中的主链区块是公共祖先。
以太坊采用了最重链规则的一个变种,我们就将以太坊当做最重链规则一个实际部署的例子。
在以太坊中,我们可以看到,多数区块都进入了主链,然后只需等待几分钟甚至更短的时间,所有新生成的诚实区块都会出现在这个区块的子树中。也就是说,这个区块成为了公共祖先。然后所有新的诚实区块齐心协力增加它的子树权重。使得占有少数算力的攻击者无法再“扶植”一个兄弟作为竞争者。
公共祖先区块积累了足够的优势后,这个区块就被确认了。
在 Conflux 的实验中,在没有攻击的情况下,每个区块可以在十秒左右内就成为公共祖先,或者进入到公共祖先的 epoch 中。如果出块速度很快的话,再过很短的时间就可以确认了。
看似一切都很美好,然而,一些攻击策略可以阻止新的区块成为“公共祖先”。也就是说,对于已经成为公共祖先、已经确认的区块,攻击者是没有能力逆转的。
然而,攻击者有能力让诚实的节点对下一个公共祖先区块是谁,达不成统一意见,从而使诚实节点陷入旷日持久的“王储之争”。之后任何一个新生成的区块都无法得到全体诚实节点的确认。
这种不以双花已确认交易为目的,以阻止新的交易被确认为目的的攻击,我们称为“存活性攻击”。
到目前为止,被公开讨论的比较多的有一种存活性工具策略,我们称之为“平衡攻击”。
平衡攻击的思想很简单,就是攻击者在最后一个公共祖先区块下面,“扶植”两个势均力敌的孩子,即尝试维护 2 个大小相同的子树。
攻击者通过对区块网络传输的影响,让差不多一半的算力贡献在其中一棵子树上,另一半算力贡献在另一棵子树上。
如果两棵子树上的算力很接近但不完全相等,攻击者可以使用自己的算力来平衡这种差距,最终实现两棵子树上的算力均等。
而被分成两部分的诚实算力,就变成了对立的两个阵营。
两棵大小差不多的子树,以相同的平均速度增长子树权重。
在攻击者的刻意影响下,每个区块生成以后,会在很短的时间内被自己阵营的节点看到,但是需要过一段时间才能被另一个阵营的节点看到,每一个阵营都觉得自己的子树权重略微大一些,然后在自己阵营的子树上继续贡献算力。
这就是攻击者制造的一个困局。
如果攻击者只平衡两棵子树的算力和网络,不进行“藏块”的操作,诚实节点还是有能力打破这个困局的。
因为挖矿的过程总有一些随机性,其中一个阵营在一段时间内挖出的区块会多一些。
然而,假设网络中平均有 n 个区块处于正在广播、但还没有传遍所有节点的状态,诚实节点自己打破这个困局需要的时间是 n 平方。
在给定的网络延迟下,每加快一倍的出块速度,n 相应地也会翻倍,而诚实节点自行打破困局的时间就会成平方量级上升。
而如果攻击者还会在每个分支上挖一些块藏起来,那么每次诚实节点即将打破困局的时候,攻击者可以“主动干预”,放出一些藏在弱势分支上的区块,来继续维持平衡(就像三国杀里的内奸一样)。
通过一些分析可以得到,在出块速度足够快的时候,哪怕算力很小的攻击者,都有一定的概率让诚实节点永远无法打破这个困局。
而作为共识机制的设计者,这个问题应当怎么解决?
很简单,像比特币那样,让出块速度慢下来,让n的数值减小。如果将一个块传遍全网需要10秒,出块时间是10分钟,在攻击者没有进行“藏块”操作的时候,一个新的诚实区块在生成时,有59/60的概率,网络中是没有其他区块在传输的,所有诚实节点的本地树图结构是一致的,不存在诚实节点在两个阵营里的情况。
即使攻击者有更强的攻击能力,也会发现在出块速度慢的情况下,需要自己“干预”的次数大大增加,而自己的算力已经力不从心了。
我们构建了一个理论的模型。
在这个模型里,诚实节点的算力为平均每秒n个区块,所有的诚实节点被分成两个小组,两个小组的算力都是均等的。小组内的区块传播是没有延迟了,小组间的区块传播有一个延迟d秒。
这样,每个小组内收到的区块都一样,两个小组看到的区块并不完全一样。
在开始的时候,两个小组选择了同一个父亲区块下不同的两个孩子区块作为主链区块,并在它们的下面贡献权重,两个孩子区块的初始权重相同。
如果在某一时刻,其中一个小组所选择的孩子区块在自己的本地视图内也不占优,也就是这个小组根据最重链规则要“倒戈”的时候,攻击者需要放出一些区块避免这件事情,从而维持两个小组不能为谁是下一个“公共祖先”达成一致。如果攻击者不能放出区块,那么则攻击失败。
如果攻击者希望攻击永远不失败的概率大于0,那么攻击者需要满足一个最低的算力要求。
下图展示了在不同的d*n的情况下最低的算力需求。
可以看到,在d*n的取值非常小的时候,要求的最近算力接近每秒 n 个区块,也就是全体好人的区块生成速率。此时,对平衡攻击的要求不比双花攻击低。当 d*n 的取值非常大的时候,要求的算力趋近于0。
如果我们将出块速度降的足够低,使d*n的取值低于0.1, 那么攻击者就很难以较低的算力发起这种攻击了(比特币不是最重链规则,但我们可以用比特币的参数举个例子。在比特币中,d*n大约是0.02。)
然而,将攻击出块速度慢了下来,又违背了我们的初衷——造一个确认时间极短的 PoW 公链。这就出现了一个两难的选择。
1. 出块速度快:已经确认的区块没有安全性危险。没人攻击时确认速度非常快,有人攻击时永远无法确认。
2. 出块速度慢:同样可以保证安全性,也可以保证在有人攻击时能够在一段时间后确认交易,但是即使没有人攻击,确认时间也会非常慢。
到目前为止,最重链规则的“瑕”(出块速度快时存活性攻击)几乎完全掩盖了最重链规则的“玉”(出块速度快时确认快)。
那么在这个困局中,我们是否有办法实现二者兼得,既有出块速度慢的安全,又有出块速度快的效率呢?
我们将在接下来的几期内容中,为大家揭晓答案。