Skip to content

BTC #3:Transaction(上)— UTXO 与交易结构

比特币没有"余额"概念。你的"钱"其实是散落在区块链上的一堆"未花费的交易输出"(UTXO)。


UTXO 模型

什么是 UTXO

UTXO(Unspent Transaction Output)即"未花费的交易输出"。比特币的记账方式不是记录"你有多少钱",而是记录"哪些钱还没被花掉"。

graph LR
    subgraph "Alice 的 UTXO"
        U1["UTXO 1<br/>0.5 BTC<br/>来自交易 A"]
        U2["UTXO 2<br/>0.3 BTC<br/>来自交易 B"]
        U3["UTXO 3<br/>0.2 BTC<br/>来自交易 C"]
    end

    SUM["Alice 的'余额'<br/>= 0.5 + 0.3 + 0.2<br/>= 1.0 BTC"]

UTXO vs 账户模型

graph TB
    subgraph "比特币 UTXO 模型"
        direction LR
        BU1["UTXO: 0.5 BTC"] --> BTX["交易"]
        BU2["UTXO: 0.3 BTC"] --> BTX
        BTX --> BN1["新 UTXO: 0.6 BTC<br/>(给 Bob)"]
        BTX --> BN2["新 UTXO: 0.19 BTC<br/>(找零给 Alice)"]
        BTX --> FEE["0.01 BTC<br/>(矿工费)"]
    end

    subgraph "以太坊 账户模型"
        EA["Alice: 1.0 ETH"] -->|"-0.6 ETH"| EA2["Alice: 0.39 ETH"]
        EB["Bob: 0 ETH"] -->|"+0.6 ETH"| EB2["Bob: 0.6 ETH"]
    end
特性UTXO 模型(BTC)账户模型(ETH)
余额表示所有 UTXO 之和单一余额数字
隐私性较好(每次可用新地址)较差(地址固定)
并发性天然支持(不同 UTXO 独立)需要 nonce 排序
转账找零需要找零输出自动扣减余额
手续费输入总额 - 输出总额 = 矿工费显式指定 gasPrice

交易结构

graph TB
    TX["📝 Bitcoin Transaction"]

    TX --> VER["version<br/>版本号"]
    TX --> INP["inputs 输入列表"]
    TX --> OUT["outputs 输出列表"]
    TX --> LOCK["locktime<br/>锁定时间"]

    INP --> I1["Input 0"]
    I1 --> TXID["前一交易哈希<br/>txid"]
    I1 --> VOUT["输出索引<br/>vout"]
    I1 --> SCRIPT["解锁脚本<br/>scriptSig"]

    OUT --> O1["Output 0"]
    O1 --> AMT["金额<br/>value (satoshi)"]
    O1 --> LOCK2["锁定脚本<br/>scriptPubKey"]

输入(Input)

  • txid:引用的前一笔交易的哈希
  • vout:前一笔交易中具体哪个输出(索引)
  • scriptSig:解锁脚本,提供花费证明(签名 + 公钥)

输出(Output)

  • value:金额(以聪 satoshi 为单位,1 BTC = 10^8 satoshi)
  • scriptPubKey:锁定脚本,定义花费条件

手续费

手续费 = 所有输入的总金额 - 所有输出的总金额

手续费不是交易的一个显式字段,而是隐含在输入输出的差值中。

比特币脚本

比特币脚本是一种基于栈的简单编程语言,用于定义和验证花费条件。

P2PKH 脚本执行过程

graph TB
    subgraph "解锁脚本 (scriptSig)"
        S1["PUSH 签名"]
        S2["PUSH 公钥"]
    end

    subgraph "锁定脚本 (scriptPubKey)"
        L1["OP_DUP"]
        L2["OP_HASH160"]
        L3["PUSH 公钥哈希"]
        L4["OP_EQUALVERIFY"]
        L5["OP_CHECKSIG"]
    end

    S1 --> S2 --> L1 --> L2 --> L3 --> L4 --> L5 --> RESULT["✅ 验证通过"]

执行流程:

  1. 将签名和公钥压入栈
  2. OP_DUP:复制栈顶的公钥
  3. OP_HASH160:对公钥做哈希
  4. OP_EQUALVERIFY:比较哈希是否与锁定脚本中的公钥哈希一致
  5. OP_CHECKSIG:用公钥验证签名

学习资源