← COMP5567 全部讲次
L04 · 第 3 周

L04 Bitcoin:全网一起刮彩票,中奖线每两周挪一次

交易打包成块,算力抽奖决定谁记账,累计工作量最大的有效链胜出。

一句话版

交易打包成块,靠算力抽奖决定谁记账,累计工作量最大的有效链说了算。

一个类比:全网一起刮彩票

全网矿工在刮同一种彩票。每张票就是一个候选区块:票面上写着上一张中奖票的编号、这一轮要记的账、一个可以随便改的编号(nonce)。刮开的结果是一串 256 位数字(区块头哈希)。中奖线是一个叫 T 的门槛数:刮出来的数小于等于 T 就算中奖,票面上那笔账被全网记下,中奖者拿走奖金(区块奖励 + 本块手续费)。

三件事顺着这个场景看:T 越小中奖越难,nBits 这四个字节就是印在票面上的中奖线;奖金每 210,000 块(约 4 年)砍一半,50 → 25 → 12.5 → 6.25 → 3.125;记录本选择有效分支中累计工作量最大的那一本,两人同时中奖就各自往下接,谁先接长算谁的。

类比在哪里失效:真彩票的中奖率是印好的常数,比特币的 T 每 2016 块(约两周)由全网各自重算一次,目标是把平均出块时间拉回 10 分钟。真彩票中奖当场兑现,比特币「中奖」还要被别人验证接受——票面上的交易必须合法、这张票必须落在累计工作量最大的有效链上,落在被抛弃的分支里就白刮。另外刮票不消耗什么,挖矿烧的是实打实的电。

概念卡

1. UTXO 与找零(Unspent Transaction Output)

人话定义:钱不以余额形式存在,只以一张张「还没花掉的输出」存在。花钱 = 用签名解锁一张旧输出,造出若干张新输出。

例子:课件 p.12 里 Bob 手上有一笔 13 BTC(= 12.5 奖励 + 0.5 手续费)。他要给 Alice 10,交易只能写成两个输出:Alice 10 + Bob 3,那个 3 是找零,因为一张 UTXO 只能整笔花掉。签名由被花那张输出的所有者做——花 55[0] 要 Alice 签,花 56[0] 要 Bob 签。

一进两出的流转:

一笔交易的输入输出流向:左边是输入 56[0],金额 13 BTC,等于 12.5 区块奖励加 0.5 手续费,由 Bob 签名解锁;右边是两个输出,输出 1 给 Alice 10 BTC,输出 2 给 Bob 3 BTC 作为找零;10 加 3 正好等于 13,没有留手续费,若删掉找零输出这 3 BTC 会被矿工当手续费收走

常见误解

以为 UTXO 模型里有个「余额」字段 → 没有这个字段,钱包显示的余额是客户端扫链把属于你的 UTXO 加总算出来的。手续费同样没有显式字段,它等于所有输入金额之和减所有输出金额之和,矿工把差额塞进 coinbase(p.11、p.15)。

2. 区块头 6 字段与 PoW(Proof-of-Work)

人话定义:真正被哈希的只有区块头,共 6 个字段 80 字节;矿工不停改 Nonce 重算,直到区块头哈希 ≤ T。PoW 的三要素是难产生、易验证、满足特定条件。

例子:区块 #544858 的区块头字段(p.8)——Version 0x20000000、Prev Hash、Merkle Root、Timestamp、Bits 388350353、Nonce 3378547724。它的 Hash 开头有 18 个十六进制 0,这就是「哈希 ≤ T」在视觉上的样子。

常见误解

把 p.19 表里的 Magic Num 和 Block Size 也当成区块头字段 → 那两项是 P2P 消息的外壳,不参与哈希。答「区块头有哪些字段」只写 6 个:Version(4) + Prev Hash(32) + Merkle Root(32) + Time(4) + nBits(4) + Nonce(4)。

3. nBits → 目标阈值 T → 期望尝试次数

人话定义:nBits 是 4 字节,用 Base-256 科学计数法压缩表示 256 位的大数 T。记 nBits = b₁b₂b₃b₄,则 T = (b₂b₃b₄) × 256^(b₁ − 3),b₁ 是缩放指数;真实 compact 编码的后三字节含符号位,不能一律当无符号尾数。

例子:2017-01-01 的 nBits = 0x180375ff(p.26)。指数 0x18 = 24;尾数 0x0375ff ≈ 0x040000 = 2¹⁸;T = 2¹⁸ × 256²¹ = 2¹⁸ × 2¹⁶⁸ = 2¹⁸⁶;期望尝试次数 = 2²⁵⁶ / 2¹⁸⁶ = 2⁷⁰。不取整的话 0x0375ff = 226,815 ≈ 2^17.79,T ≈ 2^185.79,期望次数 ≈ 2^70.21。

四个字节怎么拆:

nBits 0x180375ff 拆成四个字节:首字节 0x18 是指数,后三字节 0x03、0x75、0xff 是尾数;0x18 等于 24,指数减 3 得 21;尾数 0x0375ff 约等于 0x040000 也就是 2 的 18 次方;于是目标阈值 T 等于 2 的 18 次方乘 256 的 21 次方,等于 2 的 186 次方,期望尝试次数为 2 的 256 次方除以 T 加 1,约 2 的 70 次方

常见误解

把指数直接当成 256 的幂次 → 要减 3,因为尾数本身占 3 个字节。指数 < 3 时反过来砍尾数低位:0x02123456 的 T = 0x123456 × 256⁻¹ = 0x1234,末字节 0x56 丢掉(p.23)。另外单次命中概率是 (T+1)/2²⁵⁶,那个 +1 来自「≤ T 的整数有 T+1 个」,算近似值时可以忽略,写公式时不能漏。

4. 难度调整(Difficulty Retarget)

人话定义:T 是全网统一的设置,每 2016 块重算一次,目标是平均 10 分钟出一块。算力测不到,于是用实测出块时长反推。

例子:理想关系 600 · R = 2²⁵⁶ / (T + 1)(R 是全网每秒哈希次数)——全网每秒试 R 次,期望出块时间 = 2²⁵⁶/((T+1)·R),令它等于 600 秒即得。算力翻倍,T 减半。实际调整用 T_new = T_old × 实测时长 / (2016 × 600),主网实际取高度 2016n−1 与 2016(n−1) 的时间差(2015 个间隔),再以 2016×600 秒为分母;另有调整幅度限制。2016 × 10 分钟 = 20160 分钟 = 14 天,这就是「约两周」的来历(p.28–29)。

常见误解

以为难度可以任意跳变 → 真实实现把单次调整幅度钳在 1/4 到 4 倍之间(补充)。实测时长靠矿工自填的 nTime,所以 p.21 那两条时间规则是难度机制的防线,操纵它的攻击叫 timejacking。

5. 分叉、累计工作量与确认数

人话定义:两个矿工几乎同时出块就会分叉,节点选择自己已知累计工作量最大的有效分支。落选的那支叫 stale block。

例子:p.32 的图里上支 A → A′ → A″ 三块、下支 B → B′ 两块,最终所有节点切到上支。B、B′ 中尚未被新链包含、仍有效且符合本地策略的普通交易可回到 mempool,等着重新打包;它们的 coinbase 直接作废,挖 B、B′ 的矿工白干。正因为上链不等于最终确定,商家要等 6 个确认——你的交易所在的块之后又接了 5 个块(p.33、p.41)。

两件事画在一起:

上半是分叉:Block N 之后分出两支,上支 A、A′、A″ 共三块被认作最长链,下支 B、B′ 两块作废,输的那支叫 stale block,里面的普通交易回 mempool 重新打包,coinbase 直接作废;下半是确认数,你的交易所在的块之后又接了 5 个块,合计 6 个确认

常见误解

以为 stale block 的 coinbase 也能回 mempool → 不行,那笔钱是凭空创造的,没有可以退回的输入。「6」是白皮书按攻击者算力占比估的经验值:攻击者占 10% 算力时追平 6 块领先的概率已低于 0.1%,占比过半则再多确认也没用(补充)。

把它们串起来

主线只有一条:一个区块被接受要过三道关。第一关交易合法——被引用的输出存在且没花过、签名对得上,归 UTXO 模型管。第二关区块头哈希 ≤ T,归 PoW 管,也是这一讲唯一要动笔算的部分。第三关成为累计工作量最大有效链的一部分,归共识管。

第二关那个 T 又有自己的一条线:nBits 四个字节编码出 T → T 决定单次命中概率 (T+1)/2²⁵⁶ → 网络算力 R 决定 T 该多大(600R = 2²⁵⁶/(T+1))→ 每 2016 块按实测出块时间修正 T。这条线上的四个公式(p.23、p.25、p.28、p.29)串起来就是整个 Part 2。

Part 3 的四项技术各补一个缺口:Merkle 树让区块头用一个根锁住全部交易,还能剪枝和局部验证;确认数把「上链」和「最终」之间的缝补上;51% 攻击划出这套机制的能力边界(2018 年 5 月 Bitcoin Gold 的真实案例损失超过 1800 万美元);P2P 与 gossip 说明消息怎么走到所有节点——交易和块的传播都是「先验证再转发」的泛洪,和前面讲过的可靠广播同源,区别在于开放网络成员不固定,可靠性是概率意义上的。

左右两张对比图。左图是完整的 Merkle 树:四笔交易 Tx0 到 Tx3 各自哈希成 Hash0 到 Hash3,两两合并成 Hash01 和 Hash23,再合并成区块头里的 Root Hash,区块头里还有 Prev Hash 和 Nonce。右图是剪掉 Tx0 到 Tx2 之后:这三笔交易和 Hash0、Hash1 都不再保留,只留下 Hash01、Hash2、Hash3 和 Tx3,仍然能一路算回同一个 Root Hash
图片来源:COMP5567 Lecture_4-Bitcoin.pdf, p.38

课件里的坑

  • [课件有误] 课件 Exercise-3 题面写「refer to slide 9」→ 第 9 页是区块体截图,nBits 的例子在 p.23 和 p.26,这是旧版课件的页码没更新(p.59)
  • [读图提醒] p.19 的蓝色括号已经把 Magic Num、Block Size 排除在区块头外。真正进哈希的头部是 6 个字段、80 字节;不要因它们画在同表就加进去。这不是课件混淆字段。
  • [口径差异] 课件 p.6、p.8、p.12、p.14 的例子全按 12.5 BTC 算 → 那是 2016-07-09 到 2020-05-11 之间的奖励值,做题时以题面给的奖励为准(p.6)
  • [课件有误] 课件把 SPV 写成 Simple Payment Verification → 白皮书原文是 Simplified Payment Verification(p.52)
  • [口径差异] 课件写「切换到最长分支」→ 严格说比的是累计工作量最大的链,难度相同的短期内两种说法等价(p.33)

课后 10 分钟:考点复习

这 10 分钟怎么用:合上页面,先默写三条——coinbase 与找零的写法、T = 尾数 × 256^(指数−3)、难度调整公式;再把下面的「变式题」做一遍;最后回查两个最容易错的地方——把指数直接当成 256 的幂次、以为 stale block 的 coinbase 能回 mempool。三步做完再往下看答案。

必背

  1. 减半:每 210,000 块(约 4 年)奖励减半,50 → 25 → 12.5 → 6.25 → 3.125;2100 万 = 210,000 × 50 × 2,约 2140 年到顶。
  2. Tx[0] 是 coinbase:不花费已有 UTXO,输出总额至多为区块补贴 + 本块手续费;手续费 = 输入和 − 输出和;UTXO 只能整笔花,找零写成输出。
  3. 区块头 6 字段共 80 字节:Version / Prev Hash / Merkle Root / Time / nBits / Nonce;Magic Num 与 Block Size 不进哈希。
  4. 正目标 T 按 compact 指数与有效尾数解码,并检查符号位;p = (T+1)/2²⁵⁶,期望尝试次数 = 2²⁵⁶/(T+1)。
  5. 600R = 2²⁵⁶/(T+1);T_new = T_old × 实测时长 / (2016 × 600),实测时长取两块 nTime 之差。
  6. nTime 两条规则:大于前 11 块 nTime 的中位数;不超过网络调整时间 2 小时。
  7. 分叉按累计工作量裁决;stale block 的普通交易仍有效且符合本地策略才可回 mempool,coinbase 作废;6 个确认 = 本块之后再接 5 块。
  8. 51% 攻击能双花、能审查交易,不能偷别人的币、不能改规则。

完整例题

期末 3 小时开卷,范围含 lectures、tutorials 和 project。后面这句是我的判断:开卷场景下查得到的事实考查价值低,现场要推的题才是重点,nBits 换算就是这一讲最典型的一道。Exercise-3 两问是同一套公式的正反两个方向。

(1) 要让期望尝试次数约为 2⁹⁰,nBits 该设多少?

  1. 期望次数 = 2²⁵⁶/(T+1) ≈ 2⁹⁰,反解得 T ≈ 2²⁵⁶⁻⁹⁰ = 2¹⁶⁶
  2. 把 2¹⁶⁶ 写成「尾数 × 256^(指数−3)」:166 = 6 + 8 × 20,所以 2¹⁶⁶ = 2⁶ × 256²⁰ = 0x40 × 256²⁰。
  3. 取规范形式:2¹⁶⁶ = 0x400000 × 256¹⁸,指数 = 18+3 = 21 = 0x15。
  4. 规范 nBits = 0x15400000。验算:2²² × 2¹⁴⁴ = 2¹⁶⁶ ✓。
  5. 0x17000040、0x16004000 在简化算式下也解码为同一个 T,但不是 Bitcoin Core 输出的规范形式;不能当作可随意替换的区块字段。

(2) 课件给 nBits = 0x15c31b18,难度是多少?

补充核验:这个值设置了 0x00800000 符号位,真实 Bitcoin PoW 会拒绝它,没有合法的正目标难度。下面仅复现课件忽略符号位的无符号算术,不代表有效区块编码。

  1. 拆字节:指数 = 0x15 = 21,尾数 = 0xc31b18 = 12,786,456 ≈ 2^23.6。
  2. T = 0xc31b18 × 256^(21−3) = 0xc31b18 × 256¹⁸ ≈ 2^23.6 × 2^144 = 2^167.6
  3. 单次命中概率 p = (T+1)/2²⁵⁶ ≈ 2^−88.4。
  4. 期望尝试次数 ≈ 2²⁵⁶/T ≈ 2^88.4(约 4 × 10²⁶ 次)。
  5. 若按相对最大目标 0x1d00ffff 的定义:difficulty = T_max/T = (0xffff × 256²⁶)/(0xc31b18 × 256¹⁸) ≈ 2^56.4 ≈ 9.5 × 10¹⁶
  6. 题目问 hashing difficulty,课件语境指的是期望尝试次数 2^88.4(和 p.26「约 2⁷⁰ 次」同一口径);把相对难度也写上并注明定义,两种理解都覆盖。对照 (1):这里的 T 比 2¹⁶⁶ 大约 3 倍,期望次数比 2⁹⁰ 少约 3 倍,数量级对得上。

变式题(先自己做)

同一套公式,换两个数正反各走一遍:

(1) 要让期望尝试次数约为 2⁸⁰,nBits 该设多少? (2) nBits = 0x1a01ffff,期望尝试次数约是多少?

提示

第一问先反解 T,再写成规范 compact 编码:取最高有效字节,注意符号位;不能把任意同值的非规范写法都当成协议预期的 nBits。

参考答案与自检(非官方评分标准)

自检要点:① 反解那一步必须写成 T ≈ 2^(256 − 期望指数);② 编码要落回规范的「有效尾数 + 指数」两段,检查符号位;③ 正向题要说清用的是哪种难度口径。

(1) T ≈ 2²⁵⁶⁻⁸⁰ = 2¹⁷⁶。规范写法:2¹⁷⁶ = 0x010000 × 256²⁰;指数 = 20+3 = 23 = 0x17,故 nBits = 0x17010000。0x18000100 等可解码为同值,但不是规范编码。

(2) 指数 = 0x1a = 26,尾数 = 0x01ffff = 131,071 ≈ 2¹⁷。T ≈ 2¹⁷ × 256²³ = 2¹⁷ × 2¹⁸⁴ = 2²⁰¹。期望尝试次数 ≈ 2²⁵⁶ / T = 2⁵⁵ ≈ 3.6 × 10¹⁶。若换相对难度的口径:T_max = 0xffff × 256²⁶ ≈ 2²²⁴,difficulty = T_max / T ≈ 2²³ ≈ 8.4 × 10⁶。两个数差得很远却都没错,因为定义不同——答题时把口径写出来。

闪卡自测

1. 课件 p.12 里 B56 的 coinbase 为什么是 13 而不是 12.5?这 0.5 从哪来?

coinbase 金额 = 区块奖励 + 本块全部手续费。B56 的奖励是 12.5,块里 Tx[1] 那笔交易输入 12.5、输出 12,差额 0.5 就是手续费(p.11、p.12)。

2. Bob 想给 Alice 10,交易里为什么还有一个「Bob 3」的输出?去掉它会怎样?

一张 UTXO 只能整笔花掉,Bob 那笔 13 必须一次用完,剩下的 3 要显式打回自己地址。去掉这个输出,那 3 BTC 就变成输入减输出的差额,被矿工当手续费收走(p.12)。

3. nTime 的两条校验规则是什么?第一条为什么用中位数?

必须大于前 11 个块 nTime 的中位数,防止时间倒流;不能超过接收节点的网络调整时间 2 小时以上,防止填到未来。用中位数是为了让单个矿工填错的时间戳影响不了后续(p.21)。

4. 把 0x02123456 和 0x08123456 各自解码成 T。

0x02123456:指数 2,T = 0x123456 × 256⁻¹ = 0x1234(末字节 0x56 丢掉)。0x08123456:指数 8,T = 0x123456 × 256⁵ = 0x1234560000000000(p.23)。

5. 写出单次命中的概率公式并推出期望尝试次数;用 0x180375ff 算一遍。

p = (T+1)/2²⁵⁶,首次命中所需尝试次数服从几何分布,期望尝试次数 = 1/p = 2²⁵⁶/(T+1)。0x180375ff:指数 24、尾数 ≈ 2¹⁸,T = 2¹⁸ × 256²¹ = 2¹⁸⁶,期望次数 = 2⁷⁰(p.25、p.26)。

6. 推导 600R = 2²⁵⁶/(T+1)。算力翻倍时 T 该怎么变?

期望尝试次数是 2²⁵⁶/(T+1),全网每秒试 R 次,期望出块时间 = 2²⁵⁶/((T+1)·R),令它等于 600 秒即得。整理成 T + 1 = 2²⁵⁶/(600R),算力翻倍则 T 减半(p.28)。

7. 写出难度调整公式。若过去 2016 块只用了 7 天,T 应乘以多少?

T_new = T_old × 实测时长/(2016 × 600)。预期是 14 天,实测 7 天,T 乘以 1/2(p.29)。

8. stale block 里的普通交易和 coinbase 分别怎么处理?coinbase 为什么不能回 mempool?

普通交易未被新链包含、仍有效且符合本地策略时可回 mempool;冲突交易不能直接回去。coinbase 含特殊输入,不花费已有 UTXO,只能随所属有效区块生效,不能作为普通交易重新打包(p.33,补充限定)。

9. 剪掉 Tx0–Tx2 后需要保留哪些哈希才能重算 Root?要向只有 Root 的人证明 Tx3 在块里需要给什么?

保留 Hash01 和 Hash2(加上 Tx3 与 Hash3)就能重算出 Root。证明 Tx3 在块里需要给 Hash2 和 Hash01:对方算 H(Hash2 ‖ H(Tx3)) = Hash23,再算 H(Hash01 ‖ Hash23) 比对 Root,证明大小 O(log n)(p.36 补充、p.38)。

10. 32 位 nonce 最多 2³² 个取值,远小于 2⁷⁰,矿工怎么办?

改 coinbase 交易里可自由填的 extraNonce 字段,它会改变 Merkle Root,从而换出一整批新的区块头;nTime 在允许区间内微调也是常用变量(p.24 补充)。

11. 51% 攻击者能做哪三件事、不能做哪两件事?

能做:回滚自己的近期交易(双花)、阻止某些交易入块、让诚实矿工的块作废。不能做:花别人的币(没有私钥)、改区块奖励或凭空造币,因为每个节点独立验证交易与签名(p.43–44 补充)。

下一讲

下一讲是 Ch5 PoW and PoS。这一讲只把「找 nonce」正式命名为 PoW,没碰它的能耗、去中心化和安全性权衡,PoS 完全没提。带着「PoW 花的是电,PoS 花的是什么」这个问题去听。

下一讲的通俗笔记上完课会补,先回 COMP5567 课程页

个人整理的学习笔记,不是官方材料;数字与结论以课件和讲师为准。