来源 | ethresear.ch
作者 | Vitalik Buterin
这是对信标链提议的一个替代设计方案,信标链可以在比较远的未来切换到这个模型 (替代现在计划的 CBC),它试图提供以下一些关键特性:
➤ 在正常情况下,提供有意义的单个 slot 的经济确定性 (即类似于 Tendermint 的特性)
- 使得即使大多数验证者参与合谋进行单个 slot 的重组,执行的成本也比现在高得多,从而减少共识可提取价值 (consensus-extractable value, CEV)
➤ 摆脱对 LMD GHOST 分叉选择的高度依赖,避免那些已知的缺陷,并需要引入复杂的混合分叉选择规则,以修补这些缺陷。
➤ 有可能会使更低的最低存款额度 (deposit size) 和更高的验证者数变得可能
➤ 保留经济确定性 (economic finality) 最终接近于一个非常大的数值 (数百万个 ETH) 这一特性
预备知识
让 CONSENSUS 成为一种异步安全的共识算法 (例如,Tendermint、Casper FFG 等)。我们假设共识算法的设计是涉及 slot 和 view (查看视图) 的,即它在每个固定时间段尝试达成共识时。我们还假设它把加权的验证者集 (现有的拜占庭容错共识算法要增加这一特性是很容易的) 作为输入。
在下面的设计里,我们修改 CONSENSUS,使得在每次的查看中,要求做最终敲定的验证者集都是不一样的。也就是说,是把 CONSENSUS 而不是验证者集作为函数 get_validator_set(view_number: int) -> Map[Validator, int] (其中 int 代表验证者余额) 的输入,该函数可以生成验证者集的新查看视图。get_validator_set 应该具有这样的特性,验证者集从一个视图到下一个视图最多变化 1/r,其中 r (r=65536 ) 是复原周期长度。更形式化来说,我们希望是这样:
其中,|x|返回的是 x 值的绝对值之和,而 diff 返回的是每个键值相减后的值 (例如,diff({a: 0.1, b:0.2}, {b:0.1, c:0.3}) = {a: 0.1, b: 0.1, c: -0.3})。
在实践中,相邻的两个验证者集间的差值会包括现有验证者被扣除的余额,而新加入的验证者的比率与被扣除余额的比率相等。
请注意,只有在之前的验证者还未做最后敲定时,1/r 的最大验证者集差值函数才可用。如果之前的验证者集已经最终敲定了,CONSENSUS 的实例会改变,因此 get_validator_set 函数的内部随机性会也会完全改变;在这种情况里,两个相邻的验证者集会变得完全不一样。
请注意,这意味着,如果两个最终敲定视图上的数值相差足够大,CONSENSUS 函数现在是可能两个一起敲定的,且不会发生罚没;这是故意如此设计的,而协议的处理方法就与今天 Casper FFG 处理怠工惩罚一样。
机制
我们使用两级分叉选择:
➤ S选择 LATEST_FINALIZED_BLOCK (最新被敲定的区块)
➤ 从 LATEST_FINALIZED_BLOCK 开始,使用其他的分叉选择 (例如 LMD GHOST) 来选择区块头
在每个 slot 都能查看一次 CONSENSUS 算法,将基于 get_post_state(LATEST_FINALIZED_BLOCK) 产生的数据的验证者集生成函数作为一项输入。一个有效的提议必须包含一个 LATEST_FINALIZED_BLOCK 的有效子孙区块。只有当该部分在分叉选择中胜出,成为区块链的一部分时,验证者才会准备并给区块提议投票。
如果 CONSENSUS 在某个视图中胜出了,那么该视图中被提议的区块就会成为新的 LATEST_FINALIZED_BLOCK,改变未来几轮的验证者集。如果它失败了,它需要在下一个 slot 或 view 里进行下一次尝试。
注意:slot 应该总是等于当前的视图编号加上之前每个成功最终敲定的验证者集的视图编号之和。
我们有以下的惩罚:
➤ 由共识算法决定的常规罚没惩罚
➤ 怠工惩罚:如果区块链无法做最终敲定,每个没有参与最终敲定的验证者都会受到惩罚。这个惩罚是在 r/2 个 slot 后将余额减半。
FFG 替代方案:单个- slot-epoch 的 Casper FFG
上述设计的一个替代方案是使用 Casper FFG,但要让 epoch 的长度等同于 slot。Casper FFG 的工作机制是不一样的,因为它不试图防止同一个委员会对一个区块及其子孙区块做最终敲定。为了适应这种差异,我们需要执行 (i) 1/4 的安全阈值而不是 1/3,(ii) 这样一条规则:如果一个 slot 做最终敲定,验证者集最多替换 1/4 而不是完全替换。
请注意,在这样的设计中,实现一个 slot (但不超过一个 slot) 的重组在理论上是无成本的。另外,在图表最后“直到最大最终确定性的 slot" 数需要增加 4 倍。
特性
如果一个区块被最终敲定了,其竞争区块如果要被最终敲定的话,需要发生以下其中一种情况:
➤ 某个委员会 (committee) 出现问题了,≥1/3 的验证者因为双重最终敲定另一个区块而被罚没
➤ 最新近的委员会离线了,在经过 r/3 个 slot 后,委员会经过充分混洗能够最终敲定另一个区块而不会被罚没。但是,这带来了严重的怠工惩罚 (≥1/3 的攻击者余额)
在任何一种情况下,即使要回滚一个被最终敲定的区块也需要至少有 DEPOSIT_SIZE * COMMITTEE_SIZE / 3 (存款额*委员会人数/3) 个 ETH 被烧毁。如果我们设置 COMMITTEE_SIZE = 131,072 (Eth2 委员会每个 slot 的验证者数,理论上最大值为 400 万),那么这个数值就是 1,398,101 个 ETH。
方案里的一些其他重要特性包括:
➤ 无论有多少验证者存款了,在处理每个 slot 的 COMMITTEE_SIZE(委员会大小)交易时验证者的负载都很稳定
➤ 验证者的负载会变得更低,因为当他们没有被要求加入委员会时,它们可以休眠
➤ 休眠中的验证者可以快速退出和提款,而不会牺牲安全性。
扩展:用小型委员会进行链确认
如果为了提高效率,我们不得不缩小 COMMITTEE_SIZE ,我们可以作出下列调整:
➤ 我们把“finalization (最终敲定)” 更名为“confirmation (确认)”,以反映单个确认不再代表真正的最终确定性
➤ 不同于选择最新的被确认区块,我们选择的是被确认区块最长链链头的被确认区块 (但拒绝回滚由 COMMITTEE_LOOKAHEAD 确认以外的区块,因此 COMMITTEE_LOOKAHEAD 的确认就代表真正的最终确定性)
➤ get_validator_set 应该只能使用状态的信息,而不是 COMMITTEE_LOOKAHEAD 确认之前的信息
➤ view 的编号应该就是 slot 的编号 (这使得同一个验证者集试图在不同链上达成共识的情况变得更易于被推导出来,这种情况只有在打破一些确认的时候才可能发生)
这个方案保留了以上所有的特性,但它也引入了一个新特性:如果一个区块获得多个确认 (例如,该区块被最终敲定了,且一条链的子孙区块又获得 k-1 个确认,因为共连续获得 k 个确认会影响该区块),那么回滚该区块就需要在多个委员会违反共识保证。这会使得来自多个委员会的安全水平得以堆积起来:回滚 k 个确认需要 COMMITTEE_SIZE * DEPOSIT_SIZE * k / 3 个 ETH,要达到 k = COMMITTEE_LOOKAHEAD,委员会才会出现分歧。
还要注意的是,无论如何,为了 p2p 子网的安全,前瞻机制 (lookahead mechanism) 是值得使用的,因此用它来设计是个好主意,而且如果有需要的话,可以留给客户端来决定他们要如何处理确认回滚问题。
具体数值的例子
请注意,“打破最终确定性所需的 ETH" 数假设了攻击者控制的验证者数相当于控制了超过总质押的 ETH 的一半 (即数百万个 ETH);这个数字是攻击者将失去的 ETH 。但这不等于任何拥有 2,730, 174,762 个 ETH 的人都可以通过随便烧毁这些 ETH 就能回滚单个 slot 的确认。