本文详细介绍了leanConsensus协议中的3SF-mini(3槽最终性,精简版)最终性机制,旨在实现比以太坊Casper FFG更快的区块最终性。它通过引入“可证明槽位”概念和自适应回退策略,确保即使在网络不稳定时也能有效聚合投票,加速共识恢复。文章还对比了3SF-mini与Casper FFG的主要差异及其在ethlambda中的实现。
在我们之前的文章中,我们介绍了 ethlambda 如何使用 LMD-GHOST 来回答“我应该遵循哪一个链尖?”的问题。我们以一个悬而未决的问题结束:协议如何决定何时尖端重组 (reorg) 不再可能?Fork choice 告诉你链的走向,但它不会告诉你一个区块何时是永久性的。
这篇文章涵盖了共识的另一半:3SF-mini(3-Slot Finality,极简版本),这是 leanConsensus 使用的 Finality Gadget。如果说 LMD-GHOST 是关于在分叉中导航,那么 3SF-mini 就是关于终结分叉。
在今天的以太坊上,Finality 大约需要 13 分钟(Casper FFG 的两个 Epoch)。在该窗口期内,理论上链重组可以撤销任何交易。对于大多数用例来说,这没问题,但对于某些用例则不然。在协议层面,这意味着系统始终带有 13 分钟的不确定性。
leanConsensus 的目标是实现更快的 Finality,旨在 3 个 Slot 内达到 Finality,在 4 秒一个 Slot 的情况下,将 Finality 时间缩短到平均 10 秒。3SF-mini 可能不是最终的算法,但它让我们得以窥见更快速的 Finality 是什么样的。
在进入 Finality 之前,让我们回顾一下验证者投票的样子。每个 Attestation 携带三个检查点 (Checkpoint):
+------------------------------------------------------------------+
| ATTESTATION |
| |
| head 通过运行 Fork-choice 获得的区块 |
| <- LMD-GHOST (在前一篇文章中已涵盖) |
| |
| target 验证者希望下一个被证明合理 (justified) 的区块 |
| <- 源自 safe target,回溯到最近的 justifiable slot |
| |
| source 最新证明合理 (justified) 的检查点 |
| <- 从存储状态 (store state) 读取 |
+------------------------------------------------------------------+
head 输入到 Fork choice。source 和 target 输入到 Finality。一张选票表示:“我认为检查点 S 是 justified 的,我希望检查点 T 接下来也成为 justified。” 当足够多的验证者在同一个 (source, target) 链路上达成一致时,target 就会变成 justified。在某些条件下,justified 检查点将变为 finalized(不可逆)。
Justification 的阈值是三分之二的 Supermajority:
$$ 3 \text{vote_count} \ge 2 \text{validator_count} $$
如果有 9 个验证者,其中 7 个为同一个 target 投票:$37=21 \ge 29=18$,则该 target 被 justified。
在 ethlambda 中: Justification 和 Finalization 发生在 crates/blockchain/state_transition/src/lib.rs 中的 process_attestations() 函数中,该函数在 process_block() 期间被调用。
在有 4 个验证者且一切运行顺利的情况下,Finality 仅落后链尖两个 Slot:

在每个 Slot,验证者投票给最新的区块作为他们的 target,并引用最新的 justified 检查点作为 source:
source=N, target=N+1。四个中的三个投票($33=9 \ge 24=8$),因此 $N+1$ 是 justified。source=N+1, `target=N+2$。四个中的三个投票,因此 $N+2$ 是 justified。$N+1$ 和 $N+2$ 是连续的 justifiable Slot 且都被 justified,因此 $N+1$ 是 finalized。每个区块都携带 Attestation,用于证明父 Slot 是 justified 的,并使前一个 Slot 达到 finalized。对于 4 秒的 Slot,即从提议到 Finality 仅需 8 秒。
这是稳态;但网络并不总是稳定的。
当网络发生分区或验证者对 head 有分歧时,投票会分散在相互竞争的 target 上。没有单个 Slot 能达到三分之二的阈值。Justification 停滞,随之而来的是 Finalization 停滞。
这就是 3SF-mini 引入其最有趣想法的地方:不是每一个 Slot 都可以被 justified。只有距离最后一个 finalized Slot 特定距离的 Slot 才有资格。协议称这些 Slot 为 justifiable。
如果 $\text{delta} = \text{slot} - \text{finalized_slot}$ 小于或等于 5、是一个完全平方数,或者是一个 pronic number,则该 Slot 是 justifiable 的:
+-------------------------------------------------------+
| JUSTIFIABILITY 规则 |
| |
| 规则 1: delta <= 5 (始终是 justifiable 的) |
| |
| 规则 2: delta = n^2 (完全平方数) |
| 1, 4, 9, 16, 25, 36, 49, 64, 81, 100, ... |
| |
| 规则 3: delta = n(n+1) (pronic numbers) |
| 2, 6, 12, 20, 30, 42, 56, 72, 90, 110, ... |
| |
+-------------------------------------------------------+
在前 36 个 Slot 上的可视化:
delta: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
Y Y Y Y Y Y Y . . Y . . Y . . . Y . . . Y
|- delta <= 5 -| 2*3 3^2 3*4 4^2 4*5
delta: 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
. . . . Y . . . . Y . . . . . Y
5^2 5*6 6^2
接近 Finalization 时,每个 Slot 都是 justifiable 的,链移动很快。随着差距扩大,justifiable Slot 变得稀疏。它们之间的间隔从 1 增加到 3、4、5,并不断扩大。
为什么限制哪些 Slot 可以被 justified?因为它创造了自然的投票集中。如果在 30 个 Slot 的窗口中只有一个 Slot 是 justifiable 的,那么该窗口中的所有验证者投票都会汇集到同一个 target。当网络难以达成共识时,协议在结构上迫使投票收敛,而不是分散在多个候选者身上。
在 ethlambda 中:
crates/blockchain/state_transition/src/lib.rs中的函数slot_is_justifiable_after(slot, finalized_slot)实现了这一检查。它使用isqrt()进行完全平方数检测,并使用恒等式 $4n(n+1) + 1 = (2n+1)^2$ 进行 pronic number 检测。
仅凭 Justification 并不能使区块成为永久性的。一个 justified 的检查点在下一个 justifiable Slot 也被 justified 且中间没有 justifiable Slot 时变为 finalized。Source 和 target 必须是 justifiability 时间表中的连续条目。


推理很优雅:如果 source 和 target 之间不存在 justifiable Slot,那么验证者就不可能将他们的投票投向其他任何地方。不存在替代的 Justification 路径。这种结构上的不可能性使得该检查点不可逆。
这与 Casper FFG 有根本不同,Casper FFG 检查的是任何中间检查点是否已 justified。3SF-mini 检查的是中间检查点根本不存在。用更简单的逻辑实现更强的保证。
在 ethlambda 中:
crates/blockchain/state_transition/src/lib.rs中的try_finalize()函数遍历 source 和 target 之间的 Slot,并对每个 Slot 调用slot_is_justifiable_after。如果任何 Slot 是 justifiable 的,Finalization 就会失败。该检查使用original_finalized_slot(区块处理开始时的 finalized Slot,而不是当前的一个),因为 Finalization 可能在处理过程中推进。
除了作为过滤器外,justifiability 时间表也是一种退避机制。当 Finalization 停滞时,finalized Slot 与链尖之间的差距会增大。随着 delta 增加,justifiable Slot 变得更加稀疏。由于它们变得稀疏,投票就会集中。随着投票集中,达成共识变得更容易。系统会推动自己走向恢复。
考虑一个长期分区的网络。finalized Slot 卡在 0,链尖接近 Slot 1000:

一旦网络收敛:
阶段 1:长期停滞。 投票终于集中。Slot 992 和 1024 被 justified。它们之间没有 justifiable Slot。Slot 992 变为 finalized。新的 $F=992$。
阶段 2:部分重置。 Justifiability 时间表转移到以 $F=992$ 为锚点。在链尖(~1024)附近,delta 仅为 ~32。间隔从 31-32 缩小到约 6-7。
阶段 3:另一次 Finalization。 间隔进一步缩小。
阶段 4:恢复完成。 delta 足够小,使得每个 Slot 再次变为 justifiable。恢复快速 Finalization。
| 达成 Finalization 后 | F | Delta | 附近的间隔 |
|---|---|---|---|
| (停滞中) | 0 | ~1000 | 31-32 |
| Slot 992 | 992 | ~32 | 6-7 |
| Slot 1022 | 1022 | ~6 | 1 |
每一个 Finalization 步骤都会收紧时间表。系统逐步自我修复,无需人工干预或参数调整。
Casper FFG 没有等效机制,因为无论网络健康与否或是否分区,其 Epoch 间距都是固定的。
让我们看一个现实场景,其中分叉延迟了 Finalization,并观察系统如何恢复。这将 3SF-mini 连接回前一篇文章中的 Fork choice 机制。
设定: 9 个验证者,finalized=100,justified=101。Safe target 阈值:6 票(9 票的 2/3)。
Slot 102-103:分叉导致投票分散。

两个分支都没有超过三分之二。Safe target 卡在区块 101。Attestation 无法推进 Justification,因为从链尖的回溯总是落在 source 上,因此没有什么新的东西可以 justify。
Slot 104:分叉解决。 验证者 V7 和 V8 收到了区块 102a(因分区而延迟)并切换了阵营。

B102a 现在拥有 $7 \ge 6$ 票。Safe target 推进到 B102a。Slot 102 是 justifiable 的($\text{delta}=2 \le 5$)。带有 source=101, target=102 的 Attestation 达到 Supermajority:$37=21 \ge 29=18$。Slot 102 变为 justified。101 和 102 之间没有 justifiable Slot,因此 Slot 101 变为 finalized。
Slot 105-106:完全收敛。
所有 9 个验证者都在 a 分支上。带有 target=B104a 的 Slot 105 被 justified。但 102 的 Finalization 失败了,因为 Slot 103(位于 source=102 和 target=104 之间)是 justifiable 的,但从未被 justified(在分叉中丢失了)。
在 Slot 106 中,target=B105a 被 justified。104 和 105 之间没有 justifiable Slot,因此 Slot 104 变为 finalized。Finalization 从 101 跳到了 104,跳过了 102 和 103。

分叉导致了短暂的停滞,但协议在收敛后的两个 Slot 内就恢复了。没有特殊的恢复模式,没有操作员干预。处理 Happy Path 的相同规则也处理了 Unhappy Path。
两者都是建立在检查点之间 Supermajority 链路上的 Finality Gadget。它们共享相同的理论基础。它们的不同之处在于时间单位以及这对系统其余部分意味着什么。
Casper FFG 将 32 个 Slot(~6.4 分钟)分组为一个 Epoch,并将验证者集分配到这些 Slot 中。每个验证者每个 Epoch 见证一次。完整的统计数据仅在 Epoch 边界可用。最快的 Finalization:2 个 Epoch,大约 13 分钟。
这的存在是因为可扩展性限制,而不是协议理论偏好。以太坊上有约 1,000,000 个活跃验证者,让每个人在每个 12 秒的 Slot 都投票是无法管理的。Epoch 就是解决方案。
3SF-mini 在单个 Slot(4 秒)上运行。每个验证者在每个 Slot 都会投票。这目前之所以可行,是因为 leanConsensus 的验证者集较小。回报是:Finality 在 2 个 Slot 内达成,而不是 2 个 Epoch。
| 方面 | 3SF-mini | Casper FFG |
|---|---|---|
| 谁在何时投票 | 所有验证者,每个 Slot | 每个验证者每个 Epoch 一次 |
| 每个 Slot 的消息数 | $N$(所有验证者) | $N / 32$(一个委员会) |
| 达成 Supermajority 所需时间 | 1 个 Slot | 1 个 Epoch |
| 最快 Finalization | 2 个 Slot ~ 8 秒 | 2 个 Epoch ~ 13 分钟 |
| 自适应退避 | 是(Justifiability 时间表) | 否(固定的 Epoch 间距) |
| 实际验证者限制 | 数百到数千 | 数百万 |
Finalization 逻辑也不同。Casper 使用 $k$-finality:当其后的 $k$ 个连续 Epoch 检查点也被 justified 时,一个 justified 检查点即变为 finalized(以太坊使用 $k=2$ 作为错过 Epoch 的恢复机制)。3SF-mini 使用间隔规则:当下一个 justified 检查点是其在 justifiability 时间表中的直接继任者,且没有可能的中间 target 时,一个 justified 检查点即变为 finalized。3SF-mini 不是容忍错过的窗口,而是在网络困难时使窗口变宽。
ethlambda 中的 Finality 流水线集成在区块处理中。当一个区块被导入时,process_block() 应用 Attestation,检查 Justification,并尝试 Finalization,所有这些都在单次处理中完成。
| 步骤 | 位置 | 发生了什么 |
|---|---|---|
| Attestation 收集 | crates/blockchain/src/store.rs |
Attestation 在间隔 0 和 4 从 pending 提升为 active |
| Justification 检查 | crates/blockchain/state_transition/src/lib.rs |
process_attestations() 统计投票,应用 Supermajority 规则 |
| Justifiability 过滤器 | crates/blockchain/state_transition/src/lib.rs |
slot_is_justifiable_after() 控制哪些 Slot 可以被 justified |
| Finalization 尝试 | crates/blockchain/state_transition/src/lib.rs |
try_finalize() 检查 source 和 target 之间的间隔规则 |
| 窗口偏移 | crates/blockchain/state_transition/src/justified_slots_ops.rs |
当 Finalization 推进时,shift_window() 修剪 justified-slots 比特列表 |
| 指标 | crates/blockchain/src/metrics.rs |
每次 tick 更新 lean_head_slot 和 lean_finalized_slot |
justified_slots 比特列表使用相对索引(索引 0 映射到 finalized_slot + 1)。当 Finalization 推进时,shift_window() 会丢弃现在已经 finalized 的前缀并重新锚定比特列表。这使得数据结构无论链运行多长时间都保持有界。
如果你想查看 3SF-mini 的实际运行情况,ethlambda 是开源的,并且现在正在运行多客户端开发网:
- 原文链接: blog.lambdaclass.com/fin...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!