05-BTC-实现1

第 5 讲:BTC 实现(一)

1. 本节主线

  1. 本节从“比特币如何具体实现去中心化账本”出发,重点讲 transaction based ledger
  2. 比特币不直接记录“账户余额”,而是通过历史交易和 UTXO(Unspent Transaction Output) 推算余额。
  3. 交易合法性检查的核心问题是:你要花的币是否真的存在、是否已经被花过。
  4. 矿工的激励不仅来自 block reward,还来自 transaction fee
  5. 挖矿并不是对整个区块所有交易直接求 hash,而是对 block header 求 hash,其中包含 Merkle root 来承诺交易集合。

2. 核心概念速览

概念 简要理解 在本节中的作用
Transaction based ledger 基于交易记录的账本模式 比特币采用的账本模型,不直接记录账户余额
Account based ledger 基于账户余额的账本模式 与比特币形成对比,以太坊更接近这种模式
UTXO 尚未被花费的交易输出集合 用于推算余额、检测 double spending
Transaction input 当前交易要花掉的旧输出 必须引用之前某个交易的某个 output
Transaction output 当前交易产生的新收款结果 如果未被花费,就会进入 UTXO 集合
Double spending 同一笔币被重复花费 比特币系统必须防止的核心问题
Transaction fee 输入总额减去输出总额的差值 激励矿工把普通交易打包进区块
Coinbase transaction 区块中的特殊铸币交易 产生 block reward,也可携带 extra nonce
Block reward 矿工成功出块获得的新币奖励 早期是矿工挖矿的主要激励
Block header 区块头 挖矿求 hash 的对象,不包含完整交易列表
Merkle root Merkle tree 的根 hash 在 block header 中承诺整个交易集合
Nonce 挖矿时反复调整的随机数 用于寻找满足 difficulty target 的 block header hash
Extra nonce 通常放在 coinbase transaction 中的额外搜索空间 当 header nonce 空间不够时扩大挖矿搜索范围
Difficulty target 挖矿目标阈值 要求 block header hash 小于等于该目标

3. 知识结构图

这张图可以把本节内容分成三条主线:第一,BTC 的账本模型是基于交易的;第二,UTXO 是检查交易合法性的核心数据结构;第三,矿工通过调整 nonce 和 extra nonce 进行 proof of work,并通过 block reward 与 transaction fee 获得激励。

4. 课程内容详解

4.1 比特币采用 transaction based ledger

比特币是一个去中心化账本,但它不是像银行账户那样直接记录:

A 账户余额 = 多少 BTC
B 账户余额 = 多少 BTC

比特币采用的是 transaction based ledger,也就是账本中记录的是一笔笔交易。

如果想知道某个地址现在有多少 BTC,不能直接查一个“余额字段”,而是要根据历史交易推算:

  1. 曾经有哪些交易把 BTC 转给这个地址;
  2. 这些交易产生的 output 中,有哪些还没有被花掉;
  3. 把这些未花费 output 的金额加起来,得到当前可用余额。

所以,比特币中的“余额”不是系统显式保存的结果,而是由 UTXO 集合 推导出来的。

4.2 UTXO:未花费交易输出集合

UTXO(Unspent Transaction Output) 指的是区块链上所有“还没有被花出去的交易输出”。

一个交易可以有多个 output,其中有些可能已经被花掉,有些可能还没被花掉。

例如:

  • 某笔交易给 B 转了 5 BTC;
  • 同一笔交易给 C 转了 3 BTC;
  • 后来 B 把 5 BTC 花掉了;
  • C 还没有花掉 3 BTC。

那么:

  • 给 B 的那个 5 BTC output 不再属于 UTXO;
  • 给 C 的那个 3 BTC output 仍然属于 UTXO。

UTXO 集合中的每个元素通常需要能够定位到一个具体 output。定位方式是:

  1. 产生该 output 的交易 hash;
  2. 该 output 在该交易中的编号。

也就是说,一个 UTXO 不是只写“某人有多少钱”,而是写:

来自哪一笔 transaction,以及这笔 transaction 的第几个 output。

4.3 为什么全节点要维护 UTXO

全节点维护 UTXO 的核心目的,是为了快速判断新交易是否合法,尤其是检测 double spending

当一个新交易发布时,它会声明自己要花掉之前某些交易的 output。全节点需要检查:

  1. 被引用的 output 是否存在;
  2. 被引用的 output 是否还在 UTXO 集合中;
  3. 如果不在 UTXO 中,说明它要么不存在,要么已经被花过;
  4. 只有在 UTXO 中的 output,才能作为合法 input 被花费。

因此,UTXO 是比特币系统中验证交易合法性的关键数据结构。

它解决的问题不是“怎么显示余额”,而是:

当前这笔交易声称要花的钱,是否真的还没被别人花过?

4.4 交易会消耗旧 UTXO,也会产生新 UTXO

每一笔普通交易都可以理解为一个状态转换过程:

  1. 消耗若干旧的 UTXO;
  2. 产生若干新的 transaction output;
  3. 新 output 如果暂时没有被花掉,就加入 UTXO 集合。

例如:

  • B 原本有一个 5 BTC 的 UTXO;
  • B 把这 5 BTC 转给 D;
  • 那么 B 原来的 5 BTC UTXO 被移除;
  • 同时交易产生一个给 D 的新 output;
  • 如果 D 暂时不花,这个 output 就进入 UTXO 集合。

如果某个人收到 BTC 后永远不花,这个 output 就会长期保留在 UTXO 集合中。可能原因包括:

  1. 持有人主动长期持有;
  2. 私钥丢失,无法再花费;
  3. 地址无人管理。

这也是为什么 UTXO 集合会随着时间增长。

4.5 交易输入、输出与交易费

一笔 BTC 交易可以有多个 input,也可以有多个 output。

基本关系是:

1
total inputs >= total outputs

如果:

1
total inputs = total outputs

则这笔交易没有 transaction fee。

如果:

1
total inputs > total outputs

二者差值就是 transaction fee:

1
transaction fee = total inputs - total outputs

例如:

1
2
3
total inputs  = 1 BTC
total outputs = 0.99 BTC
transaction fee = 0.01 BTC

这 0.01 BTC 会作为交易费给成功打包该交易的矿工。

需要注意:交易费不是显式写在某个 output 里,而是通过 input 总额和 output 总额的差额隐式体现出来。

4.6 为什么需要 transaction fee

矿工打包交易是有成本的:

  1. 需要验证交易是否合法;
  2. 区块中交易越多,区块越大;
  3. 区块越大,网络传播速度可能越慢;
  4. 传播慢可能导致自己挖出的区块更容易成为 orphan block。

如果只有 block reward,某些自私矿工可能只打包自己的交易,而不愿意帮别人打包交易。

所以 BTC 设计了第二种激励机制:transaction fee

交易费可以理解成用户给矿工的小费:

你把我的交易打包进区块,我给你一点手续费。

课程中强调,在某些早期或课程案例阶段,block reward 仍然是矿工主要收益来源。但从长期看,block reward 会不断减半,transaction fee 的重要性会逐渐提高。

4.7 Block reward 与减半机制

成功挖出新区块的矿工可以通过 coinbase transaction 获得 block reward。

BTC 中 block reward 不是固定不变的,而是每隔约 210000 个区块减半一次。

因为 BTC 的平均出块时间约为 10 分钟,所以:

1
2
3
210000 blocks × 10 minutes/block
= 2100000 minutes
≈ 4 years

因此,通常说 BTC 的 block reward 大约每四年减半一次。

课程中提到这个机制的目的,是说明 BTC 的激励结构会变化:

  1. 早期:block reward 是主要激励;
  2. 随着减半进行:block reward 逐渐变小;
  3. 未来:transaction fee 可能越来越重要。

4.8 Transaction based ledger 与 account based ledger 的区别

比特币采用 transaction based ledger,而以太坊更接近 account based ledger。

二者的核心区别如下:

对比项 Transaction based ledger Account based ledger
代表系统 Bitcoin Ethereum
是否显式记录账户余额 不显式记录 显式记录
花钱时是否要说明币的来源 要说明 通常不需要逐个说明来源
核心数据结构 UTXO Account state
隐私性 相对更好一些 账户状态更直接
交易验证重点 input 引用的 UTXO 是否存在且未花费 账户余额是否足够、nonce 是否正确

比特币中,如果你想转给别人 10 BTC,交易必须说明这 10 BTC 从哪里来。

原因是系统没有一个地方直接写着:

1
A 的余额 = 10 BTC

所以交易必须引用之前某些 transaction output,证明自己确实有可花的钱。

4.9 普通转账交易中的脚本验证

课程中还提到 BTC 交易的合法性验证和 script 有关。

每个 input 和 output 都可以带有 script。验证交易时,不是把同一笔交易内部的 input script 和 output script 随便配对,而是:

当前交易的 input script,要和它引用的上一笔交易中的 output script 配对执行。

也就是说:

  1. 当前交易 input 声称要花掉之前某个 output;
  2. 那个旧 output 中有锁定条件;
  3. 当前 input 要提供解锁信息;
  4. 两段 script 拼接执行成功,说明有权花这笔钱。

这体现了 BTC 中“花钱”的本质:

花钱不是修改余额,而是证明自己有资格解锁之前某个 output。

4.10 Block header、Merkle root 与挖矿

挖矿时,矿工不是对整个 block body 里的所有交易直接求 hash。

实际求 hash 的对象是 block header

block header 中包含:

  1. version;
  2. previous block hash;
  3. Merkle root;
  4. timestamp;
  5. difficulty target 的编码形式;
  6. nonce。

其中,完整交易列表不直接放在 block header 中,而是通过 Merkle tree 计算出一个 Merkle root,再把 Merkle root 放进 block header。

这样做有两个作用:

  1. block header 很小,便于反复 hash;
  2. Merkle root 又能承诺整个交易集合,交易一旦被篡改,Merkle root 就会变化,从而导致 block header hash 变化。

所以,虽然挖矿只 hash block header,但这并不意味着交易内容不受保护。

4.11 Difficulty target 与 hash 前导 0

BTC 的 proof of work 要求:

1
H(block header) <= target

target 越小,找到满足条件的 hash 越难。

由于 hash 值通常写成十六进制形式,如果 target 很小,那么满足条件的 hash 往往表现为:

1
前面有一长串 0

这就是为什么区块 hash 经常看起来以很多 0 开头。

这些 0 不是人为添加的,而是 proof of work 难度要求造成的结果。

4.12 Nonce 空间不够与 extra nonce

block header 中的 nonce 通常是 32-bit unsigned integer。

因此它最多只有:

1
2^32

种可能取值。

在挖矿难度很高时,仅仅遍历 2^32 个 nonce 很可能找不到合法 hash。

那么矿工还可以调整什么?

block header 中有些字段不能随意改:

字段 能否随意改 原因
version 不能 协议版本
previous block hash 不能 必须指向当前链末端
difficulty target 不能随意改 按协议周期性调整
timestamp 可小范围调整 时间戳允许一定误差
nonce 可以调整 挖矿搜索空间
Merkle root 可以间接调整 改变交易集合或 coinbase transaction 会影响 Merkle root

关键在于 coinbase transaction

coinbase transaction 有一个 coinbase field,可以写入任意内容。矿工可以把其中一部分当作 extra nonce 使用。

当 coinbase field 改变时:

  1. coinbase transaction 的 hash 改变;
  2. Merkle tree 中相关节点 hash 改变;
  3. Merkle root 改变;
  4. block header 改变;
  5. block header hash 的搜索空间被扩大。

真实挖矿可以理解成两层循环:

1
2
外层:调整 coinbase transaction 中的 extra nonce
内层:调整 block header 中的 nonce

4.13 对教材 PPT 中“hash 交易信息”的误解

课程最后强调了一个容易误解的地方:

有些示意图可能把交易列表和 block header hash 画得过于接近,容易让人误以为:

挖矿时直接把所有 transactions 放进去一起 hash。

正确理解是:

  1. 挖矿 hash 的对象是 block header;
  2. block header 不包含完整交易列表;
  3. block header 只包含 Merkle root;
  4. Merkle root 是由交易集合构造出来的;
  5. 因此交易内容仍然被间接绑定到 block header 上。

所以更准确的表达是:

1
transactions -> Merkle tree -> Merkle root -> block header -> block hash

而不是:

1
block hash = H(all transactions)

5. 关键机制图解

5.1 UTXO 的消耗与生成

这张图说明:一笔交易会消耗旧 UTXO,同时产生新 output。旧 UTXO 被花掉后要从集合中移除;新 output 如果还没被花,就会进入 UTXO 集合。

5.2 交易费的形成

交易费不是一个必须显式写出的 output,而是 input 总额和 output 总额之间的差额。矿工有动力优先打包交易费更高的交易。

5.3 Block header 与 Merkle root

这张图强调:完整交易列表不直接进入 block header。交易集合先形成 Merkle root,Merkle root 再进入 block header。挖矿时反复计算的是 block header hash。

5.4 Extra nonce 如何扩大搜索空间

当 32-bit nonce 不够用时,矿工可以修改 coinbase transaction 中的 extra nonce。这样会改变 Merkle root,从而使 block header 发生变化,提供新的搜索空间。

6. 易混点与常见误解

易混点 正确理解
比特币有没有账户余额? 没有像银行或以太坊那样显式维护账户余额。余额是由 UTXO 推算出来的。
UTXO 是某个用户的余额吗? 不是。UTXO 是一个个尚未被花费的 transaction output,余额是这些 output 的金额总和。
一个 transaction 的 output 要么都花掉,要么都没花? 不对。同一笔交易可以有多个 output,其中一部分可能已花,一部分可能仍在 UTXO 中。
Transaction fee 是写在某个 output 里的吗? 通常不是。它是 total inputs 和 total outputs 的差额。
Coinbase transaction 是普通转账吗? 不是。它没有普通 input,是系统产生新 BTC 的方式。
挖矿是对整个区块所有交易直接求 hash 吗? 不是。挖矿求 hash 的对象是 block header,交易集合通过 Merkle root 间接进入 block header。
Merkle root 只是为了节省空间吗? 不只是。它还用于承诺交易集合,使交易内容被篡改时 block header hash 也会受影响。
Nonce 不够时是不是只能换区块? 不一定。矿工可以通过修改 coinbase transaction 中的 extra nonce 改变 Merkle root,从而扩大搜索空间。
Transaction based ledger 和 account based ledger 只是数据格式不同吗? 不只是格式不同。它们影响余额表示、交易验证、隐私性和系统状态维护方式。
Block reward 和 transaction fee 是一回事吗? 不是。Block reward 是新发行 BTC,transaction fee 来自用户交易输入输出差额。

7. 课堂外补充理解

7.1 为什么 UTXO 模型更像“现金”

UTXO 可以类比成一张张现金钞票。

假设你有两张“电子钞票”:

1
2
3 BTC
7 BTC

你要支付 5 BTC,不能直接从 7 BTC 中“减去 5 BTC”,而是要把 7 BTC 这个 UTXO 整体花掉,然后产生新的 outputs:

1
2
5 BTC 给对方
2 BTC 找零给自己

所以 BTC 交易中经常会出现“找零地址”。

这有助于理解为什么一笔交易可以有多个 input 和多个 output。

7.2 为什么 UTXO 有利于并行验证

UTXO 模型中,不同交易如果花费的是不同 UTXO,它们之间的状态依赖相对清晰。

这使得节点在验证交易时,可以围绕“这个 output 是否还没被花”进行判断。

相比 account based model,UTXO 模型不需要频繁修改同一个账户余额字段,而是不断消耗旧 output、创建新 output。

不过这不是说 UTXO 一定在所有方面都更好。它的代价是交易必须显式说明币的来源,理解和管理起来也更复杂。

7.3 为什么 Merkle root 足以绑定交易集合

Merkle tree 的关键性质是:底层任意一笔 transaction 改变,都会导致它的 transaction hash 改变。

这个变化会沿着树一路向上传递:

1
2
3
4
5
transaction hash 改变
=> 父节点 hash 改变
=> 更高层 hash 改变
=> Merkle root 改变
=> block header hash 改变

因此,虽然 block header 中没有完整交易列表,但只要 Merkle root 放在 block header 里,交易集合就被绑定到了 block header 上。

7.4 Difficulty adjustment 的补充说明

课程文字稿中相关位置可能存在转写误差。BTC 的 difficulty adjustment 通常是每 2016 blocks 调整一次,而不是“15 个区块”。

因为 BTC 目标平均出块时间约为 10 分钟:

1
2016 blocks × 10 minutes/block = 20160 minutes ≈ 14 days

所以难度调整周期大约是两周。

这个机制的目的,是让全网算力变化时,系统仍然尽量维持平均 10 分钟出一个新区块。

8. 本节小结

  1. BTC 采用 transaction based ledger,不直接保存账户余额。
  2. UTXO 是 BTC 交易验证的核心数据结构,用于判断某个 output 是否仍可被花费。
  3. 普通交易会消耗旧 UTXO,并产生新的 transaction outputs。
  4. Transaction fee 来自 total inputs 与 total outputs 的差额,是矿工打包交易的重要激励。
  5. Coinbase transaction 用于产生 block reward,同时可以携带 extra nonce 来扩大挖矿搜索空间。
  6. 挖矿计算的是 block header hash,而不是直接对所有交易求 hash;交易集合通过 Merkle root 进入 block header。
  7. BTC 的长期激励结构会随着 block reward 减半逐渐更加依赖 transaction fee。

9. 自测问题

1. 为什么说比特币没有直接记录账户余额?

参考答案:因为 BTC 使用 transaction based ledger,账本中记录的是一笔笔交易,而不是账户余额字段。某个地址的余额需要通过统计其拥有的未花费 outputs,也就是 UTXO,推算出来。

2. UTXO 集合中每个元素至少需要哪些信息来定位?

参考答案:需要产生该 output 的 transaction hash,以及该 output 在该 transaction 中的编号。

3. 为什么 UTXO 可以用来检测 double spending?

参考答案:如果某个 output 仍在 UTXO 集合中,说明它尚未被花费,可以作为合法 input。如果不在 UTXO 集合中,则说明它不存在或已经被花过,再次花费就是 double spending。

4. 一笔交易的 transaction fee 如何计算?

参考答案:

1
transaction fee = total inputs - total outputs

如果输入总额大于输出总额,差额归成功打包该交易的矿工所有。

5. 为什么 BTC 需要 transaction fee,而不仅仅依赖 block reward?

参考答案:矿工打包和验证交易有成本。如果没有 transaction fee,矿工可能缺乏动力打包别人的交易。随着 block reward 逐渐减半,transaction fee 对维护矿工激励会越来越重要。

6. Coinbase transaction 和普通交易有什么区别?

参考答案:Coinbase transaction 没有普通 input,是矿工在新区块中创建的特殊交易,用于获得 block reward。它的 coinbase field 可以写入任意内容,因此也可以用作 extra nonce。

7. 挖矿时 hash 的对象是什么?完整交易列表是否直接参与 hash?

参考答案:挖矿时 hash 的对象是 block header。完整交易列表不直接放入 block header,而是先形成 Merkle tree,再把 Merkle root 放入 block header。

8. 为什么修改 coinbase field 会影响 block header hash?

参考答案:修改 coinbase field 会改变 coinbase transaction 的 hash,进一步改变 Merkle tree 的路径 hash,最终改变 Merkle root。Merkle root 是 block header 的一部分,因此 block header hash 也会改变。