书接前文(点击阅读详情),GHAST 设计中的一个关键点就是判断树图中每个区块的“年龄”是否已经足够老。这次我们先来聊一聊为什么这个问题不是那么简单。
要判断一个区块是否足够老,最简单的判别依据自然是收到这个区块的时间。所有基于工作量证明的共识系统都必须假设每个区块广播到全网(绝大部分诚实节点)所需的时间都是有上限的。因此,诚实节点生成的区块到达(绝大多数)全节点的时间误差不会超过一次广播的延迟 d。
那些被雪藏了很久的区块也很容易被辨别出来。因为一个区块不可能引用生成时间比它更晚的区块,所以我们可以根据“没有引用的区块”来推测一个区块是否被雪藏了很久。如果一个区块漏掉了很多足够老的区块没有引用,那么这个区块本身肯定也不会年轻到哪里。
上面这个简单直接的判断方法最重要的问题在于不同的节点很难保持完全一致。对同一个区块,每个节点收到它的时间虽然很接近但是仍有少许差别(在 d 以内),而这微小的差别却会为一致性带来极大的麻烦。
当一个区块的“岁数”接近我们对于足够老的定义时,可能会进入“老与不老的中间状态”:部分节点认为它是足够老的,而另外一部分节点认为还要再等等。攻击者可能会利用这种短暂的不一致状态,把“某一个区块是否足够老”的分歧,放大到“区块权重”的分歧,再进一步放大到关于主链和全局共识的分歧。
上述问题最根本的原因在于各个节点收到区块的时间是不一样的。如果区块的年龄完全由树图结构决定,那么只要大家对树图结构达成共识,则对于区块年龄的判断结果就必然是一致的。而这里面,发挥关键作用的是图的拓扑结构。
在一个有向无环图里,两个区块 A 和 B 的关系有三种:1) 从 A 出发可以抵达 B;2) 从 B 出发可以抵达 A;3) 其他——A 和 B之间没有有向道路连接。于是,对于一个树图结构中的给定区块 B,我们可以按照上述三种关系把树图中其他区块分为三类:历史区块,未来区块,光锥外区块。
对于每一个区块 B,当它被所有全节点都收到后,每一个遵守协议的节点新生成的区块,都应当是 B 的“未来区块”。因此,根据“未来区块”的个数就可以判断一个诚实的区块是否足够老。
但是,对于那些被坏人藏了很久的区块,上述方法就无效了。在下图的例子中,区块 B 虽然生成得很早,但是它的“未来区块”却很少——本该是它的“未来区块”被变成了 “光锥外区块”。所以,“光锥外区块+未来区块”的总数,或许可以用来推测一个区块的“岁数”。
然而,用“光锥外区块+未来区块”数量推测区块的年龄也是有隐患的。坏人可以预先制造并储备大量的“光锥外区块”,从而让一个新生成的好人区块显得足够老。这显然也不是我们想要的结果。
正如之前的读者评论的,设计公链的共识协议,一个好的想法是远远不够的。必须站在攻击者的角度换位思考,反复在新的设计和新的攻击方式间进行迭代,才能最终得到一个可以抵抗已知的攻击手段的协议。接下来还要通过数学证明来论证这个协议对于未知的攻击手段也是安全的,一个端到端的安全性有保障的共识协议才算是大功告成了。
了解最新动态