BSC双验证者节点为何卡在相邻区块?解密 PBFT 的“双重提案死锁”
问题直击:
在自建BSC链(基于Tendermint PBFT共识)的双节点测试环境中,您观察到一个典型现象:
-
验证者1 (V1) 认为当前应该出 区块2,并提出了自己的区块2提案。
-
验证者2 (V2) 也认为当前应该出 区块2,但提出了一个不同的区块2提案 (或由于网络原因没收到V1的提案)。
-
结果: V1 坚持自己的区块2,V2 坚持自己的区块2,双方都无法说服对方接受自己的提案,整个网络卡死。增加第3个节点后,问题立即消失。
验证者1/验证者2都报错:
Signed recently, must wait for others
但验证者1因为处于"同步"状态,丢弃了区块2:
同时启动导致竞争:两个验证者几乎同时启动,都开始挖区块1
区块1的竞争挖矿:
验证者1:在 03:40:45.649 成功挖出区块1(hash: 99f60f..858790)
验证者2:在 03:40:45.609 也成功挖出区块1(hash: 5dfc4f..b180b9)
两个节点几乎同时挖出区块1,但hash不同,说明是分叉
验证者2挖出区块2后,验证者1收到了广播
但验证者1因为处于"同步"状态,丢弃了区块2
WARN [07-03|03:40:57.753] Syncing, discarded propagated block number=2 hash=b0feb0..c50000
核心问题:缺乏“多数票”的裁决机制导致死锁
⚔️ 双重提案死锁详解 (非恶意场景)
-
提案冲突的发生:
-
场景A (网络分区/延迟): V1 作为当前轮的主节点,成功生成并广播了 区块2提案A。但由于网络波动,V2 没有及时收到 提案A。
-
场景B (超时视图切换): V2 在等待提案时超时了。根据 PBFT/Tendermint 协议,V2 认为主节点 V1 失效,于是触发视图切换。在新的视图中,V2 成为主节点,并提出了自己认为正确的 区块2提案B,并将其广播出去。
-
此时状态: V1 持有并相信 提案A 是正确的区块2。V2 持有并相信 提案B 是正确的区块2。两个节点都处于“区块2”的高度,但内容不同或互不知晓对方提案。
-
-
投票僵局:
-
V1 收到 V2 的 提案B,但它已经基于 提案A 投出了自己的 预投票 (PreVote)。根据协议,诚实节点在同一高度/轮次只会为一个提案投票。V1 拒绝投票给提案B (因为它已为A投票)。
-
同理,V2 收到 V1 的 提案A (可能延迟到达),但 V2 已经为 提案B 投出了预投票。V2 拒绝投票给提案A。
-
结果: V1 只有自己对自己提案A的投票(1票)。V2 只有自己对自己提案B的投票(1票)。双方都无法获得
> 2/3多数票(在2节点环境下,> 2/3 * 2 = > 1.33,即需要至少2票)来锁定 (PreCommit) 任何一个提案。
-
-
死锁循环:
-
由于两个提案都得不到足够的票数,双方最终都会再次超时。
-
超时后,又会触发新一轮的视图切换。
-
在新视图中,可能:
-
V1 再次成为主节点,提出 区块2提案A (或新提案C)。
-
V2 再次成为主节点,提出 区块2提案B (或新提案D)。
-
-
历史重演: 投票僵局再次发生,任何提案依然无法获得2票。网络陷入 “提议 -> 投票失败 -> 超时 -> 视图切换 -> 再提议” 的无限循环,V1 和 V2 永远卡在“区块2”的高度无法前进。这就是您观察到的“一个卡在3(可能是上一轮尝试提交3未果的残留状态),一个卡在2”的根本原因——它们实际上在“区块2”的高度陷入了提案冲突的死循环。
-
🧩 为什么第3个节点 (V3) 是解药?
引入 V3 这个关键的第3票,彻底打破了僵局:
-
多数票裁决: 共识规则要求
> 2/3多数票。对于3节点,需要ceil(2/3 * 3) = 2票。 -
打破平衡:
-
假设 V1 作为主节点首先广播了 区块2提案A。
-
V3 成功收到提案A,并在验证后对其投出 预投票。
-
此时 V1 和 V3 都投票给了 提案A (共 2票)。这满足了
> 2/3的要求(2 >= 2)。 -
节点们进入 预提交 (PreCommit) 阶段。同样,V1 和 V3 的预提交票也构成多数(2票)。
-
区块2提案A 被成功提交 (Commit),链高度推进到区块2。
-
-
处理延迟/失效:
-
V2 延迟收到提案A? 即使 V2 因为网络问题投票晚了或没投票,只要 V1 和 V3 达成一致(2票),区块就能最终确认。V2 稍后从链上同步已确认的区块2即可。
-
V1 主节点失效? 如果 V1 在提议前就挂了,V2 和 V3 会在超时后发起视图切换。在新视图中,V2 (或 V3) 成为主节点提出提案。只要 V2 和 V3 能正常通信(2票),就能成功提交提案。
-
核心作用: V3 的存在确保了:
-
总能产生明确多数: 在三个节点中,任何获得两票的提案就是唯一合法的提案。
-
避免双重提案僵持: 两个竞争提案不可能同时各自获得两票(总共只有三票)。总有一个提案能胜出(或都达不到两票导致视图切换,但三个节点下更容易选出有效主节点)。
-
容忍单点波动: 允许一个节点暂时离线、延迟或未响应,不影响另外两个节点推进链。
📌 关键结论与行动指南
-
死锁根源确认: 您观察到的“验证者1提议块2,验证者2也提议块2,双方互不认可”的现象,正是PBFT/Tendermint共识在2节点环境下的致命缺陷——双重提案缺乏多数票裁决机制导致的必然死锁。 无关节点作恶,纯粹是协议规则与节点数不足的矛盾。
-
“3”是解锁共识的魔法数字: 它是在非恶意环境下打破提案僵局、形成明确多数决的最小节点数。第3个节点提供了至关重要的“决胜票”。
-
“4”是提升稳定性的推荐选择:
-
n=4时,共识需ceil(2/3 * 4) = 3票。 -
优势: 即使有一个验证者节点临时维护、重启或遇到轻微网络问题(非永久离线),剩下的3个节点(3票 >= 3)依然可以持续稳定地出块,极大提升测试链的可用性和健壮性。避免了单点临时故障导致整个链暂停。
-
更贴近生产: 4节点能模拟生产环境中常见的单点故障场景。
-
总结:两个诚实的节点,也会因为网络的不确定性和共识规则,在相同高度陷入“谁说了算?”的无解争吵。第三方的加入,不是为了监督作恶,而是为了在分歧时提供那枚决定性的“赞成票”,让共识得以继续。 因此,搭建基于 PBFT/Tendermint 的测试链,3节点是底线,4节点是推荐。
附录:节点数与双重提案解决能力
| 节点数 | 所需多数票 (ceil(2/3 * n)) |
能否有效解决双重提案冲突? | 容忍1节点短暂离线? | 推荐度 |
|---|---|---|---|---|
| 2 | 2 | ❌ (必然死锁) | ❌ | 🚫 绝对避免 |
| 3 | 2 | ✅ (第3票打破僵局) | ⚠️ (链停风险高) | ⭐ 最低可行 |
| 4 | 3 | ✅ | ✅ | ⭐⭐⭐⭐ 强烈推荐 |
解决方案
引入第三个节点,且每个节点的抵押金额不一致,投票权重不一致,



浙公网安备 33010602011771号