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