文章探讨了通过解耦区块生产与最终性来优化以太坊共识协议。核心方案是利用 Goldfish 协议(结合投票过期和视图合并特性)实现快速出块,并引入“稳定组件”和最终性组件,以在不牺牲插槽速度的前提下,提升协议在异步环境中的安全性和重组韧性。
感谢 EF 共识团队的讨论和评论
在当前的共识协议中,区块生成和最终性(finality)的时间线是耦合的。一个大型委员会(由整个验证者集的 1/32 组成)在每个 Slot 的关键路径中进行见证。缩小这个委员会的规模,例如缩小到验证者集的 1/64,将允许更快的 Slot 速度,但它会减慢最终性的达成,因为完成一轮完整的投票(一个 Epoch)现在需要累积 64 个 Slot 的开销,而不是 32 个。
在这个权衡空间的极端情况下,每个 Slot 只有一个验证者投票,而一轮完整的投票大约每 100 万个 Slot 才能完成一次,即使 Slot 时间为 100 毫秒,这也需要一天以上的时间。即使对于不那么极端的委员会规模(以及由此产生的 Epoch 长度),通过“逐个 Slot 累积实现最终性”所带来的开销也不容忽视。
另一方面,增加委员会的规模将使最终性更快达成,代价是区块生成速度变慢(Slot 时间更长)。在权衡空间的另一个极端,整个验证者集在每个 Slot 中都进行投票,而 Slot 时间在很大程度上取决于我们聚合投票的速度。
拟议的共识升级,如 SSF 和 3SF 的变体,并未从根本上改变这种权衡。它们只是将其置于权衡的一端,即整个验证者集在每个 Slot 中都进行投票。为此,其假设是验证者集将通过合并(consolidation)缩小到可行且不对 Slot 时间造成过严限制的程度。
另一种路径是解耦区块生成和最终性:
这种权衡可以被完全消除,两条流水线都可以独立优化。
在这个方向上已经进行了一些探索,但拼图的一块仍然缺失:目前尚无已知的基于投票的可用链协议在由快速变化的委员会运行时具有足够好的属性。特别是现有协议在面对暂时性异步时无法平稳降级,当活跃参与者快速变化时,用于增加其异步韧性的技术也会失效。
本文讨论的解决方法是:首先构建一个对委员会友好、同步下具有最佳安全性且具有异步韧性的可用协议;然后将其与最终性小组件一起,作为涨落协议(ebb-and-flow protocol)的两个构建模块。
Goldfish 是对 LMD-GHOST 的小幅修改,增加了两个关键特性:投票过期和视图合并。
通过视图合并与投票过期的结合,协议可以有效抵御事前重组(ex-ante reorg)。敌对节点在旧 Slot 积累的投票会过期,而诚实投票则由于视图合并而集中在诚实区块上。
然而,这种无记忆性也使 Goldfish 容易受到暂时性异步的影响。如果网络延迟导致诚实投票迟到,分叉选择缺乏诚实贡献,敌对节点便可能重写历史。
为了增强异步韧性,我们引入“稳定小组件”。其核心思想是借鉴最终性小组件的机制,但不要求那么高的参与度。如果没有支持委员会的要求,我们可以使用 RLMD-GHOST 或 Majorum 等协议作为稳定小组件,其动作延迟由整个验证者集的投票轮次决定。
我们可以利用稳定小组件确定底层可用协议分叉选择的起点。例如,结合 Majorum 和 Goldfish 的分叉选择步骤如下:
真正的最终性小组件用于提供异步和经济安全性。在实践中,分叉选择会演变为三步:
尽管逻辑上分为三步,但在实现中,最终性和稳定性可以捆绑在单一投票轮次中。当在线质押量低于 2/3 无法达成最终性时,稳定小组件仍能防止长程重组。
视图合并规定了如何处理冲突投票:节点仅跟踪最近一轮的投票,并记录每个验证者的前两个投票以识别冲突。
def on_vote(self, vote: Vote, from_block: bool):
if vote.slot != self.current_slot():
return
if vote.validator_id in self.equivocations:
return
time_in_slot = (self.network.time % SLOT_DURATION)
freeze_deadline = SLOT_DURATION * 2 // 3
if time_in_slot > freeze_deadline:
if not from_block and not self.is_proposer():
return
if vote.validator_id not in self.votes:
self.votes[vote.validator_id] = vote
return
if self.equivocations[vote.validator_id] != vote:
self.equivocations[vote.validator_id] = vote
为了兼顾安全性和抗攻击性,我们可以结合比例分配与 VRF 秘密选择:
def get_committee_seats_per_validator(slot_signature: bytes,
balance: Gwei,
total_balance: Gwei,
TARGET_COMMITTEE_SIZE: uint64) -> int:
balance_per_committee_seat = max(1, total_balance // TARGET_COMMITTEE_SIZE)
seats = balance // balance_per_committee_seat
random_value = bytes_to_uint64(hash(slot_signature)[:8]) % balance_per_committee_seat
remainder_balance = balance % balance_per_committee_seat
seats += 1 if random_value < remainder_balance else 0
return seats
- 原文链接: ethresear.ch/t/unblockin...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!