第 4 讲:BTC 协议(一)

第 4 讲:BTC 协议(一)
agsd依据附件文字稿与笔记生成指南整理。
第 4 讲:BTC 协议(一)
1. 本节主线
- 本节从“如何设计一种数字货币”出发,引出数字货币最核心的问题:double spending attack。
- 单纯依靠数字签名只能证明“货币由谁发行、交易由谁授权”,但不能阻止数字文件被复制后重复花费。
- 中心化系统可以通过央行数据库记录每个币的归属来防止 double spending,但这依赖中心机构。
- Bitcoin 的核心思路是:把“央行数据库”改造成由所有用户共同维护的 blockchain。
- 本节重点解释 Bitcoin transaction、hash pointer、public key hash、Bitcoin script、block header / block body、full node / lightweight node 之间的关系。
2. 核心概念速览
| 概念 | 简要理解 | 在本节中的作用 |
|---|---|---|
| 数字签名(digital signature) | 用 private key 签名,用 public key 验证 | 证明交易确实由币的拥有者授权 |
| double spending attack | 同一份数字货币被复制后重复花费 | 数字货币系统必须解决的核心问题 |
| 中心化数据库 | 由中心机构记录每个币当前归谁所有 | 可以防止 double spending,但依赖中心机构 |
| 区块链(blockchain) | 由全体节点共同维护的交易历史数据结构 | 在去中心化环境中记录币的流转历史 |
| 铸币交易(coinbase transaction) | 凭空产生新币的特殊交易 | Bitcoin 中发行新币的入口 |
| 交易输入(transaction input) | 指明本次花费的币来自之前哪笔交易输出 | 证明“我花的钱确实有来源” |
| 交易输出(transaction output) | 指明收款人的 public key hash 和金额 | 规定这笔钱以后由谁能花 |
| 哈希指针(hash pointer) | 通过 hash 引用并校验前面的数据 | 连接区块,也用于追溯币的来源 |
| Bitcoin script | Bitcoin 中验证交易合法性的脚本机制 | 用于检查签名、公钥和前序输出是否匹配 |
| block header | 区块头,存放区块宏观信息 | 参与区块之间的 hash pointer 链接 |
| block body | 区块体,存放交易列表 | 交易通过 Merkle tree 组织 |
| Merkle tree | 用 hash tree 组织多笔交易 | 通过 Merkle root 保护交易列表不被篡改 |
| full node | 保存完整区块链并验证所有交易的节点 | 真正参与交易合法性验证 |
| lightweight node | 只保存 block header 的轻节点 | 不能独立验证所有交易合法性 |
3. 知识结构图
flowchart TD
A[设计数字货币] --> B[中心化方案]
A --> C[去中心化方案]
B --> B1[央行签名发行]
B1 --> B2[数字文件可复制]
B2 --> B3[double spending attack]
B3 --> B4[央行数据库记录归属]
B4 --> B5[正确但中心化]
C --> C1[Bitcoin]
C1 --> C2[发行问题]
C1 --> C3[交易验证问题]
C2 --> C21[挖矿决定]
C3 --> C31[blockchain 记录交易历史]
C31 --> C32[transaction input 追溯来源]
C31 --> C33[transaction output 绑定收款人]
C32 --> C34[防止重复花费]
C33 --> C35[public key hash 验证所有权]
C31 --> D[区块结构]
D --> D1[block header]
D --> D2[block body]
D2 --> D3[Merkle tree]
这张图展示了本节课的主线:先从中心化数字货币出发,发现 digital signature 不能解决 double spending,于是需要维护“币的历史流转记录”。中心化方案由央行维护数据库,Bitcoin 则用 blockchain 让全网共同维护这份记录。
4. 课程内容详解
4.1 为什么不能只用央行签名发行数字货币?
最直观的数字货币方案是:
- 央行拥有一对 public key / private key。
- 央行用 private key 对一份数字文件签名。
- 文件内容写着“100 元,signed by central bank”。
- 所有人都知道央行的 public key,所以收到这份数字货币后可以验证签名。
这个方案看起来像纸币:纸币有防伪标记,数字货币有央行签名。但它有一个致命问题:数字文件可以被复制。
纸币的特点是:我把 100 元纸币给你之后,我手里就没有这张纸币了。
数字文件的特点是:我把文件发给你之后,我仍然可以保留副本,甚至复制很多份继续发给别人。
所以,digital signature 只能证明:
这份文件确实是央行签过名的,内容没有被篡改。
但它不能证明:
这份文件以前有没有被花过。
这就是 double spending attack:同一份数字货币被重复花费。
4.2 中心化方案如何解决 double spending?
为了解决 double spending,可以给每个数字货币加上唯一编号。例如:
- 100 元数字货币编号为 017;
- 50 元数字货币编号为 092。
然后由央行维护一张数据库表:
| 货币编号 | 当前所有者 |
|---|---|
| 017 | A |
| 092 | B |
当 A 想把编号 017 的数字货币转给 B 时,B 不仅要验证央行签名,还要向央行确认:
- 这个币是否真实存在;
- 这个币当前是不是属于 A;
- 这个币之前有没有被 A 花掉。
如果确认合法,央行就更新数据库:
| 货币编号 | 当前所有者 |
|---|---|
| 017 | B |
这样,A 如果再把同一个编号 017 的币转给 C,C 去央行查询时就会发现:这个币已经不属于 A 了,所以交易无效。
这个方案在正确性上没有大问题,但它是 centralized 的:每次交易都必须经过央行确认。Bitcoin 想解决的问题就是:能不能不依赖中心机构,也能防止 double spending?
4.3 去中心化货币要解决的两个问题
一个 decentralized cryptocurrency 至少要解决两个问题:
货币发行问题
没有央行之后,谁有权发行货币?什么时候发行?发行多少?交易验证问题
没有央行数据库之后,谁来判断一笔交易是否合法?怎样防止 double spending?
本节课主要讨论第二个问题:交易验证。第一个问题在 Bitcoin 中由 mining 解决,后续课程会展开。
4.4 Bitcoin 的基本思路:用 blockchain 替代央行数据库
中心化方案中,央行数据库记录每个币的流转历史。Bitcoin 的思路是:
不让央行维护数据库,而是让所有节点共同维护一份公开的交易历史,这份数据结构就是 blockchain。
在 Bitcoin 中,判断一笔交易是否合法,不是看某个中心账户余额,而是沿着交易输入向前追溯:
- 这笔钱从哪里来?
- 之前有没有被花掉?
- 当前交易是否由有权花这笔钱的人签名?
如果一笔钱已经被用作某个交易的 input,又再次被另一个交易作为 input 使用,那么后一个交易就是 double spending,节点不会接受它。
4.5 Bitcoin transaction 的 input 和 output
Bitcoin 中每个 transaction 通常包含两部分:
| 部分 | 内容 | 作用 |
|---|---|---|
| transaction input | 指向之前某笔 transaction 的 output,并提供签名、公钥等验证信息 | 说明“我花的钱从哪里来,以及我有权花它” |
| transaction output | 指定金额和收款人的 public key hash | 说明“这笔钱以后归谁控制” |
一个简化例子:
- 某个矿工通过 coinbase transaction 创建 10 BTC 给 A。
- A 把 10 BTC 分成两份,分别转给 B 和 C,每人 5 BTC。
- B 再把自己的 5 BTC 分成两份,转给 C 2 BTC、转给 D 3 BTC。
- 此时 C 一共有 7 BTC:来自 A 的 5 BTC,加上来自 B 的 2 BTC。
- C 可以把这 7 BTC 一起转给 E。
这里要注意:Bitcoin 中的钱不是一个简单的“账户余额数字”,而是一系列可以被花费的 transaction output。你要花钱,就要在 input 中指出你花的是以前哪一个 output。
4.6 两类 hash pointer:连接区块与追溯币来源
本节课强调了两类 hash pointer:
| 类型 | 指向哪里 | 作用 |
|---|---|---|
| 区块之间的 hash pointer | 指向前一个 block header | 把区块串成 blockchain |
| 交易中的来源指针 | 指向之前某笔 transaction 的 output | 说明本次花费的币从哪里来 |
第一类 hash pointer 让区块链形成链式结构,防止历史区块被篡改。
第二类 hash pointer 让交易之间形成“币的来源关系”,用于检查这笔钱有没有被重复花费。
4.7 为什么只验证签名还不够?
假设 B 已经把 5 BTC 转给了 C 和 D。之后 B 又想把同一笔 5 BTC 转给 F。
B 对第二笔交易签名,这个签名本身可能是真的,因为确实是 B 发起的交易。但问题是:B 已经把这 5 BTC 花掉了。
所以节点不能只检查:
签名是不是 B 的?
还必须检查:
B 声称要花的这笔钱,现在是否还没有被花过?
这就是为什么 transaction input 必须指向币的来源。节点会沿着 input 指向的前序交易回溯,检查该 output 是否已经被使用过。如果已经被使用过,就拒绝这笔交易。
4.8 收款地址、公钥和 public key hash
A 要给 B 转账,需要知道 B 的地址。Bitcoin address 可以理解为从 B 的 public key 推导出来的标识,核心是 public key hash。
这里可以类比银行账号:
- 你给别人银行转账,需要知道对方账号。
- Bitcoin 转账也需要知道对方 address。
- Bitcoin 系统本身不会提供“输入某个人姓名,查询他的地址”的功能。
- 收款人需要通过其他渠道告诉付款人地址,例如网站页面、二维码等。
但是,交易验证时还有另一个问题:所有节点都要验证付款人的签名,因此所有节点都需要知道付款人的 public key。
那么付款人的 public key 从哪里来?
答案是:由当前 transaction input 自己给出。
这看起来似乎有安全漏洞:如果攻击者把自己的 public key 冒充成 A 的 public key,再用自己的 private key 签名,是不是就能偷走 A 的钱?
答案是不能。因为前一笔 transaction output 中写的是 A 的 public key hash。当前 input 中给出的 public key 必须满足:
hash(input 中给出的 public key) = 前序 output 中记录的 public key hash
如果攻击者给出自己的 public key,它的 hash 和前序 output 中记录的 A 的 public key hash 对不上,验证就不会通过。
因此,Bitcoin 的验证逻辑不是单独检查签名,而是同时检查:
- input 指向的币来源是否存在;
- 该来源是否尚未被花费;
- input 中给出的 public key 是否和前序 output 中的 public key hash 匹配;
- signature 是否能用这个 public key 验证通过。
4.9 Bitcoin 不是“加密系统”,而是“签名验证系统”
课堂中有一个容易混淆的问题:能不能用 private key 加密交易,然后用 public key 解密,来证明交易来自 A?
这里要区分 encryption 和 signature:
| 机制 | 使用方式 | 目标 |
|---|---|---|
| encryption | 通常用接收者 public key 加密,接收者用 private key 解密 | 保密,让别人看不懂内容 |
| digital signature | 发送者用 private key 生成签名,别人用发送者 public key 验证 | 认证,证明是发送者授权且内容未被篡改 |
Bitcoin 的 transaction 内容本身不是为了保密,而是要公开给全网节点验证。所以 Bitcoin 不是把交易“加密隐藏起来”,而是让交易公开,并附带 signature 供所有节点验证。
4.10 Bitcoin script 如何验证交易?
Bitcoin 中,transaction input 和 transaction output 都包含 script。
简化理解:
- 前一笔 transaction output 中的 script 规定:“谁能花这笔钱?”
- 当前 transaction input 中的 script 提供:“我来证明我有权花这笔钱。”
验证时,节点会把当前 input script 和前序 output script 拼接起来执行。如果执行成功,说明当前交易满足前一笔 output 设置的花费条件。
以常见支付为例,可以理解为:
前序 output 中记录收款人的 public key hash;
当前 input 提供 public key 和 signature;
脚本执行时检查:
- public key 的 hash 是否等于前序 output 中记录的 public key hash;
- signature 是否能用 public key 验证通过。
如果两个条件都满足,说明这个人确实有权花这笔钱。
4.11 block header、block body 与 Merkle tree
课堂前面的例子中,为了方便理解,好像每个 block 只包含一笔 transaction。实际 Bitcoin 系统中,一个 block 可以包含很多 transactions。
一个 block 分成两部分:
| 部分 | 包含内容 | 作用 |
|---|---|---|
| block header | version、previous block hash、Merkle root、target / nBits、nonce 等 | 区块的宏观信息,参与 hash pointer 链接和 mining |
| block body | transaction list | 保存该区块中的交易 |
transaction list 不直接全部放进 block header,而是组织成 Merkle tree。block header 中只保存 Merkle root。
这样做的好处是:
- Merkle root 能代表整棵交易树;
- 只要 block body 中任意 transaction 被篡改,Merkle root 就会变化;
- block header 的 hash 也会变化;
- 因此交易列表受到 block header 的保护。
课堂中还特别强调:区块之间的 hash pointer 指向的是前一个 block header。也就是说,串起 blockchain 的主要是 block header,而不是整个 block body。
4.12 full node 和 lightweight node
Bitcoin 节点分为:
| 节点类型 | 保存内容 | 能否独立验证交易 |
|---|---|---|
| full node / fully validating node | 保存完整 blockchain,包括所有 block body 和 transactions | 可以 |
| lightweight node | 通常只保存 block header | 一般不能 |
full node 可以检查一笔交易是否 double spending,因为它保存了完整历史,可以追溯之前的 transaction output 是否已经被花过。
lightweight node 只保存 block header,不保存完整交易历史,所以它通常不能独立判断某笔交易是否 double spending。它更多是利用 blockchain 信息进行查询或轻量验证。
5. 关键机制图解
5.1 从中心化数据库到 blockchain
flowchart LR
A[数字货币文件] --> B[央行签名]
B --> C[可以验证真伪]
C --> D[但文件可复制]
D --> E[double spending]
E --> F[中心化方案]
F --> G[央行数据库记录归属]
G --> H[每次交易找央行确认]
E --> I[Bitcoin 方案]
I --> J[全网维护 blockchain]
J --> K[交易历史公开可查]
K --> L[检查币是否已被花费]
这张图说明:digital signature 解决的是“真伪问题”,不是“重复花费问题”。要防止 double spending,必须有一份记录币流转历史的数据结构。中心化系统用央行数据库,Bitcoin 用 blockchain。
5.2 transaction input / output 的来源追溯
flowchart TD
T0[coinbase transaction<br/>create 10 BTC to A] -->|output: A public key hash| T1[A transfers<br/>5 BTC to B<br/>5 BTC to C]
T1 -->|B's 5 BTC output| T2[B transfers<br/>2 BTC to C<br/>3 BTC to D]
T1 -->|C's 5 BTC output| T3[C has 5 BTC]
T2 -->|C's 2 BTC output| T4[C has total 7 BTC]
T3 --> T5[C transfers 7 BTC to E]
T4 --> T5
这张图表示 Bitcoin 中“钱”的来源不是账户余额,而是之前 transaction 留下的 output。C 的 7 BTC 来自两个不同的 output:A 给 C 的 5 BTC,以及 B 给 C 的 2 BTC。C 花钱时需要在 input 中同时引用这两个来源。
5.3 防止伪造付款人公钥
flowchart TD
A[前序 output<br/>记录 A public key hash] --> B[当前 input<br/>提供 public key]
B --> C{hash(public key)<br/>是否等于前序 hash}
C -->|否| D[验证失败]
C -->|是| E{signature<br/>是否验证通过}
E -->|否| F[验证失败]
E -->|是| G[有权花费该 output]
这张图说明:当前 input 中的 public key 虽然是交易自己提供的,但不能随便伪造。因为它必须和前序 output 中记录的 public key hash 对得上,同时 signature 也必须能验证通过。
5.4 block header 与 block body 的关系
flowchart TD
B[Block] --> H[Block header]
B --> Body[Block body]
H --> V[version]
H --> P[previous block hash]
H --> M[Merkle root]
H --> T[target / nBits]
H --> N[nonce]
Body --> L[transaction list]
L --> MT[Merkle tree]
MT --> M
P --> Prev[previous block header]
这张图说明:block body 里存交易列表,交易列表通过 Merkle tree 得到 Merkle root,Merkle root 存入 block header。区块之间通过 previous block hash 连接,而该 hash 指向前一个 block header。
6. 易混点与常见误解
| 易混点 | 正确理解 |
|---|---|
| 有了央行签名的数字货币就安全了吗? | 不够。签名只能防伪,不能阻止文件复制后重复花费。 |
| double spending 是不是伪造签名? | 不是。double spending 可以使用真实签名,问题在于同一笔钱被重复引用为 input。 |
| 中心化数据库方案是不是错误的? | 不是。它在正确性上可行,但依赖中心机构,每次交易都要经过中心确认。 |
| blockchain 是不是只用来把区块串起来? | 不只是。它还保存完整交易历史,使节点能追溯币的来源并检查 double spending。 |
| transaction input 是不是写付款人是谁? | 不只是。更关键的是它指向之前的 transaction output,说明本次花的钱从哪里来。 |
| transaction output 是不是直接写收款人名字? | 不是。它通常写的是收款人的 public key hash,类似地址。 |
| 当前 input 里的 public key 是自己提供的,会不会随便冒充? | 不能。该 public key 的 hash 必须和前序 output 中记录的 public key hash 匹配。 |
| Bitcoin transaction 是加密的吗? | 不是。交易内容公开,核心是 signature verification,而不是隐藏内容。 |
| private key 加密、public key 解密就是签名吗? | 不能这样简单理解。Bitcoin 中 signature 是专门的签名算法,目标是认证,不是保密。 |
| lightweight node 能不能独立判断 double spending? | 一般不能。它只保存 block header,没有完整交易历史,无法独立检查所有 input 是否已被花费。 |
7. 课堂外补充理解
7.1 Bitcoin 更接近 UTXO 模型,而不是账户余额模型
本节虽然没有正式展开 UTXO 这个术语,但实际上已经在讲 UTXO 思想。
UTXO 是 Unspent Transaction Output,意思是“尚未被花费的交易输出”。
在银行账户模型中,我们通常说:
A 的账户余额是 10 元。
在 Bitcoin 中,更接近这样说:
A 拥有若干个尚未被花费的 transaction outputs,它们加起来价值 10 BTC。
当 A 要转账时,不是直接从“余额数字”中减钱,而是选择若干个 UTXO 作为 input,并生成新的 output 给收款人。
7.2 为什么 output 里放 public key hash,而不是直接放 public key?
从本节课理解角度看,public key hash 的作用是把“谁能花这笔钱”绑定到一个更短、更固定的标识上。之后真正花钱时,input 再提供 public key 和 signature。
验证时检查两件事:
- public key 是否对应之前 output 里记录的 public key hash;
- signature 是否由对应 private key 生成。
这样就把“地址”和“签名验证”连接起来了。
7.3 Merkle root 为什么能保护 block body?
Merkle tree 的核心特点是:底层 transaction 的任何一点变化,都会逐层影响到上层 hash,最终改变 Merkle root。
由于 Merkle root 存在 block header 中,而 block header 又参与区块链的 hash pointer 连接,所以篡改 block body 中的 transaction 会导致:
- transaction hash 改变;
- Merkle root 改变;
- block header hash 改变;
- 后续区块的 previous block hash 对不上。
因此,block body 虽然不直接作为区块链 hash pointer 的目标,但仍然受到 Merkle root 的保护。
7.4 full node 为什么重要?
Bitcoin 的安全性不能只依赖“别人告诉我这笔交易合法”。
full node 的意义在于:它可以自己保存完整历史,自己验证每一笔交易。
这体现了 decentralized system 的一个基本思想:
不信任单个节点,而是通过公开规则让每个节点都能独立检查。
lightweight node 使用起来更轻便,但它牺牲了一部分独立验证能力。
8. 本节小结
- 数字货币的核心难点不是“如何防伪”,而是“如何防止 double spending”。
- 单纯的 digital signature 只能证明发行者或付款者身份,不能证明这笔钱没有被重复花费。
- 中心化方案可以通过数据库记录每个币的当前归属,但这依赖中心机构。
- Bitcoin 用 blockchain 保存公开交易历史,让节点通过追溯 transaction input 来判断币的来源和状态。
- transaction output 通过 public key hash 指定谁能花这笔钱,transaction input 通过 public key 和 signature 证明自己有权花。
- block header 保存 previous block hash、Merkle root、target / nBits、nonce 等信息;block body 保存 transaction list。
- full node 保存完整数据并验证所有交易,lightweight node 只保存 block header,通常不能独立验证 double spending。
9. 自测问题
1. 为什么“央行签名的数字文件”不能直接作为数字货币?
参考答案:因为数字文件可以被复制。央行签名只能证明文件真实、内容未被篡改,但不能证明这份文件以前没有被花过,所以会产生 double spending attack。
2. 中心化数据库如何防止 double spending?
参考答案:给每个数字货币编号,由央行数据库记录每个编号当前归谁所有。交易时先查询该币是否属于付款人,交易成功后更新归属。如果付款人再次使用同一编号,查询会失败。
3. Bitcoin 为什么需要 transaction input 指向之前的 transaction output?
参考答案:因为 input 要说明本次花费的钱从哪里来。节点可以沿着 input 回溯历史,检查该 output 是否存在、是否属于付款人、是否已经被花过。
4. 一笔交易有付款人的真实 signature,就一定合法的吗?
参考答案:不一定。signature 只能证明付款人授权了这笔交易,但还要检查这笔钱是否真实存在、是否属于付款人、是否已经被花过。
5. 为什么当前 transaction input 中自己提供 public key 不会造成冒名顶替?
参考答案:因为该 public key 的 hash 必须和前序 output 中记录的 public key hash 匹配。如果攻击者提供自己的 public key,它的 hash 对不上前序 output 中绑定的 hash,验证失败。
6. Bitcoin 中 encryption 和 digital signature 的区别是什么?
参考答案:encryption 的目标是保密,通常用接收者 public key 加密、接收者 private key 解密。digital signature 的目标是认证和防篡改,发送者用 private key 生成 signature,其他人用发送者 public key 验证。Bitcoin transaction 主要依赖 signature,不是加密隐藏交易内容。
7. block header 和 block body 分别保存什么?
参考答案:block header 保存 version、previous block hash、Merkle root、target / nBits、nonce 等宏观信息;block body 保存 transaction list。transaction list 通过 Merkle tree 得到 Merkle root,写入 block header。
8. full node 和 lightweight node 的核心区别是什么?
参考答案:full node 保存完整 blockchain,并能独立验证所有交易,包括 double spending 检查;lightweight node 通常只保存 block header,没有完整交易历史,不能独立完成所有交易合法性验证。









