你给同事发了条消息,十分钟没回。
他是在忙、手机没电、还是已经离职了?你没法确定。 而且这里有个让人不安的地方:再等十分钟也不能确定——因为"还没回"和"永远不会回",在任何有限的时间里都长得一模一样。
这个日常困扰,是这一讲全部困难的来源。
上一讲的结论是:双花的本质是排序问题。这一讲处理的是——这个排序问题,理论上能被解决到什么程度。
这一讲不涉及任何区块链技术,全部是 1980 年代的分布式系统结论。但不知道这些边界,就无法判断任何一条链的安全宣称是真是假。
一、把问题写清楚
我们要造的东西叫复制状态机(State Machine Replication, SMR):
一组节点,每个节点都维护一份完全相同的状态。
它们从外界接收命令(交易),需要就"命令的执行顺序"达成一致。
只要所有节点以相同的顺序执行相同的命令,它们的状态就必然相同(因为状态转移函数是确定的)。所以整个问题归约成一件事:给命令定序。
一个共识协议必须满足两类性质:
| 性质 | 含义 | 直觉说法 |
|---|---|---|
| 安全性(Safety) | 两个诚实节点永远不会在同一个位置确定不同的命令 | 不会出错 |
| 活性(Liveness) | 每个被提交的命令最终会被确定下来 | 不会卡住 |
⭐ 这两者的区别至关重要,后面反复用到:
安全性被违反 = 发生了坏事(账本分裂、双花成功) 活性被违反 = 好事没发生(链停止出块,但没人损失钱)
打个比方
这两条像法庭的两个要求:安全性是"不冤枉好人",活性是"案子最终得判"。
理想情况两个都要。但在证据不足、又必须做决定的时候,法庭的选择是明确的:宁可拖着不判,也不能判错。 因为判错了没法撤销,拖着还有救。
⚠️ 当两者不能兼得时,几乎所有金融系统做的都是同一个选择:牺牲活性。链停一小时,损失是不便;链分裂一小时,损失是钱。第 20 讲会看到以太坊在极端情况下的具体选择。
⚠️ 当两者不能兼得时,几乎所有金融系统都选择牺牲活性。链停一小时,损失是不便;链分裂一小时,损失是钱。第 20 讲会看到以太坊在极端情况下的具体选择。
二、三种网络模型
“消息什么时候到"这件事的假设,直接决定了什么协议是可能的。
① 同步(Synchronous)
存在一个已知上界 Δ,任何消息都在 Δ 内送达。
⟹ 超时没收到 = 对方一定出故障了
② 异步(Asynchronous)
消息最终会送达,但没有任何时间上界。
⟹ 超时没收到 = 可能是慢,也可能是死了,⚠️ 无法区分
③ 部分同步(Partial Synchrony)
存在某个未知的时刻 GST(Global Stabilization Time)。
GST 之前网络可以任意坏;GST 之后消息都在 Δ 内送达。
⟹ 现实网络的合理模型
⭐ 第 ② 条里那句"无法区分"是全部困难的根源,也正是开头那条没回的消息。如果你能确定地判断一个节点是死是活,共识就容易得多。
⚠️ 这一点第一次读容易觉得是在钻牛角尖——“等久一点不就知道了吗?”不能。 任何你选定的等待时长,都可能只是对方恰好比这个时长慢一点。你没法用一个有限的超时,去区分"很慢"和"永远不来”——这不是工程精度问题,是逻辑上不可能。 下一节的 FLP 定理把这句话变成了一个证明。
现实中的互联网既不是同步也不是异步:绝大多数时候消息几十毫秒就到,但偶尔会有路由抖动、网络分区、BGP 劫持。部分同步是最贴近现实的模型,也是绝大多数现代协议采用的假设。
三、两种故障模型
| 故障类型 | 节点会做什么 | 别名 |
|---|---|---|
| 崩溃故障(Crash) | 停止响应,但从不发送错误消息 | fail-stop |
| 拜占庭故障(Byzantine) | 任意行为:撒谎、发送矛盾消息、串通、有选择地沉默 | 恶意 |
⚠️ 拜占庭故障不是"更严重的崩溃",它是质的不同:一个拜占庭节点可以对 A 说"我投 X",同时对 B 说"我投 Y"。区块链必须假设拜占庭故障,因为参与者是匿名的陌生人,其中一定有人想偷钱。
四、拜占庭将军问题:为什么是 n > 3f
Lamport、Shostak、Pease 在 1982 年的论文里用了这个比喻:
若干支拜占庭军队围住一座城,将军们只能通过信使沟通。他们必须一致地决定"进攻"还是"撤退"——全部进攻会赢,全部撤退能保命,一半进攻一半撤退会全军覆没。 其中有些将军是叛徒,会给不同的人发不同的消息。
结论是:
⭐ 在只有口头消息(消息不可验证来源、可以被中转者篡改)的情况下,要容忍 f 个拜占庭节点,总数必须满足
n ≥ 3f + 1。
三个将军、一个叛徒:为什么必然失败
设 n = 3, f = 1。分两种情况,我们会发现对诚实节点来说这两种情况完全无法区分。
情况 A:司令是叛徒
司令 C(叛徒)
├── 对 L1 说:进攻
└── 对 L2 说:撤退
L1 转告 L2:"司令说进攻"
L2 转告 L1:"司令说撤退"
L1 手上的信息:C 说进攻,L2 说"司令说撤退"
L2 手上的信息:C 说撤退,L1 说"司令说进攻"
情况 B:司令诚实,L2 是叛徒
司令 C(诚实)
├── 对 L1 说:进攻
└── 对 L2 说:进攻
L1 转告 L2:"司令说进攻"
L2 转告 L1(撒谎):"司令说撤退"
L1 手上的信息:C 说进攻,L2 说"司令说撤退" ← ⚠️ 和情况 A 中 L1 看到的完全一样
⭐ 关键在这里:L1 在两种情况下收到的消息集合一模一样。 它无法区分自己身处 A 还是 B。
- 如果它身处 B(司令诚实),协议要求它必须服从司令,即进攻。
- 但在 A 里,L2 收到的是"撤退",且 L2 也面临对称的困境。若 L1 进攻而 L2 撤退,就是最坏结果。
无论 L1 采取什么固定策略,总存在一种情况让两个诚实将军做出不同决定。所以 n = 3, f = 1 无解。
n ≥ 3f + 1 的直觉
换一个角度看这个式子,它其实非常直观:
总数 n,其中 f 个可能是拜占庭的。
你等待回复时,最多只能等 n − f 个 —— 因为那 f 个可能永远不回。
这 n − f 个回复里,最多有 f 个来自拜占庭节点(它们回了,但内容是假的)。
所以真实的诚实回复至少有:(n − f) − f = n − 2f 个。
要让"诚实的大多数"能压过"可能的谎言",需要:
n − 2f > f
⟹ n > 3f
⭐ f 被减了两次:一次因为它们可能不回话(活性代价),一次因为它们可能说谎(安全性代价)。这就是 3 的来源。
一个常见误解:n ≥ 3f+1 不是普适定律。如果消息带数字签名(第 7 讲),中转者无法伪造他人的消息,那么在同步网络下 n ≥ f + 2 就够了。区块链系统全部使用签名,但仍然采用 n ≥ 3f+1——因为它们运行在部分同步模型下,而在部分同步下即使有签名,n ≥ 3f+1 依然是必要的。
五、FLP 不可能性
1985 年,Fischer、Lynch、Paterson 证明了一个更强的结论:
⭐ 在完全异步的网络中,即使只有一个节点可能崩溃(不是作恶,只是宕机),也不存在任何确定性协议能同时保证安全性和活性。
注意这个结论有多强:
- 不需要拜占庭故障,崩溃就够了
- 不需要多个故障,一个就够了
- 不是"很难",是不存在
它为什么成立(直觉)
回到第二节那句话:异步网络中无法区分"节点死了"和"节点很慢"。
假设有个协议声称能在异步网络下工作。考虑某个"临界时刻"——此时系统还没决定结果,而下一条消息的到达会决定最终结果是 0 还是 1。
对手(调度器)可以做一件事:把那条关键消息拖住。协议无法判断消息发送者是死了还是消息在路上,于是:
- 如果它选择等待 → 万一对方真的死了,就永远等下去(违反活性)
- 如果它选择不等,先做决定 → 万一那条消息随后到达且内容相反,就可能出现两个不同结果(违反安全性)
FLP 的论文证明了这个"临界时刻"总是可以被构造出来,且对手总能把系统推向下一个临界时刻,无限延续下去。
它没有说什么
⚠️ FLP 经常被误引。它没有说"分布式共识不可能"。它的每个限定词都是必要的:
| 限定词 | 去掉它会怎样 |
|---|---|
| 异步 | 同步或部分同步下,共识是可能的(用超时来判定故障) |
| 确定性 | 允许随机化就可以绕过(下面讲) |
| 同时保证安全性和活性 | 只保证其中一个是容易的 |
六、现实中怎么绕过
⭐ 回到法庭那个比方:下面这些做法,全都是在"不冤枉好人"和"案子最终得判"之间选一头。没有一个方案两样都要——它们只是把选择挪到了不同的条件下。
既然理论上不行,实际系统是怎么工作的?三条路:
① 假设部分同步(主流 BFT 的做法)
承认现实网络在绝大多数时候是好的。协议的设计原则是:
⭐ 安全性:无论网络多糟,永不违反(不依赖时间假设)
活性: 只在 GST 之后保证(依赖网络恢复正常)
PBFT、Tendermint、HotStuff 全部走这条路(第 19 讲)。网络分区时它们会停止出块,但绝不会分叉。
② 随机化(Ben-Or 1983)
FLP 排除的是确定性协议。如果协议里允许抛硬币,那么"对手构造无限延迟序列"的策略就失效了——它无法预测下一步。
这类协议保证:以概率 1 终止(期望轮数有限),安全性始终成立。现代的异步 BFT(如 HoneyBadgerBFT)走这条路。
③ 换一个更弱的目标(比特币的做法)
⭐ 这是最有意思的一条,也是中本聪最容易被低估的地方。
比特币没有解决经典共识问题。它做了两处让步:
让步一:把"确定性最终性"换成"概率最终性"
经典共识:确定了就是确定了
比特币: 一笔交易被回滚的概率随确认数指数下降,但永不为零
让步二:假设网络是同步的
出块间隔 10 分钟 ≫ 全球网络传播时间(秒级)
⟹ 实际上假设了一个非常宽松的 Δ
在这两个让步之下,FLP 不适用(因为不是异步 + 不是确定性),拜占庭将军的下界也不适用(因为它不追求确定性一致)。比特币用"永远不完全确定"换来了"无准入 + 不会卡住"。
| 经典 BFT | 比特币 | |
|---|---|---|
| 参与者 | 已知、固定的 n 个 | 任何人随时进出 |
| 最终性 | 确定的,一旦提交永不回滚 | 概率的,6 个确认后回滚概率极低 |
| 网络分区时 | 停止出块(保安全性) | 两边各自出块,恢复后短链被抛弃(保活性) |
| 容错门槛 | f < n/3 | 算力 < 50%(第 16 讲会看到实际更低) |
⭐ 最后一行的对比是这门课反复出现的主题:BFT 系统在分区时牺牲活性,中本聪共识在分区时牺牲安全性(暂时的)。这是同一个权衡的两种选择,没有哪个绝对更好。
七、顺便澄清 CAP
CAP 定理经常被拿来讨论区块链,但几乎总是被误用。它的准确表述是:
在发生**网络分区(P)时,系统只能在一致性(C)和可用性(A)**之间选一个。
⚠️ 三个常见误读:
- “三选二"是误导。 分区不是你能选择的,它是网络强加给你的。真正的选择只在分区发生时才出现,是 C 和 A 的二选一。
- CAP 的 C 是线性一致性,不是"数据库的一致性”,也不是区块链语境下的"安全性"——虽然二者接近。
- CAP 假设的是崩溃故障,不是拜占庭故障。 它对区块链的适用性有限,因为区块链的核心难题是恶意节点,而 CAP 根本没建模这个。
用第一节的语言重新表述会清楚得多:分区时,要么牺牲安全性,要么牺牲活性。 这句话比 CAP 更准确,也更有用。
八、本讲小结
- 共识问题 = 给命令定序。只要顺序一致且状态转移确定,所有副本的状态必然相同。
- ⭐ 安全性 = 不会出错,活性 = 不会卡住。 二者不能兼得时,金融系统几乎总是牺牲活性——链停一小时是不便,链分裂一小时是钱。
- 三种网络模型:同步(有已知上界)、异步(无上界)、部分同步(GST 之后才好)。⭐ 异步的困难全部来自"无法区分节点是死是慢"。
- 拜占庭故障是质的不同,不是"更严重的崩溃":它可以对不同人说不同的话。
n ≥ 3f+1的来源:等待时最多只能等到n−f个回复,其中最多f个在说谎,所以可信回复只有n−2f个,要压过f个谎言需要n−2f > f。f 被减两次——一次为活性,一次为安全性。- 三将军反例的关键:L1 在"司令是叛徒"和"L2 是叛徒"两种情况下收到的消息集合完全相同,无法区分,所以任何固定策略都会在某种情况下失败。
- FLP:异步 + 确定性 + 一个崩溃故障 ⟹ 不存在解。 但它的每个限定词都必要——它没有说"共识不可能"。
- 绕过 FLP 的三条路:假设部分同步(主流 BFT)、引入随机化、换一个更弱的目标。
- 比特币走的是第三条:用"概率最终性 + 同步假设"换来"无准入 + 不会卡住"。它没有解决经典共识问题,它换了一个问题。
- CAP 对区块链适用性有限:它建模的是崩溃故障,而区块链的核心难题是恶意节点。用"分区时牺牲安全性还是活性"来表述更准确。
思考题
- 举一个现实中的例子,说明"违反安全性"和"违反活性"的后果差别有多大。
- 为什么在异步模型下无法区分"崩溃"和"缓慢"?如果给每个节点装一个绝对准确的故障检测器,FLP 还成立吗?
- 把三将军反例扩展到四将军一叛徒,说明为什么这时有解。
- 推导
n > 3f时,为什么"最多只能等 n−f 个回复"?如果协议要求等 n−f+1 个会发生什么? - 有签名的同步网络下门槛可以降到
n ≥ f+2。为什么区块链系统仍然用n ≥ 3f+1? - 比特币和 Tendermint 在网络分区时的行为完全相反。分别说出这两种选择在什么场景下更合适。
- “我们的链既有确定性最终性,又完全无准入,还能在异步网络下工作”——用这一讲的结论说明这个宣称哪里有问题。