打开钱包,看到一笔转账"已确认 1 个区块"。十分钟后再看,它不见了。

没有人攻击你,也没有出错。只是网络上另一条链后来居上,而你那笔交易所在的那个块被丢掉了。

两个矿工在同一秒挖出了块。两个块都合法,都有有效的工作量证明。

网络分成了两半,各自认了一个。

现在没有裁判,没有投票,也没有人有权宣布哪个算数。这一讲讲的就是:在这种情况下,一群互不信任的人靠一条谁都能独立算出的规则,最终收敛到同一条链上。

上一讲解决了"谁能出块"。这一讲解决"出现两个块时听谁的"。

一、分叉选择规则

⚠️ 一个几乎人人都说错的细节:

规则不是"最长链",是"累计工作量最大的链"(chainwork)。

每个区块贡献的工作量 = 2²⁵⁶ / (目标值 + 1)     ≈ 该块对应的难度
链的累计工作量 = 所有区块之和

⭐ 选累计工作量最大的那条链。

为什么这个区别重要:

⚠️ 攻击者可以把难度调低,快速造出一条【区块数更多】但工作量更少的链。
   如果规则是"最长",这条垃圾链会赢。
   ⟹ 按累计工作量,它一文不值。

打个比方

“最长链"和"最重的链"的差别,像比较两摞纸

“最长"是比页数——而页数是可以灌水的:把难度调低,就能快速印出一大摞薄纸。

“最重"是比总重量——每一页有多重,由它对应的难度决定。攻击者印再多张,那摞纸也轻。

⭐ 记法:“最长链"是在难度恒定时的简化说法。真正的规则永远是"最重的链”。

⚠️ 这个区别在正常运行时看不出来(难度稳定时,长 = 重),所以它长期被当成一个可以忽略的措辞问题。它不是:整个防御建立在"攻击者没法便宜地造出更重的链"上,而如果规则真的是比页数,这条防御就是免费可破的。

二、临时分叉与孤块

两个矿工几乎同时挖到块,网络会短暂看到两条链:

              ┌── 区块 101a (矿工 A)
   区块 100 ──┤
              └── 区块 101b (矿工 B)

⭐ 每个节点跟随自己先收到的那个,网络暂时分裂。
   下一个块出现在哪一边,哪一边就赢。

输掉的那个块叫孤块(orphan/stale block),它的奖励作废——矿工的电费白花了。

孤块率取决于什么

设:区块在全网传播需要 t 秒,平均出块间隔 T 秒

在 A 的块传播的这 t 秒里,别人可能也挖出块:
    ⭐ 孤块率 ≈ t / T

比特币:t ≈ 几秒,T = 600 秒 ⟹ 孤块率约 0.5%     ✅ 可忽略
若 T = 12 秒,t ≈ 2 秒        ⟹ 孤块率约 17%      灾难性

这就是比特币选择 10 分钟出块间隔的核心原因——不是保守,是为了把孤块率压到可忽略。

⚠️ 而孤块率高会直接导致中心化(第 9 讲第八节):

大矿池的块在池内无需传播 ⟹ 它的孤块率更低
⟹ 同等算力下大矿池收益更高
⟹ 算力向大矿池集中

以太坊的应对:叔块奖励

以太坊 PoW 时期出块 12–15 秒,孤块率必然很高。它引入了 GHOST 的简化版

⭐ 孤块(称为"叔块")也能被后续区块引用,并获得部分奖励。

效果:
   ① 小矿工的收益方差降低,中心化压力减轻
   ② 被引用的叔块也贡献链的"重量",让攻击更难

三、确认数:“6 个确认"从哪来

一笔交易被打包不等于安全——那条链可能被更重的链取代。每多一个后续区块,回滚的成本就翻倍增长。

中本聪在白皮书第 11 节做了这个计算:

攻击者算力占比 q,诚实方 p = 1−q。攻击者落后 z 个块,问他最终追上的概率。

这是一个泊松随机游走问题,结果:

P(追上) = 1 − Σ(k=0..z) [ λᵏe⁻ᵛ/k! ] × [ 1 − (q/p)^(z−k) ]        其中 λ = z·q/p

代入具体数字:

攻击者算力 q = 10%
   z=1  →  20.46%
   z=2  →   5.10%
   z=3  →   1.32%
   z=4  →   0.35%
   z=5  →   0.09%
   z=6  →   0.024%     ⭐ 这就是"6 个确认"的来源
   z=10 →   0.0001%

攻击者算力 q = 20%
   z=6  →   1.43%      6 个确认已经不够了
   z=10 →   0.11%

攻击者算力 q = 30%
   z=6  →  13.21%
   z=10 →   4.17%
   z=30 →   0.02%      ⟹ 要达到同等安全需要 30 个确认

两个重要推论:

① "6 个确认"不是一个绝对安全的数字,
   ⚠️ 它对应的是"攻击者算力 ≤ 10%"这个假设下 0.024% 的风险。

② 确认数应该按【交易金额】来定:
   买一杯咖啡:0 确认可以接受
   转一亿美元:应该等更久,因为攻击者愿意投入的算力更多

这个模型的三个假设

① 攻击者算力固定不变
② 诚实矿工不会察觉并做出反应(现实中交易所会暂停充值)
③ ⭐ 攻击者的目的是双花,而不是别的

四、51% 攻击:能做什么,不能做什么

⭐ 用那两摞纸来说:51% 攻击的意思是攻击者有能力持续造出更重的那一摞。注意它买到的只是"重量”——下面这一节说明,重量能改写顺序,但改不了那些需要签名才能做的事。

这是被误解最多的话题之一。

✅ 能做

① 双花:先付款收货,再重组链把付款抹掉
② 审查:拒绝把某些交易打包(但别人的块仍会包含它,除非算力接近 100%)
③ 独占区块奖励:让其他矿工的块全部变成孤块

❌ 不能做

① ⚠️ 偷别人的币 —— 没有私钥就签不出交易,
   而无效签名会被【每一个全节点】拒绝
② 凭空增发 —— 违反 coinbase 上限,同样被全节点拒绝
③ 改变很久以前的区块 —— 需要重做那之后的全部工作

这个区分回到第 3 讲的核心论点:

矿工控制的是"顺序”,不是"规则”。规则由运行全节点的人共同执行。

⚠️ 但如果没有人跑全节点,这个防线就不存在了。

攻击成本的现实

对大链,租用 51% 算力的成本极高,且 ASIC 无法大量租到(第 15 讲)。但对小链,这个攻击是真实且频繁发生的:

⭐ 一条与比特币共用 SHA-256 算法的小链,
   攻击者只需从比特币算力中临时租一小部分即可。
   历史上多条中小市值链遭受过成功的 51% 双花攻击。

⚠️ 所以"这条链用了 PoW 所以安全"是错的。安全性等于它的算力占该算法总算力的比例。

五、自私挖矿:真正的阈值不是 50%

2013 年,Eyal 和 Sirer 证明了一件让人不安的事:

一个算力远低于 50% 的矿工,可以通过偏离协议获得超出其算力比例的收益。

策略

① 挖到一个块 ⟹ ⚠️ 不广播,藏起来,在私链上继续挖
② 观察公链:

   若公链追平(诚实方也挖到 1 个):
       立刻发布自己的块,制造竞争
       部分诚实算力会转到攻击者的块上
       ⟹ 若攻击者赢,诚实方那个块作废

   若攻击者领先 ≥ 2 个块,而公链出了 1 个:
       发布一个块盖过它 ⟹ 诚实方白干

   若领先太多可能被追上:
       全部发布,锁定收益

核心逻辑:攻击者在私链上的工作从不浪费,而每次"抢发"都让诚实矿工的工作作废。

注意攻击者的绝对收益可能下降,但相对份额上升——而难度会随之下调,最终他的绝对收益也会回升。

阈值

γ 为"平局时选择跟随攻击者区块的诚实算力比例”,则攻击有利可图的门槛是:

α  >  (1 − γ) / (3 − 2γ)
γ(攻击者的网络优势) 阈值
0(攻击者传播最慢) 33.3%
0.25 30%
0.5(平局时各占一半) 25%
1(攻击者传播压倒性快) 趋近 0

结论:真正的安全阈值不是 50%,而是 25% 左右——且网络连接越好的攻击者,门槛越低。

更糟的是它的动态后果

自私挖矿有利可图 ⟹ 理性矿工加入攻击者的池子(收益更高)
⟹ 攻击者算力上升 ⟹ 收益更高 ⟹ ⭐ 正反馈,走向集中

为什么现实中没有大规模发生

① 一旦被发现,币价下跌,⚠️ 而矿工的 ASIC 资产被绑定在这条链上(第 15 讲)
② 声誉成本:矿池会流失矿工
③ 需要极好的网络连接(拉高 γ)
④ 检测手段在改善(异常的孤块模式可被观察)

但这些全部是链外的经济和社会约束,不是协议保证。 这是理解 PoW 安全性的关键:它的安全边界一部分在协议里,一部分在协议外。

六、其他几种攻击

攻击 机制 防御
日蚀攻击(Eclipse) 占满受害节点的全部对等连接,让它只能看到攻击者构造的世界 增加连接数、锚定连接、多样化对等选择
时间戳操纵 微调时间戳影响难度调整 第 9 讲的中位数规则 + 限幅
费用狙击(fee sniping) 链尾费用高时,矿工不去挖新块而是重挖上一个块抢手续费 区块奖励减半后会加剧(第 17 讲)
贿赂攻击 用智能合约悬赏其他矿工挖某条分叉 无技术性防御,只能靠成本

七、重组的现实

1–2 个块的重组:⭐ 每天都在发生,完全正常
3+ 个块的重组:  罕见,通常意味着有问题
比特币历史上最严重的一次:2013 年 v0.8 升级引发的意外共识分歧,
                          造成约 24 个区块的分叉,靠社区协调回滚解决

⚠️ 注意最后这个例子的性质:它不是攻击,是两个版本的客户端对同一个区块的合法性判断不一致共识系统里,实现的差异本身就是共识风险——这也是"多客户端实现"在以太坊被强调的原因。

八、Go 实现

package fork

import (
	"math"
	"math/big"
)

// ChainWork 计算一条链的累计工作量。
// ⭐ 分叉选择比较的是这个值,不是区块数量。
func ChainWork(targets []*big.Int) *big.Int {
	total := new(big.Int)
	two256 := new(big.Int).Lsh(big.NewInt(1), 256)
	for _, t := range targets {
		// 单块工作量 = 2²⁵⁶ / (target + 1)
		w := new(big.Int).Div(two256, new(big.Int).Add(t, big.NewInt(1)))
		total.Add(total, w)
	}
	return total
}

// AttackerSuccess 实现中本聪白皮书第 11 节的双花成功概率。
// q: 攻击者算力占比;z: 攻击者落后的区块数(即确认数)。
func AttackerSuccess(q float64, z int) float64 {
	if q >= 0.5 {
		return 1.0 // 算力过半时必然成功,只是时间问题
	}
	p := 1 - q
	lambda := float64(z) * (q / p)

	sum := 1.0
	for k := 0; k <= z; k++ {
		poisson := math.Exp(-lambda) * math.Pow(lambda, float64(k)) / factorial(k)
		sum -= poisson * (1 - math.Pow(q/p, float64(z-k)))
	}
	return sum
}

// ConfirmationsFor 返回把双花风险压到 maxRisk 以下所需的确认数。
// 实际使用中应按交易金额来选 maxRisk。
func ConfirmationsFor(q, maxRisk float64) int {
	for z := 0; z < 1000; z++ {
		if AttackerSuccess(q, z) < maxRisk {
			return z
		}
	}
	return -1 // 该算力比例下无法达到目标风险
}

// SelfishMiningThreshold 返回自私挖矿有利可图的算力门槛。
// gamma: 平局时跟随攻击者区块的诚实算力比例。
// gamma = 0.5 时门槛只有 25%,远低于直觉中的 50%。
func SelfishMiningThreshold(gamma float64) float64 {
	return (1 - gamma) / (3 - 2*gamma)
}

func factorial(n int) float64 {
	f := 1.0
	for i := 2; i <= n; i++ {
		f *= float64(i)
	}
	return f
}

九、本讲小结

  • ⚠️ 规则是"累计工作量最大",不是"最长"。 否则攻击者可以调低难度快速造出一条区块数更多、工作量更少的链。
  • 临时分叉每天都在发生,输的块叫孤块,奖励作废。⭐ 孤块率 ≈ 传播时间 / 出块间隔
  • 这就是比特币选 10 分钟的核心原因:把孤块率压到 0.5%。若出块间隔 12 秒,孤块率会到 17%。
  • 孤块率高直接导致中心化:大矿池内部无需传播,孤块率更低 ⟹ 同等算力收益更高。以太坊用叔块奖励缓解。
  • “6 个确认"对应的是"攻击者算力 ≤ 10%“下 0.024% 的风险。攻击者有 30% 算力时,6 个确认的风险高达 13%,需要 30 个确认才能达到同等安全。
  • 确认数应该按金额定:买咖啡 0 确认可以,转一亿应该等更久——因为攻击者愿意投入的算力随金额上升。
  • 51% 能做:双花、审查、独占奖励。不能做:偷币、增发、改久远历史。矿工控制顺序,不控制规则——但前提是有人在跑全节点。
  • “用了 PoW 所以安全"是错的:安全性等于算力占该算法总算力的比例。共用 SHA-256 的小链可以被租算力攻击。
  • 自私挖矿把真正的阈值从 50% 拉到 (1−γ)/(3−2γ):网络条件中等(γ=0.5)时只要 25%,网络优势压倒性时趋近 0。
  • 它还有正反馈:有利可图 ⟹ 理性矿工加入 ⟹ 算力更集中。现实中未大规模发生,靠的是 ASIC 资产绑定、声誉、网络条件——全是协议之外的约束
  • 2013 年的 24 块重组不是攻击,是两个客户端版本的判断不一致。 实现差异本身就是共识风险——这是多客户端实现被强调的原因。

思考题

  1. 构造一个例子:链 A 有 100 个块但难度很低,链 B 有 50 个块但难度很高。说明按两种规则各会选哪条,以及为什么"最长"是危险的。
  2. 一条链把出块间隔从 600 秒降到 60 秒,传播时间不变。孤块率变成多少?这会怎样影响小矿工?
  3. 以太坊的叔块奖励为什么能缓解中心化?它有没有引入新的攻击面?
  4. 用第三节的公式,计算攻击者算力 25% 时,把风险压到 0.1% 以下需要多少确认。
  5. 一笔价值 1000 万美元的交易,你会要求多少个确认?请给出你的推理过程(提示:考虑攻击者能投入多少)。
  6. 白皮书模型假设"诚实矿工不响应”。现实中交易所会暂停充值。这会怎样改变攻击的经济学?
  7. 51% 攻击者想把某个地址的余额改成 100 万 BTC。他能做到吗?请说明会在哪一步被拦下。
  8. 完整推演自私挖矿:攻击者领先 2 个块时公链出了 1 个块,他该怎么做?领先 1 个块时呢?
  9. 为什么 γ 越大攻击门槛越低?攻击者能用什么手段提高自己的 γ?
  10. 自私挖矿在现实中很少发生,靠的是哪些链外约束?如果这些约束消失(比如一条没有 ASIC、矿工匿名的链),会怎样?