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

核心问题:缺乏“多数票”的裁决机制导致死锁

⚔️ 双重提案死锁详解 (非恶意场景)

  1. 提案冲突的发生:

    • 场景A (网络分区/延迟): V1 作为当前轮的主节点,成功生成并广播了 区块2提案A。但由于网络波动,V2 没有及时收到 提案A。

    • 场景B (超时视图切换): V2 在等待提案时超时了。根据 PBFT/Tendermint 协议,V2 认为主节点 V1 失效,于是触发视图切换。在新的视图中,V2 成为主节点,并提出了自己认为正确的 区块2提案B,并将其广播出去。

    • 此时状态: V1 持有并相信 提案A 是正确的区块2。V2 持有并相信 提案B 是正确的区块2。两个节点都处于“区块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) 任何一个提案。

  3. 死锁循环:

    • 由于两个提案都得不到足够的票数,双方最终都会再次超时

    • 超时后,又会触发新一轮的视图切换

    • 在新视图中,可能:

      • V1 再次成为主节点,提出 区块2提案A (或新提案C)

      • V2 再次成为主节点,提出 区块2提案B (或新提案D)

    • 历史重演: 投票僵局再次发生,任何提案依然无法获得2票。网络陷入 “提议 -> 投票失败 -> 超时 -> 视图切换 -> 再提议” 的无限循环,V1 和 V2 永远卡在“区块2”的高度无法前进。这就是您观察到的“一个卡在3(可能是上一轮尝试提交3未果的残留状态),一个卡在2”的根本原因——它们实际上在“区块2”的高度陷入了提案冲突的死循环。

🧩 为什么第3个节点 (V3) 是解药?

引入 V3 这个关键的第3票,彻底打破了僵局:

  1. 多数票裁决: 共识规则要求 > 2/3 多数票。对于3节点,需要 ceil(2/3 * 3) = 2 票。

  2. 打破平衡:

    • 假设 V1 作为主节点首先广播了 区块2提案A

    • V3 成功收到提案A,并在验证后对其投出 预投票

    • 此时 V1 和 V3 都投票给了 提案A (共 2票)。这满足了 > 2/3 的要求(2 >= 2)。

    • 节点们进入 预提交 (PreCommit) 阶段。同样,V1 和 V3 的预提交票也构成多数(2票)。

    • 区块2提案A 被成功提交 (Commit),链高度推进到区块2。

  3. 处理延迟/失效:

    • V2 延迟收到提案A? 即使 V2 因为网络问题投票晚了或没投票,只要 V1 和 V3 达成一致(2票),区块就能最终确认。V2 稍后从链上同步已确认的区块2即可。

    • V1 主节点失效? 如果 V1 在提议前就挂了,V2 和 V3 会在超时后发起视图切换。在新视图中,V2 (或 V3) 成为主节点提出提案。只要 V2 和 V3 能正常通信(2票),就能成功提交提案。

核心作用: V3 的存在确保了:

  1. 总能产生明确多数: 在三个节点中,任何获得两票的提案就是唯一合法的提案。

  2. 避免双重提案僵持: 两个竞争提案不可能同时各自获得两票(总共只有三票)。总有一个提案能胜出(或都达不到两票导致视图切换,但三个节点下更容易选出有效主节点)。

  3. 容忍单点波动: 允许一个节点暂时离线、延迟或未响应,不影响另外两个节点推进链。

📌 关键结论与行动指南

  • 死锁根源确认: 您观察到的“验证者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 ⭐⭐⭐⭐ 强烈推荐

解决方案

  引入第三个节点,且每个节点的抵押金额不一致,投票权重不一致,

  

  

posted @ 2025-07-07 11:45  若-飞  阅读(32)  评论(0)    收藏  举报