一、回到女巫攻击

第 1 讲的结论:投票权必须绑定到一种无法凭空复制的稀缺资源上。

PoW 选的是计算。它的思路是:

让"写下一个区块"这件事需要消耗真实世界的资源,而这个消耗可以被任何人快速验证。

这个想法来自 Adam Back 1997 年的 Hashcash——一个反垃圾邮件方案:发一封邮件要先算一小会儿,正常用户无感,群发一百万封的人就付不起了。中本聪把它从"反垃圾邮件"改造成了"抽签决定记账权"。

打个比方

PoW 像一场没有发票根的抽奖:想抽一次,就得先真的花掉一块钱。

它有两条性质,缺一不可:

买票很贵    你没法凭空多买票 ⟹ 女巫攻击失效(第 1 讲)
验票极快    任何人一眼就能看出这张票是不是真中了

⭐ 第二条常被忽略,但它才是 PoW 能用在开放网络里的原因:算的人要烧几万亿次,核的人只需要算一次哈希。 这个巨大的不对称,让"谁都可以参与,谁都可以核验"同时成立。

二、谜题

找一个 nonce,使得:

    H( 区块头 ‖ nonce )  <  目标值 T

其中 H = 双重 SHA-256(第 4 讲),目标值 T 是一个 256 位的数。

T 越小,符合条件的哈希越少,越难找。

T 很大(容易):  0x00FFFFFF...   约 1/256 的尝试能成功
T 很小(困难):  0x00000000FF... 约 1/2⁴⁰ 的尝试能成功

⭐ 直觉说法:要求算出的哈希以足够多个 0 开头。

三、为什么这个谜题是对的

⭐ 这一节验证的正是抽奖那两条:票买不便宜(除了穷举没有近路),而票好验(一次哈希就知道中没中)。 缺任何一条,这个机制都不成立。

它必须同时满足三条,缺一不可:

① 难解易验(不对称)

求解:平均要试 2²⁵⁶ / T 次
验证:⭐ 算一次哈希,比大小。微秒级。

⚠️ 不对称性是全部价值所在:矿工付出巨大代价,而全网每个节点用几微秒就能确认他确实付出了。

② 无记忆性(memoryless)——最容易被忽略但最关键

因为哈希有雪崩效应(第 4 讲),每一次尝试都是独立的伯努利试验。没有"部分进度",没有"越试越接近"。

这带来一个至关重要的公平性质:

一个已经算了一小时的矿工,和一个刚开机的矿工,
⭐ 在下一次尝试上的成功概率完全相同。

⟹ 不存在"进度积累",不存在先发优势
⟹ 一个矿工的期望收益,严格正比于他的算力占比

⚠️ 如果谜题有部分进度(比如"找一个前缀最长的匹配"),大矿工就能积累优势,小矿工永远追不上,网络会迅速中心化。

③ 难度可调

T 是一个参数,可以随全网算力变化而调整,从而保持出块速度稳定。见第五节。

四、出块时间的分布:方差比你想的大

设单次尝试成功的概率:

p = T / 2²⁵⁶

全网每秒 R 次哈希,则每秒出块概率 ≈ R·p。这是一个泊松过程,于是:

出块间隔服从指数分布,均值 1/(R·p)。比特币把它调到 600 秒。

⚠️ 指数分布的方差非常大,这一点常被误解:

P(间隔 > 10 分钟) = e⁻¹     ≈ 36.8%     ⭐ 超过三分之一的区块间隔比"平均值"还长
P(间隔 > 20 分钟) = e⁻²     ≈ 13.5%
P(间隔 > 30 分钟) = e⁻³     ≈  5.0%
P(间隔 > 60 分钟) = e⁻⁶     ≈  0.25%    ⟹ 平均每 403 个块出现一次
P(间隔 <  1 分钟) = 1−e⁻⁰·¹ ≈  9.5%

推论:

① "10 分钟一个块"是均值,不是节奏。
   ⚠️ 一小时不出块完全正常,不是网络故障。

② 指数分布是【无记忆】的:
   已经等了 20 分钟,再等 10 分钟的概率仍然是 63.2%——
   "等得越久越快出"是错的。

③ 这也解释了为什么"6 个确认"要留余量(第 16 讲)。

五、难度调整

全网算力会剧烈变化(币价涨跌、新矿机上市、政策变动)。若不调整,出块速度会失控。

比特币的规则

每 2016 个区块调整一次(期望恰好 2016 × 10 分钟 = 14 天)

新目标 = 旧目标 × (实际耗时 / 20160 分钟)

⚠️ 限幅:比值被夹在 [1/4, 4] 之间

三点说明:

① 实际耗时短(算力涨了)⟹ 比值 < 1 ⟹ 目标变小 ⟹ 难度上升 ✅
② ⭐ 限幅防止时间戳操纵造成难度剧烈波动
   但也意味着算力骤降 80% 时,这个周期会拖得非常久
      (历史上出现过一个调整周期长达数周的情况)
③ 难度只在周期边界变,周期内固定

又一个永远修不掉的 bug

计算"实际耗时"时,用的是
    第 2016 块的时间戳 − 第 1 块的时间戳

⭐ 但这中间只有 2015 个间隔,不是 2016 个!

⟹ 目标出块时间实际是 600 × 2015/2016 ≈ 599.7 秒
⟹ 比特币比"设计值"快约 0.05%

修复它需要硬分叉,收益却近乎为零,所以它被永久保留了。⭐ 这和第 10 讲 OP_CHECKMULTISIG 的多余 OP_0 是同一类现象:共识系统里,bug 一旦上线就成了规范。

难度与目标的关系

难度 D = 最大目标 / 当前目标

最大目标(难度 1)= 0xFFFF × 2²⁰⁸

⭐ 由此可以反推全网算力:
    算力 ≈ D × 2³² / 600     (每秒哈希次数)

⚠️ 注意"全网算力"是估算出来的,不是测量出来的——没有人能真的统计全球矿机。所有算力图表都来自这个公式。

六、以太坊 PoW 时期的两点不同

① 每个区块都调整难度(不是每 2016 块)
   ⟹ 响应更快,但也更容易被时间戳微调影响

② ⭐ 难度炸弹(Ice Age)
   在难度公式里加一个随区块高度指数增长的项,
   ⟹ 出块时间会逐渐变长直到链"冻住"
   目的是【强制】社区在某个期限前完成向 PoS 的迁移

⭐ 难度炸弹是一个有意思的治理工具:用技术手段给升级设一个不可拖延的截止日期。它被推迟过多次(每次推迟都要一次硬分叉),最终随合并生效。

七、挖矿设备与矿池

设备演进

CPU → GPU → FPGA → ASIC
⭐ 每一代的能效提升都在数量级上

⚠️ “ASIC 抗性"是一个有争议的目标。支持者认为它保护普通人参与;反对者的论点更有力:

① ASIC 抗性算法通常改用内存密集型(如 Ethash、RandomX),
   ⚠️ 但历史反复表明,只要有足够利润,ASIC 最终总会出现
② 更重要的是:ASIC 只能用来挖这一条链,
   ⟹ 矿工的资本被【锁定】在链的长期价值上
   ⟹ 攻击链等于摧毁自己设备的价值
   而通用硬件(GPU)可以随时租来攻击,攻击后转手就走

所以 ASIC 在安全上其实是有利的——它把矿工的利益和链绑定了。第 17 讲会展开这个论点。

矿池

单个矿工挖到块的期望时间可能是几十年,收益方差无法承受。矿池把大家的算力集中起来,按贡献分配收益。

份额(share)机制

矿池给矿工一个【难度低得多】的目标(比如低 100 万倍)。
矿工找到满足这个低目标的哈希,就提交一个"份额"作为工作证明。

⭐ 由于无记忆性(第三节),份额数量是算力的无偏估计。
而矿工无法把"真正达标的块"私吞——因为区块里的 coinbase 收款地址是矿池的。

分配方式:

方式 机制 特点
PPS 每个份额立即按期望值付钱 矿工零方差,矿池承担全部风险
PPLNS 按最近 N 个份额的占比分配实际收益 矿池零风险,矿工方差大、跳池受罚

矿池是 PoW 最主要的中心化压力:算力分散在千万台机器上,但决定区块内容(打包哪些交易)的权力集中在少数几个矿池运营者手里

注意区分这两件事:

矿池能做的:   审查交易、重排交易牟利(MEV,第 34 讲)
矿池不能做的: 偷币、凭空增发 —— ⚠️ 这些会被全节点直接拒绝(第 3 讲)

八、能耗:把问题说准确

PoW 的能耗争议里,有两句话经常被混淆:

❌ "算力越高越安全,所以必须消耗大量电力"——不完全对
⭐ 准确的说法是:安全性来自【攻击成本】,
   而攻击成本 = 获取多数算力的成本 ≈ 全网正在消耗的资源

⟹ 能耗不是副作用,它【就是】安全预算本身(第 17 讲)

⚠️ 由此得到一个重要推论:

⭐ 能耗和安全性无法解耦。
   "又要 PoW 的安全性,又要低能耗"在逻辑上不成立——
   除非把安全建立在别的稀缺资源上,那就是 PoS(第 18 讲)。

至于总量:比特币的年耗电量在中等国家的量级。这个数字本身不构成结论——它是否"值得"取决于你如何评价这个系统提供的服务,而那是一个链外的判断,这门课不作评价。

九、Go 实现

package pow

import (
	"crypto/sha256"
	"encoding/binary"
	"math/big"
	"time"
)

// maxTarget 是难度为 1 时的目标值:0xFFFF × 2²⁰⁸
var maxTarget = new(big.Int).Lsh(big.NewInt(0xFFFF), 208)

// CompactToTarget 把区块头里 4 字节的 bits 展开成目标值。
func CompactToTarget(bits uint32) *big.Int {
	exp := bits >> 24
	mant := big.NewInt(int64(bits & 0x00ffffff))
	if exp <= 3 {
		return mant.Rsh(mant, 8*(3-uint(exp)))
	}
	return mant.Lsh(mant, 8*(uint(exp)-3))
}

// Mine 穷举 nonce 直到哈希小于目标值。
// ⭐ 由于无记忆性,这个循环没有任何"接近成功"的中间状态可以利用。
func Mine(header []byte, target *big.Int, maxNonce uint32) (uint32, bool) {
	buf := make([]byte, len(header)+4)
	copy(buf, header)

	for nonce := uint32(0); nonce < maxNonce; nonce++ {
		binary.LittleEndian.PutUint32(buf[len(header):], nonce)

		first := sha256.Sum256(buf)
		h := sha256.Sum256(first[:])

		// 比特币把区块哈希按小端序解释为整数,所以要反转字节
		if new(big.Int).SetBytes(reverse(h[:])).Cmp(target) < 0 {
			return nonce, true
		}
	}
	return 0, false // 4 字节 nonce 可能不够,需要改动 coinbase 的 extraNonce
}

// NextTarget 实现比特币的难度调整。
// actualSpan 由调用方按 "末块时间戳 − 首块时间戳" 计算,
// 这中间只有 2015 个间隔——这就是那个永远修不掉的 off-by-one。
func NextTarget(oldTarget *big.Int, actualSpan time.Duration) *big.Int {
	const expected = 2016 * 10 * time.Minute // 20160 分钟

	// 限幅到 [expected/4, expected*4]
	if actualSpan < expected/4 {
		actualSpan = expected / 4
	}
	if actualSpan > expected*4 {
		actualSpan = expected * 4
	}

	next := new(big.Int).Mul(oldTarget, big.NewInt(int64(actualSpan)))
	next.Div(next, big.NewInt(int64(expected)))

	if next.Cmp(maxTarget) > 0 { // 难度不能低于 1
		return maxTarget
	}
	return next
}

// EstimateHashrate 从难度反推全网算力(次/秒)。
// 这是估算,不是测量——没有人能统计全球矿机。
func EstimateHashrate(difficulty float64, blockTimeSec float64) float64 {
	return difficulty * 4294967296.0 / blockTimeSec // 2³² = 4294967296
}

func reverse(b []byte) []byte {
	out := make([]byte, len(b))
	for i := range b {
		out[i] = b[len(b)-1-i]
	}
	return out
}

十、本讲小结

  • PoW 把"记账权"绑定到计算这个稀缺资源上,思路来自 Adam Back 1997 年的反垃圾邮件方案 Hashcash。
  • 谜题必须同时满足三条:难解易验、无记忆、难度可调。
  • ⭐⚠️ 无记忆性最容易被忽略却最关键:每次尝试独立,没有部分进度 ⟹ 期望收益严格正比于算力占比,不存在先发优势。若谜题有进度积累,网络会迅速中心化。
  • 出块间隔服从指数分布,方差很大:36.8% 的间隔超过 10 分钟,0.25% 超过 1 小时(约每 403 块一次)。“等得越久越快出块"是错的——指数分布无记忆。
  • 难度每 2016 块调整一次,按实际耗时与 20160 分钟的比值,限幅在 [1/4, 4]。限幅防操纵,但也意味着算力骤降时周期会拖很久。
  • 计算耗时用了 2015 个间隔而不是 2016,导致比特币比设计值快 0.05%。共识系统里 bug 一旦上线就成了规范——和 OP_CHECKMULTISIG 的多余 OP_0 同类。
  • “全网算力"是从难度反推的估算值,不是测量值。
  • 以太坊 PoW 时期每块调难度,并有难度炸弹——用技术手段给 PoS 迁移设了一个不可拖延的截止日期。
  • ASIC 在安全上其实有利:设备只能挖这一条链,资本被锁定在链的长期价值上;而通用硬件可以租来攻击、转手就走。
  • 矿池的份额机制利用了无记忆性——份额数是算力的无偏估计。矿池是 PoW 最主要的中心化压力:算力分散但打包权集中
  • 能耗不是 PoW 的副作用,它就是安全预算本身。 “既要 PoW 的安全性又要低能耗"在逻辑上不成立。

思考题

  1. 如果 PoW 谜题改成"找一个哈希,其前导零的个数尽可能多,一小时后前导零最多者出块”,会破坏哪条性质?后果是什么?
  2. 计算 P(出块间隔 > 45 分钟)。如果观察到连续三个间隔都超过 30 分钟,这是异常吗?
  3. 已经等了 20 分钟没出块。下一个 10 分钟内出块的概率是多少?这个答案和"刚出完块"时有区别吗?
  4. 一个周期实际耗时 7 天(算力翻倍)。新目标是旧目标的几倍?如果实际耗时 100 天呢(注意限幅)?
  5. 详细说明那个 off-by-one 为什么让比特币变快,并计算 100 年会累积多少偏差。
  6. 从难度反推算力的公式里,2³² 是怎么来的?(提示:难度 1 时期望要试多少次)
  7. 矿池给矿工的目标难度低 100 万倍。一个矿工提交了 300 万个份额,估算他做了多少次哈希。为什么这个估计是无偏的?
  8. 为什么矿工无法私吞矿池挖到的区块?如果他改掉 coinbase 地址会发生什么?
  9. 论证"ASIC 让链更安全"这个观点,然后给出反方最强的论据。
  10. “PoW 太浪费电,应该改成低能耗的 PoW”——用第八节的推理说明这句话为什么自相矛盾。