Skip to content

交易格式详解

目录

  1. 交易格式概述
  2. 交易序列化
  3. 紧凑尺寸编码
  4. 交易字段详解
  5. 交易输入详解
  6. 交易输出详解
  7. 脚本序列化
  8. 实际交易示例
  9. 交易大小
  10. 常见问题

交易格式概述

交易的二进制表示

比特币交易在网络中以二进制形式传输和存储。理解这种二进制格式对于开发比特币应用至关重要。

层级说明
逻辑层输入、输出、签名
序列化层二进制编码格式
网络层P2P 协议传输
存储层区块链持久化

基本结构

交易 (Transaction)
├── 版本号 (4 字节)
├── 输入计数 (1-9 字节,CompactSize)
├── 输入列表 (可变长度)
│   ├── Input 1
│   │   ├── 前一交易 TXID (32 字节)
│   │   ├── 输出索引 (4 字节)
│   │   ├── 脚本长度 (1-9 字节)
│   │   ├── 解锁脚本 (可变长度)
│   │   └── 序列号 (4 字节)
│   ├── Input 2
│   └── ...
├── 输出计数 (1-9 字节,CompactSize)
├── 输出列表 (可变长度)
│   ├── Output 1
│   │   ├── 金额 (8 字节)
│   │   ├── 脚本长度 (1-9 字节)
│   │   └── 锁定脚本 (可变长度)
│   ├── Output 2
│   └── ...
└── 锁定时间 (4 字节)

交易序列化

字节顺序(Endianness)

比特币使用小端序(Little Endian)在大多数情况下。

例子:
  十六进制值:0x12345678
  
  大端序(网络字节序):12 34 56 78
  小端序(Intel 格式):78 56 34 12

比特币中的用法:
  - 内存中的整数:通常是本机字节序
  - 网络传输:小端序
  - TXID 显示:反转字节顺序(大端序显示)

规则:
  大多数多字节字段都使用小端序
  但某些字段(如脚本)使用大端序

序列化过程

序列化步骤:

1. 版本号 → 4 字节小端序
2. 输入计数 → CompactSize
3. 对每个输入:
   a. 前一交易 TXID → 32 字节小端序
   b. 输出索引 → 4 字节小端序
   c. 脚本长度 → CompactSize
   d. 脚本数据 → 原始字节
   e. 序列号 → 4 字节小端序
4. 输出计数 → CompactSize
5. 对每个输出:
   a. 金额 → 8 字节小端序
   b. 脚本长度 → CompactSize
   c. 脚本数据 → 原始字节
6. 锁定时间 → 4 字节小端序

结果:
  连续的字节序列,可以传输或存储

紧凑尺寸编码

CompactSize 编码

紧凑尺寸用于编码可变长度的无符号整数。

规则:

如果 n < 253:
  编码为 1 字节:0xNN

如果 253 ≤ n < 65536:
  编码为 3 字节:0xFD + n (2字节小端序)

如果 65536 ≤ n < 4294967296:
  编码为 5 字节:0xFE + n (4字节小端序)

如果 n ≥ 4294967296:
  编码为 9 字节:0xFF + n (8字节小端序)

优势:
  小值使用少字节
  大值才使用多字节
  比固定 8 字节更高效

编码示例

例子 1:计数为 2 个输入
  值:2
  编码:0x02(1 字节)

例子 2:计数为 300 个输入
  值:300 = 0x012C
  编码:0xFD 2C 01(3 字节,小端序)

例子 3:脚本长度为 100 字节
  值:100 = 0x64
  编码:0x64(1 字节)

例子 4:脚本长度为 50000 字节
  值:50000 = 0xC350
  编码:0xFE 50 C3 00 00(5 字节,小端序)

交易字段详解

1. 版本号(Version)

大小:4 字节小端序
范围:1-4(常见)

版本 1(0x01000000):
  标准交易
  所有基础功能

版本 2(0x02000000):
  支持交易指数的替换(BIP 125)
  更灵活的费用替换策略

格式示例:
  原始值:1
  十六进制:01 00 00 00(小端序)

含义:
  版本号向后兼容
  节点可识别未来的新版本

2. 输入计数

大小:CompactSize
含义:此交易有多少个输入

编码示例:
  1 个输入:0x01
  2 个输入:0x02
  255 个输入:0xFF
  256 个输入:0xFD 00 01
  
理论限制:
  无绝对限制
  但区块大小限制(1MB)间接限制
  实际交易通常 < 100 个输入

3. 输出计数

大小:CompactSize
含义:此交易有多少个输出

范围和限制同输入计数

4. 锁定时间(Locktime)

大小:4 字节小端序
范围:0 到 4294967295(2^32 - 1)

含义:交易何时能花费

解释规则:

如果 locktime = 0:
  交易立即有效

如果 0 < locktime < 500000000:
  解释为区块高度
  例:locktime = 100000
  交易在第 100000 个区块之前无效

如果 locktime ≥ 500000000:
  解释为 Unix 时间戳(秒)
  例:locktime = 1234567890
  交易在 2009-02-13 后有效

应用场景:
  1. 时间锁定交易
  2. 支付渠道(闪电网络)
  3. 原子交换

示例:
  locktime = 0x00000000 (立即有效)
  locktime = 0x80000000 (2106-02-07 后)

交易输入详解

输入结构

每个输入包含:

1. 前一交易 TXID (32 字节)
   指向被花费的 UTXO

2. 输出索引 (4 字节)
   该 UTXO 在前一交易中的位置

3. 脚本长度 (CompactSize)
   解锁脚本的字节长度

4. 解锁脚本 (可变长度)
   证明有权花费 UTXO 的脚本

5. 序列号 (4 字节)
   用于交易替换和锁定时间

前一交易 TXID

大小:32 字节
顺序:小端序

含义:
  指向前一个交易的哈希值
  该交易包含要花费的输出

显示形式(反转字节顺序):
  内存存储:12 34 56 78 ... (小端)
  显示:    ... 78 56 34 12   (大端)

作用:
  1. 唯一标识前一个交易
  2. 链接到区块链历史
  3. 可验证 UTXO 的存在

双重花费防护:
  同一个 TXID + vout 只能被花费一次

输出索引(Vout)

大小:4 字节小端序
范围:0 到 2^32 - 1

含义:
  在前一交易中,被花费的输出位置

例子:
  前一交易有 3 个输出:
    Output 0: 1 BTC
    Output 1: 2 BTC
    Output 2: 3 BTC
  
  如果 vout = 1,则花费 Output 1(2 BTC)

编码:
  第 0 个输出:0x00 00 00 00
  第 1 个输出:0x01 00 00 00
  第 2 个输出:0x02 00 00 00

脚本长度

大小:CompactSize
含义:解锁脚本的字节长度

示例:
  脚本 47 字节:0x47
  脚本 256 字节:0xFD 00 01

作用:
  告诉解析器多少字节是脚本
  允许不定长的脚本数据

解锁脚本(ScriptSig)

大小:可变长度
含义:证明有权花费 UTXO 的脚本

P2PKH (Pay-to-Public-Key-Hash) 脚本:
  <signature> <pubkey>
  
  例:
  47 30 44...(签名数据)
  21 02 79be...(公钥数据)

脚本语言:
  基于栈的语言
  非图灵完整
  串联操作码和数据

作用:
  提供解锁证明
  通常包含:签名 + 公钥
  签名证明有私钥
  公钥证明身份

序列号(Sequence)

大小:4 字节小端序
范围:0 到 4294967295

含义和用途:

原始意图(不常用):
  用于交易替换
  值越高,优先级越高

现代用途:

1. 相对锁定时间 (BIP 68)
   高位编码锁定时间
   序列号 < 0xFFFFFFFF 激活锁定时间

2. 交易替换信号 (BIP 125)
   序列号 < 0xFFFFFFFF 允许 RBF

标准值:
  0xFFFFFFFF:无限制,立即有效
  0xFFFFFFFE:允许 RBF
  < 0xFFFFFFFF:启用锁定时间

使用示例:
  标准交易:0xFF FF FF FF(允许立即花费)
  锁定交易:0xFE FF FF FF(启用锁定时间)

交易输出详解

输出结构

每个输出包含:

1. 金额 (8 字节)
   聪为单位的金额

2. 脚本长度 (CompactSize)
   锁定脚本的字节长度

3. 锁定脚本 (可变长度)
   定义谁能花费此输出

金额(Value)

大小:8 字节小端序
单位:聪(satoshi)
范围:0 到 2099999997690000

1 BTC = 100,000,000 聪

编码示例:
  1 BTC = 100000000 聪
  十六进制(小端):00 e1 f5 05 00 00 00 00

  0.5 BTC = 50000000 聪
  十六进制(小端):80 f0 fa 02 00 00 00 00

特殊值:
  -1:未初始化或错误
  > 21000000 BTC:无效,超过总供应量

精度:
  只能精确到 1 聪
  不能表示 0.000000001 BTC 的更小单位

锁定脚本(ScriptPubKey)

大小:可变长度
含义:定义谁能花费这个输出

常见脚本类型:

1. P2PKH (Pay-to-Public-Key-Hash)
   OP_DUP OP_HASH160 <pubkeyhash> OP_EQUALVERIFY OP_CHECKSIG
   
   格式:0x76 A9 14 <20 bytes hash> 88 AC
   总长度:25 字节

2. P2SH (Pay-to-Script-Hash)
   OP_HASH160 <scripthash> OP_EQUAL
   
   格式:0xA9 14 <20 bytes hash> 87
   总长度:23 字节

3. P2WPKH (Pay-to-Witness-Public-Key-Hash, SegWit)
   OP_0 <20 bytes pubkeyhash>
   
   格式:0x00 14 <20 bytes>
   总长度:22 字节

4. P2WSH (Pay-to-Witness-Script-Hash, SegWit)
   OP_0 <32 bytes scripthash>
   
   格式:0x00 20 <32 bytes>
   总长度:34 字节

脚本大小:
  P2PKH:25 字节
  P2SH:23 字节
  P2WPKH:22 字节(最小)

脚本序列化

脚本基础

脚本是栈基的:
  1. 从左到右读取操作码
  2. 操作数压入栈
  3. 操作码执行栈操作
  4. 最终栈顶必须为真

编码规则:
  操作码 0x00-0x4B:数据长度
  操作码 0x4C:PUSHDATA1
  操作码 0x4D:PUSHDATA2
  操作码 0x4E:PUSHDATA4
  操作码 0x51-0x60:OP_1 到 OP_16
  操作码 0x6B 等:其他操作码

常见操作码

OP_DUP (0x76):复制栈顶

OP_HASH160 (0xA9):SHA256 后 RIPEMD160

OP_EQUAL (0x87):比较栈顶两项

OP_EQUALVERIFY (0x88):EQUAL + OP_VERIFY

OP_CHECKSIG (0xAC):验证签名

OP_0 (0x00):压入空值

OP_1 (0x51):压入 1

实际交易示例

例子:简单的 P2PKH 交易

场景:Alice 发送 1 BTC 给 Bob

原始十六进制数据(已序列化):
01000000                           版本号 (1)
01                                输入计数 (1)
86c6047f6f79...                    前一交易 TXID (32 字节)
00000000                           输出索引 (vout=0)
48                                 脚本长度 (72 字节)
47304402...86a1                    解锁脚本 (72 字节)
ffffffff                           序列号 (0xFFFFFFFF)
01                                输出计数 (1)
00ca9a3b00000000                   金额 (1 BTC = 100000000 聪)
19                                 脚本长度 (25 字节)
76a91462e907b15cbf...88ac          锁定脚本 (25 字节)
00000000                           锁定时间 (0)

大小:约 226 字节

交易大小

字节计算

基础开销:
  版本号:4 字节
  输入计数:1 字节
  输出计数:1 字节
  锁定时间:4 字节
  小计:10 字节

每个输入:
  TXID:32 字节
  Vout:4 字节
  脚本长度:1 字节
  脚本:平均 72 字节(签名)+ 33 字节(压缩公钥)
  序列:4 字节
  小计:约 146 字节

每个输出:
  金额:8 字节
  脚本长度:1 字节
  脚本:25 字节(P2PKH)或更小
  小计:约 34 字节

总大小 ≈ 10 + (输入数 × 146) + (输出数 × 34) 字节

大小优化

使用 SegWit 可减小交易大小:

传统交易大小 = 1 × vBytes
SegWit 交易大小 = vBytes

vBytes = (基础大小 + 见证数据 × 0.25)

节省约 25-50% 的区块空间

常见问题

Q1: 为什么使用小端序?

A: 历史原因和本地处理效率。网络通常使用大端序,但比特币选择小端序作为内部表示。

Q2: 交易最大能有多少个输入?

A: 理论上无限制,但受区块大小限制(1MB,或 SegWit 下 4MB)。实际上,输入越多,费用越高。

Q3: 可以有 0 个输出吗?

A: 可以,但不推荐。这样的交易会烧毁所有输入的比特币。

Q4: 解锁脚本和锁定脚本的作用?

A: 锁定脚本定义条件(出现在前一交易中),解锁脚本提供证明(出现在当前交易中)。

Q5: 序列号为什么总是 0xFFFFFFFF?

A: 因为大多数交易不使用锁定时间。0xFFFFFFFF 表示无锁定限制。