文章系统解释了 PoS 区块链中的 BFT 共识为什么常见于 33% 拜占庭容错上限,以及为何传统协议需要两轮投票才能保证跨槽安全。
![]()
大多数现有的 PoS(Proof of Stake)区块链都使用 BFT(Byzantine Fault Tolerant)共识协议,它假设恶意 validator 的阈值为 33%(或 1/3),并且需要两轮投票(再加上一轮提议,因此总共三轮消息)才能达到最终性。最近,人们重新关注起一轮投票的 BFT 共识(总共两轮消息),其恶意 validator 阈值为 20%,例如 Alpenglow、ChonkyBFT(zkSecurity 的审计),以及 Minimmit。这些两轮消息协议通常能实现更快的最终性,尤其是在 validator 地理分布较广、网络延迟占主导时(这里的消息轮次指的是单向广播阶段,而不是网络往返)。这篇博客将解释一轮投票 BFT 协议背后的直觉,并探讨 乐观的 一轮投票最终性的想法。
我们将建立对以下问题的直觉:
让我们从 BFT 共识中的基本设定开始。一个 validator 集合(总数为 n)协作广播并最终确定区块。它们通过一个并不总是稳定的网络通信,其中一些 validator(总数为 f)可能会表现出恶意行为(文献中称为 Byzantine)。BFT 共识的目标是在网络不确定性和故障参与者并存的情况下,正确地最终确定区块。
网络模型。 在现实世界中,网络大多数时候是快速且稳定的。然而,有时它也会不稳定:消息可能被延迟或丢失,网络分区也可能发生。例如,在平均情况下,你可能预期东京的一台计算机能在 200ms 内向纽约市的一台服务器传递一条消息。但如果你的路由器宕机,或者一条海底电缆被切断,网络可能会暂时不可达。这通常被建模为一个 部分同步 网络:
网络在开始时是异步的,消息延迟没有上界。经过某个未知时间之后(GST,Global Stabilization Time),网络变为同步,并且消息延迟有一个已知上界,但协议不知道 GST 何时发生。
由于 GST 对 validator 来说是未知的,它们永远无法确定当前网络是否同步。即使网络看起来很健康,下一秒也可能变得中断。因此,在共识算法运行期间,它必须始终在异步情况下保持安全。
Validator 模型。 大多数 validator 是 诚实 的:它们遵循协议,不会任意偏离(例如,它们从不 equivocate 或 double-vote)。当一个诚实 validator 最终确定/提交一个区块时,它会将该决定视为不可逆,并且只会在已最终确定的历史之上继续构建。有些 validator 可能以两种方式发生故障:
一个 BFT 共识协议应该足够稳健,能够在部分同步和 Byzantine validator 存在的情况下同时维持安全性和活性:
安全性确保即使在异步情况下也不会出现分叉。活性要求它在同步期间能够继续推进。
下面是 PoS 区块链中的 BFT 共识通常在高层如何运作:有一个固定的 validator 集合,每个 validator 都有基于 stake 的权重。为了简单起见,我们假设 stake 相等。validator 之间的所有消息都使用数字签名进行认证,以防止伪造。
时间被划分为 slots,每个 slot 都有一个提前已知的指定 leader(例如轮转)。在每个 slot 中,leader 提议一个区块并将其广播给所有 validator。其他 validator 验证该提议并广播自己的投票。每个 validator 在每个 slot 中只为它收到的第一个有效提议投票。如果某个 validator 收集到足够多的投票,它就提交/最终确定该区块并进入下一个 slot。在未来的 slot 中,validator 只会为那些扩展其最高最终确定区块的提议投票,因此它永远不会在与已最终确定历史冲突的分叉之上构建。如果 leader 保持沉默,且在超时前没有区块被最终确定,那么每个 validator 都会广播一个 timeout 消息,无论它是否在该 slot 中投过票。一旦达到一个 quorum 的 timeout,validator 就进入下一个 slot。
大多数现有的 PoS 区块链都假设 Byzantine 阈值为 33%,并且需要两轮投票来最终确定区块。这是因为 1/3(非正式地说)是在部分同步 BFT 协议中能够同时维持安全性和活性的最大 Byzantine 比例。让我们看看为什么。
设 n 是 validator 的总数,其中至多有 f 个是 Byzantine。
首先,我们引入一个有用的分析技巧,称为 quorum intersection:对于两个各包含 x 个 validator 的集合,它们至少会有 max(0, 2x - n) 个 validator 重合。由于这些共同的 validator 中至多有 f 个是 Byzantine,因此这两个集合至少有 max(0, 2x - n - f) 个诚实 validator 重合。例如,假设 n = 3f + 1,并且我们有两个各包含 x = 2f + 1 个 validator 的集合。那么这两个集合至少重叠 f + 1 个 validator,而且其中至少有 1 个必须是诚实的。如果两个互相冲突的提议在同一个 slot 中都获得了 2f + 1 票(因此都达到 quorum),那么它们的投票集合至少必须重叠一个诚实 validator,这意味着某个诚实 validator 必须同时给两者投票,这是不可能的。

现在假设某个共识算法需要 x 个 validator 的投票才能做出有意义的决定(即 quorum 是 x)。回忆一下,Byzantine validator 可以保持沉默或 equivocate。
f 个 Byzantine validator 都保持沉默时,也能仅靠诚实投票最终确定区块。在这种最坏情况下,只有 n - f 个 validator 可用,因此必须有 x ≤ n - f。否则,如果我们设 x = n - f + 1(或更大),那么对手就可以轻松发起 DoS:让所有 Byzantine validator 保持沉默,协议就会永远“差一票”达不到 quorum,也永远无法推进。f 个 Byzantine validator 都双重投票,两个冲突的决定也不可能同时达成。为了确保在一个 slot 中最多只有一个提议能够达到 quorum,我们需要 quorum 足够大,以至于任意两个 quorum 集合至少共享一个 诚实 validator。也就是说:2x − n - f > 0,即 x > (n + f) / 2。在这种情况下,如果两个不同的提议都获得了 x 票,那么必然存在一个诚实 validator 同时为两个提议投票,这是不可能的。综合两个方向,我们需要:
(n+f)/2<x≤n−f
要使这样的 x 存在,我们需要:
(n+f)/2<n−f⇒f<n/3
这正是 Byzantine validator 必须少于总数三分之一的结论!
直观地说,1/3 是我们能够选择的最大 Byzantine 比例。在这个比例下,quorum 既足够大,能够强制诚实重叠(安全性),又足够小,仅靠诚实投票就能达到(活性)。这就是为什么许多 PoS 区块链假设 33% 的 Byzantine 阈值:这是它们可以追求的最大韧性上界。
最小的整数选择是 n = 3f + 1。在这个经典设定中,选择 x = 2f + 1 满足两边:
2f + 1 ≤ n − f = 2f + 1。2x − n = (4f + 2) − (3f + 1) = f + 1 > f。在这个设定下,如果区块 B1 和一个冲突区块 B2 都在 3f + 1 个 validator 中获得了 2f + 1 票,那么它们的投票集合至少重叠 f + 1 个。由于至多只有 f 个 Byzantine validator,至少有一个重叠投票者是诚实的,这意味着一个诚实 validator 发生了双重投票,这是不可能的。因此,两个冲突区块不可能同时达到 2f + 1。
注意,1/3 是最大阈值。当然,我们也可以在设计协议时假设更低的阈值,例如 n = 5f + 1(即 20%)。在这种情况下,范围 3f + 1 ≤ x ≤ 4f + 1 内的所有 x 都是有效 quorum。正如我们将看到的,更低的 Byzantine 阈值是把两轮投票减少为一轮的关键。
乍一看,当 n = 3f + 1 时,我们似乎只需要一轮投票:在每个 slot 中,leader 提议一个区块,validator 验证它,广播一个投票,而任何收集到 2f + 1 票的 validator 都会立即最终确定该区块。从单个 slot 来看,这似乎是安全的,因为在同一个 slot 中不会有冲突区块能达到 2f + 1 票。然而,如果该 slot 超时,这个区块仍然可能被“丢失”。
考虑这样一个场景:所有 f 个 Byzantine validator 都保持沉默。2f 个诚实 validator 为区块 B 投票。最后一个诚实 validator 也为 B 投票,并且在本地看到了 2f + 1 票,于是它最终确定了 B。但由于网络异步性,它没能把自己的投票传递给其他人。结果,其他 validator 永远不知道 B 达到了 2f + 1 票。当该 slot 超时时,下一个 leader 可以提议一个跳过 B 的区块。在这种情况下,一个诚实 validator 提交了 B,而其他人跳过了它。安全性被破坏了。问题在于,2f + 1 票只能保证 B 是该 slot 中唯一可能被提交的 候选者,但并不能保证该 slot 不会被跳过。
我们增加第二轮投票,以在第一轮之后进一步决定该 slot 的结果是“提交 B”还是“空”(灵感来自 这篇博客):
vote1):当 validator 看到 leader 的提议 B 并认为其有效后,它广播 vote1(B)。vote2):如果 validator 观察到某个区块 B 的 2f + 1 个 vote1,它就广播 vote2,其中包含它收集到的 vote1(B)。在收到 2f + 1 个 vote2 后,validator 提交区块 B 并进入下一个 slot。timeout):如果 validator 在该 slot 超时后还没有提交区块,它就广播 timeout。如果 validator 已经发送过 vote1 或 vote2,它会把它们包含在 timeout 消息中:timeout(vote1, vote2)。看到 2f + 1 个 timeout 消息后,validator 进入下一个 slot。如果一个诚实 validator 提交了一个区块,那么它一定看到了 2f + 1 个 vote2。通过 quorum intersection,任何 2f + 1 个 timeout 消息集合都必须与任何 2f + 1 个 vote2 消息集合至少在一个 诚实 validator 上相交。这意味着,如果下一个 leader 收集到了 2f + 1 个 timeout,那么这些 timeout 消息中至少有一个包含 vote2,而该 vote2 又包含 2f + 1 个 vote1。因此,上一 slot 的区块不可能被“丢失”:协议可以要求下一个 leader 扩展它,而诚实 validator 会拒绝为不扩展锁定区块的提议投票。
第二轮投票是维持跨 slot 安全性所必需的。从 validator 的视角来看,这大致如下:
vote1 的 quorum 之前,validator 无法确定哪个区块(如果有的话)会被最终确定。B 的 2f + 1 个 vote1 之后,该 slot 的结果是“B 或空”(不会有冲突区块也收集到 2f + 1)。B 的 2f + 1 个 vote2 之后,B 在之后的 slot 中不会被跳过,因此可以安全地最终确定。所有诚实 validator 最终都会知道这一点,并且也会最终确定 B。
我们现在知道,对于 n = 3f + 1,我们需要第二轮投票,因为 2f + 1 个 vote1 还不足以决定“区块 B”与“空”之间的选择。一个自然的问题是:如果 validator 在第一轮中获得某个区块 多于 2f + 1 个 vote1,这些额外的票是否能提供更多确定性?答案是肯定的:如果一个 validator 在第一轮中收集到了 全部 票(3f + 1),它就可以直接提交一个区块。
假设在某些 slot 中,Byzantine validator 的行为是诚实的(后面会详细说明)。某个 validator 收集到了区块 B 的全部 3f + 1 个 vote1。那么在该 slot 中,就不可能还有另一个有效区块获得 quorum 票。我们仍然需要确保 B 不会被跳过:任何 2f + 1 个 timeout 消息集合都必须与这 3f + 1 个 vote1 消息至少在 f + 1 个诚实 validator 上相交。这意味着,在这 2f + 1 个 timeout 中,至少有 f + 1 个包含 vote1(B),这已经是严格多数。因此,下一个 leader(收集 2f + 1 个 timeout)被迫扩展 B。所以,在收到全部 3f + 1 个 vote1 后就可以安全地最终确定,因为额外的票确保了区块不会被跳过。反过来说,收到更少的(例如 3f 个)vote1 并不够,因为这不能保证 vote1(B) 在一个 quorum 的 timeout 中构成多数。
这就得到了一条快速路径:在第一轮投票中看到 3f + 1 个 vote1 时,就可以只用一轮投票最终确定区块。它是 乐观的,因为它要求所有 f 个 Byzantine validator 在该 slot 中都诚实参与。任何一个 Byzantine validator 都可以通过不投票来阻止快速路径。我们仍然需要第二轮路径作为默认的安全路径。
如果我们希望在不“乐观”地假设 Byzantine 参与的情况下实现一轮最终性,就需要一种不依赖 Byzantine 投票的方法。事实证明,解决方案相当直接:降低可容忍的 Byzantine 比例,这样我们就能拥有更多诚实 validator。
假设 n >= 3f + 1。让 validator 在看到 n - f 个 timeout 后进入下一个 slot。让 validator 在看到 n - f 个 vote1 后最终确定一个区块(这是我们在不依赖 Byzantine validator 的情况下所能保证的最多票数)。那么这些 vote1 和 timeout 集合的 诚实 交集至少是 n - 3f(因为 (n-f) + (n-f) - n - f = n - 3f)。为了确保该区块不会被跳过,timeout 的 quorum 中该区块的 vote1 必须是严格多数:
n−3f>(n−f)/2⇒n>5f
这说明,当 n > 5f 时,也就是 Byzantine validator 少于 20% 时,我们可以实现稳定的一轮最终性(不依赖同步期间 Byzantine validator 的参与)。
当 n = 5f + 1 时,大致如下:
vote1):当 validator 看到 leader 的提议 B 并认为其有效后,它广播 vote1(B)。如果某个 validator 看到了 4f + 1 个 vote1,它就直接最终确定该区块并进入下一个 slot。timeout):如果 validator 在该 slot 超时后还没有提交区块,它就广播 timeout。如果 validator 已经发送过 vote1,它会把它包含进去:timeout(vote1)。看到 4f + 1 个 timeout 消息后,validator 进入下一个 slot。如果一个诚实 validator 提交了一个区块,那么它一定看到了该区块的 4f + 1 个 vote1。通过 quorum intersection,任何 4f + 1 个 timeout 消息集合都必须与任何 4f + 1 个 vote1 消息集合至少在 2f + 1 个诚实 validator 上相交(因为 (4f+1) + (4f+1) - (5f+1) - f = 2f+1),这已经是严格多数。因此,如果下一个 leader 收集到了 4f + 1 个 timeout,那么其中超过一半都包含 vote1(B),迫使 leader 扩展 B。
这就是诸如 Alpenglow 和 Minimmit 等近期协议如何在 20% Byzantine 阈值下实现一轮最终性的直觉。这把三轮消息减少到了两轮,从而显著降低了最终性延迟,尤其是在 validator 地理分布较广、网络延迟(每轮消息约 100ms)占主导时。这些协议通常也更容易推理,因为它们避免了第二种类型的投票。
注意,我们仍然可以在共识中保留一个两轮回退路径。一轮和两轮路径可以并行运行。在这样的设计中,两轮路径的 quorum 阈值可以是 x = 3f + 1(即 60%),这样两个 quorum 至少在一个诚实 validator 上相交。这意味着两轮路径只需要 60% 的诚实参与就能达到最终性。它可以在保持安全性和活性的同时,容忍额外 20% 的诚实节点崩溃。这就是围绕 Solana 的 Alpenglow 设计中“20% Byzantine + 20% crash”这一表述背后的直觉。
在 33% Byzantine 阈值下,我们通过两轮投票实现最终性;在 20% Byzantine 阈值下,我们通过一轮投票实现最终性。现在考虑 Byzantine 阈值介于 20% 和 33% 之间的中间情况。
假设 n >= 3f + 1,并且我们使用与之前相同的协议结构。我们知道两轮路径的 quorum 是 x > (n+f)/2。假设一轮最终确定的阈值是 y。要在一轮中最终确定,我们需要足够多的 vote1,使得在 n-f 个 timeout 消息中,超过一半包含该区块的 vote1。用同样的交集推理:
y+(n−f)−n−f>(n−f)/2⇒y>(n+3f)/2
如上所述,我们可以并行运行两条路径:在第一轮之后,如果 validator 收集到了 x 个 vote1,它就广播 vote2 并继续收集 vote1。在收集到 y 个 vote1 后,它会立即最终确定该区块。
当 Byzantine 阈值从 20% 增加到 33% 时,一轮投票最终性的阈值 y 会从 80% 增加到 100%,而这始终高于可保证的诚实参与率 n - f(从 80% 到 66%)。在这个范围内,一轮投票最终性必然依赖某些 Byzantine validator 的投票来触发,因此它变成了 乐观的。下表列出了不同 Byzantine 阈值下的最终性阈值。

例如,当 Byzantine 阈值为 30% 时,我们可以用大约 65% 的票实现两轮投票最终性,用大约 95% 的票实现一轮投票最终性。这样就得到了一条可行的一轮快速路径,同时将最坏情况下的 Byzantine 阈值仅从 33.3% 降低到 30%。
这种乐观的快速路径想法在更早的工作 Fast Byzantine Consensus 中已有研究,也在更新近的 Kudzu 和 Hydrangea 中出现过。然而,它并没有被广泛用于生产系统。人们可能会认为乐观快速路径不太有用,因为“依赖 Byzantine validator 做正确的事”听起来自相矛盾。但实际上,它可能是一种在不牺牲保守最坏情况安全性的前提下降低最终性延迟的实用方式,因为:
例如,Ethereum 和 Solana 在实践中的参与率都非常高(Ethereum participation ~99%+,Solana vote success rate ~99%+,见 Rated),远好于最坏情况假设:


Ethereum 目前使用两轮投票式最终性,因此区块需要两个 epoch(约 12.8 分钟,每个 epoch 约 6.4 分钟)才能最终确定。鉴于实践中的高投票率,技术上可以通过将 Byzantine 阈值降低到约 30%,并加入一条乐观的一轮投票快速路径,来争取一 epoch 最终性。
其思路是在应对最坏情况的同时优化常见情况:两轮投票是保守基线,旨在在最坏情况下的网络和对抗假设下仍然安全且具备活性。一轮路径可以作为其上的一个 乐观快速路径。当某个 slot 遇到优于最坏情况的条件(例如高参与率和有限的对抗干扰)时,它可以更早最终确定,而两轮路径仍然作为保留原始韧性保证的回退方案。
大多数 PoS 区块链假设 33% 的 Byzantine 阈值,因为这是部分同步 BFT 共识的经典上界。在这种设定下,需要两轮投票来确保跨 slot 的安全性。一些近期的 BFT 协议假设 20% 的 Byzantine 阈值,以实现一轮投票最终性,把三轮消息减少到两轮。在 20% 到 33% 之间,乐观的 一轮投票最终性是可能的:它需要比可保证的诚实阈值更多的票,因此依赖于(某些)Byzantine validator 在某个 slot 中不进行干扰。尽管如此,作为建立在保守基线之上的快速路径,它可以在不牺牲最坏情况安全性的前提下减少实践中的最终性延迟。看到更多区块链探索这一设计空间会很有意思。
zkSecurity 为包括零知识证明、MPC、FHE 和共识协议在内的密码学系统提供审计、研究和开发服务。
- 原文链接: blog.zksecurity.xyz/post...
- 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!
作者暂未设置收款二维码