区块链

交易链:一笔交易怎样花掉刚刚生成的 UTXO

理解交易链,才能真正理解比特币白皮书中“coin 是一条数字签名链”的含义。本文从最小模型出发,介绍 UTXO 在交易之间如何转移,以及交易链在 BSV 应用状态管理中的关键作用。

林知衡

林知衡

technical_editor

发布于 2026年6月18日3 分钟阅读

先讲结论

交易链描述的是 UTXO 在连续交易中不断被花费和再创建的过程。理解它,才能真正掌握白皮书里“coin 是一条数字签名链”的含义,也才能明白为什么 BSV 应用常常把状态放在 UTXO 里进行连续更新。

交易链:一笔交易怎样花掉刚刚生成的 UTXO 文章封面

从 A 到 B 的最小模型

假设交易 A 创建了一个输出:

TEXT
1交易 A
2 output 0: 1000 satoshis,锁给 Alice

此时这个 output 还是 UTXO。

交易 B 想花它,就必须引用:

TEXT
1交易 A 的 txid + output index 0

交易 B 的输入:

TEXT
1交易 B
2 input 0: 引用 A:0,并提供 Alice 的签名和公钥

交易 B 再创建新输出:

TEXT
1交易 B
2 output 0: 600 satoshis,锁给 Bob
3 output 1: 350 satoshis,找零给 Alice
4 fee: 50 satoshis

这样,A 的 output 0 被花掉,不再是 UTXO。B 的 output 0 和 output 1 成为新的 UTXO。

为什么叫“链”

每一笔后续交易都引用之前某笔交易的 output。

TEXT
1Coinbase 或早期交易
2 -> 交易 A output 0
3 -> 交易 B input 0 花 A:0,创建 B:0
4 -> 交易 C input 0 花 B:0,创建 C:0

这就是 coin 的链。它不是账户余额表,而是一串 output 不断被花费和重新创建的历史。

需要注意的是:区块链是区块按时间和工作量连接的链;UTXO 链是 coin 所有权沿交易不断转移的链。这两个结构结合起来,才构成了可追踪的公共账本。

用 SDK 动手构造交易链

手动构建交易链的关键:交易 B 的 input 必须引用交易 A 的 output。

下面是一段概念示意代码(基于 BSV TypeScript SDK):

TypeScript
1const txA = new Transaction()
2
3txA.addInput({
4 sourceTransaction: fundingTx,
5 sourceOutputIndex: 0,
6 unlockingScriptTemplate: new P2PKH().unlock(alicePrivateKey)
7})
8
9txA.addOutput({
10 lockingScript: new P2PKH().lock(aliceAddress),
11 satoshis: 500
12})
13
14txA.addOutput({
15 lockingScript: new P2PKH().lock(aliceAddress),
16 change: true
17})
18
19await txA.fee()
20await txA.sign()
21
22const txB = new Transaction()
23
24txB.addInput({
25 sourceTransaction: txA,
26 sourceOutputIndex: 0,
27 unlockingScriptTemplate: new P2PKH().unlock(alicePrivateKey)
28})
29
30txB.addOutput({
31 lockingScript: new P2PKH().lock(bobAddress),
32 satoshis: 300
33})
34
35txB.addOutput({
36 lockingScript: new P2PKH().lock(aliceAddress),
37 change: true
38})
39
40await txB.fee()
41await txB.sign()

注意:真实广播时还需处理 txA 和 txB 的广播顺序、依赖关系、手续费、服务策略以及错误处理等。

未确认交易也可能形成依赖

交易 B 可以直接依赖交易 A 的 output,即使 A 尚未被网络接受或打包。此时 txB 依赖一个尚不稳定的父交易。

这种依赖关系在实际处理中很重要:

  • txB 依赖 txA。
  • 如果 txA 无效,txB 也无法成立。
  • 如果 txA 未传播到处理节点,txB 可能因缺少父交易而失败。

在官方的高级交易教程中提到 sendWith 这样的选项,用于让依赖交易一起发送。生产系统还需处理父子交易、祖先限制、重试和状态查询等一系列问题。

交易链与应用状态

BSV 应用可以把状态建模成 UTXO 链。例如:

  • 一个 token 可以由某个 UTXO 表示。转移 token 时,旧 token UTXO 被花掉,新 token UTXO 被创建。
  • 一个凭证状态可以通过交易链更新:旧状态 output 被花掉,新状态 output 记录更新后的状态。
  • 游戏、订单或供应链事件也可以使用类似模式,把状态变更写成连续交易。

这种设计的优点是状态转移有明确的前后关系,每一步都引用上一状态,而不是像传统数据库那样随意写入一行。

交易链与并行处理

UTXO 模型本身也具有并行优势:

  • 如果两笔交易花费不同的 UTXO,它们没有直接冲突,可以并行处理。
  • 如果两笔交易花费同一个 UTXO,它们冲突,只能有一笔有效。

这对 BSV 扩展至关重要。大量独立 UTXO 可以并行验证和处理,避免所有操作都挤在一个全局账户状态里。

钱包为什么要管理 UTXO

交易链也解释了钱包为什么不能只记录一个余额数字。它必须知道:

  • 哪些 UTXO 归自己控制。
  • 每个 UTXO 来自哪笔交易、哪个 output index。
  • 哪些 UTXO 已花费。
  • 哪些 UTXO 正在被未确认交易使用。
  • 哪些交易之间存在依赖。

第 7 阶段钱包可以帮你自动处理这些关系。第 8 阶段再进行手动学习,是为了未来能更好地调试钱包和应用状态问题。

新手常见误解

  • 新交易不能凭空引用不存在的 output。
  • 花费的是具体的 outpoint,而不是账户余额。
  • 交易 B 依赖交易 A 时,要确保处理节点能看到 A。
  • 交易链不是区块链本身,它是 coin 或状态 UTXO 的转移链。
  • 应用状态上链,不等于只追加日志。很多状态协议需要花旧状态、建新状态。

参考来源

推荐文章