第 4 讲:BTC 协议(一)

依据附件文字稿与笔记生成指南整理。

第 4 讲:BTC 协议(一)

1. 本节主线

  1. 本节从“如何设计一种数字货币”出发,引出数字货币最核心的问题:double spending attack
  2. 单纯依靠数字签名只能证明“货币由谁发行、交易由谁授权”,但不能阻止数字文件被复制后重复花费。
  3. 中心化系统可以通过央行数据库记录每个币的归属来防止 double spending,但这依赖中心机构。
  4. Bitcoin 的核心思路是:把“央行数据库”改造成由所有用户共同维护的 blockchain
  5. 本节重点解释 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. 知识结构图

这张图展示了本节课的主线:先从中心化数字货币出发,发现 digital signature 不能解决 double spending,于是需要维护“币的历史流转记录”。中心化方案由央行维护数据库,Bitcoin 则用 blockchain 让全网共同维护这份记录。

4. 课程内容详解

4.1 为什么不能只用央行签名发行数字货币?

最直观的数字货币方案是:

  1. 央行拥有一对 public key / private key。
  2. 央行用 private key 对一份数字文件签名。
  3. 文件内容写着“100 元,signed by central bank”。
  4. 所有人都知道央行的 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 不仅要验证央行签名,还要向央行确认:

  1. 这个币是否真实存在;
  2. 这个币当前是不是属于 A;
  3. 这个币之前有没有被 A 花掉。

如果确认合法,央行就更新数据库:

货币编号 当前所有者
017 B

这样,A 如果再把同一个编号 017 的币转给 C,C 去央行查询时就会发现:这个币已经不属于 A 了,所以交易无效。

这个方案在正确性上没有大问题,但它是 centralized 的:每次交易都必须经过央行确认。Bitcoin 想解决的问题就是:能不能不依赖中心机构,也能防止 double spending?

4.3 去中心化货币要解决的两个问题

一个 decentralized cryptocurrency 至少要解决两个问题:

  1. 货币发行问题
    没有央行之后,谁有权发行货币?什么时候发行?发行多少?

  2. 交易验证问题
    没有央行数据库之后,谁来判断一笔交易是否合法?怎样防止 double spending?

本节课主要讨论第二个问题:交易验证。第一个问题在 Bitcoin 中由 mining 解决,后续课程会展开。

4.4 Bitcoin 的基本思路:用 blockchain 替代央行数据库

中心化方案中,央行数据库记录每个币的流转历史。Bitcoin 的思路是:

不让央行维护数据库,而是让所有节点共同维护一份公开的交易历史,这份数据结构就是 blockchain。

在 Bitcoin 中,判断一笔交易是否合法,不是看某个中心账户余额,而是沿着交易输入向前追溯:

  1. 这笔钱从哪里来?
  2. 之前有没有被花掉?
  3. 当前交易是否由有权花这笔钱的人签名?

如果一笔钱已经被用作某个交易的 input,又再次被另一个交易作为 input 使用,那么后一个交易就是 double spending,节点不会接受它。

4.5 Bitcoin transaction 的 input 和 output

Bitcoin 中每个 transaction 通常包含两部分:

部分 内容 作用
transaction input 指向之前某笔 transaction 的 output,并提供签名、公钥等验证信息 说明“我花的钱从哪里来,以及我有权花它”
transaction output 指定金额和收款人的 public key hash 说明“这笔钱以后归谁控制”

一个简化例子:

  1. 某个矿工通过 coinbase transaction 创建 10 BTC 给 A。
  2. A 把 10 BTC 分成两份,分别转给 B 和 C,每人 5 BTC。
  3. B 再把自己的 5 BTC 分成两份,转给 C 2 BTC、转给 D 3 BTC。
  4. 此时 C 一共有 7 BTC:来自 A 的 5 BTC,加上来自 B 的 2 BTC。
  5. 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 的验证逻辑不是单独检查签名,而是同时检查:

  1. input 指向的币来源是否存在;
  2. 该来源是否尚未被花费;
  3. input 中给出的 public key 是否和前序 output 中的 public key hash 匹配;
  4. 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 设置的花费条件。

以常见支付为例,可以理解为:

  1. 前序 output 中记录收款人的 public key hash;

  2. 当前 input 提供 public key 和 signature;

  3. 脚本执行时检查:

    • 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。

这样做的好处是:

  1. Merkle root 能代表整棵交易树;
  2. 只要 block body 中任意 transaction 被篡改,Merkle root 就会变化;
  3. block header 的 hash 也会变化;
  4. 因此交易列表受到 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

这张图说明:digital signature 解决的是“真伪问题”,不是“重复花费问题”。要防止 double spending,必须有一份记录币流转历史的数据结构。中心化系统用央行数据库,Bitcoin 用 blockchain。

5.2 transaction input / output 的来源追溯

这张图表示 Bitcoin 中“钱”的来源不是账户余额,而是之前 transaction 留下的 output。C 的 7 BTC 来自两个不同的 output:A 给 C 的 5 BTC,以及 B 给 C 的 2 BTC。C 花钱时需要在 input 中同时引用这两个来源。

5.3 防止伪造付款人公钥

这张图说明:当前 input 中的 public key 虽然是交易自己提供的,但不能随便伪造。因为它必须和前序 output 中记录的 public key hash 对得上,同时 signature 也必须能验证通过。

5.4 block header 与 block body 的关系

这张图说明: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。

验证时检查两件事:

  1. public key 是否对应之前 output 里记录的 public key hash;
  2. 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 会导致:

  1. transaction hash 改变;
  2. Merkle root 改变;
  3. block header hash 改变;
  4. 后续区块的 previous block hash 对不上。

因此,block body 虽然不直接作为区块链 hash pointer 的目标,但仍然受到 Merkle root 的保护。

7.4 full node 为什么重要?

Bitcoin 的安全性不能只依赖“别人告诉我这笔交易合法”。
full node 的意义在于:它可以自己保存完整历史,自己验证每一笔交易。

这体现了 decentralized system 的一个基本思想:

不信任单个节点,而是通过公开规则让每个节点都能独立检查。

lightweight node 使用起来更轻便,但它牺牲了一部分独立验证能力。

8. 本节小结

  1. 数字货币的核心难点不是“如何防伪”,而是“如何防止 double spending”。
  2. 单纯的 digital signature 只能证明发行者或付款者身份,不能证明这笔钱没有被重复花费。
  3. 中心化方案可以通过数据库记录每个币的当前归属,但这依赖中心机构。
  4. Bitcoin 用 blockchain 保存公开交易历史,让节点通过追溯 transaction input 来判断币的来源和状态。
  5. transaction output 通过 public key hash 指定谁能花这笔钱,transaction input 通过 public key 和 signature 证明自己有权花。
  6. block header 保存 previous block hash、Merkle root、target / nBits、nonce 等信息;block body 保存 transaction list。
  7. 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,没有完整交易历史,不能独立完成所有交易合法性验证。