在比特币和 btcd 中,交易(Transaction)是区块链的基本构建块。每个交易由输入(Inputs)和输出(Outputs)组成。输入引用之前的输出,并提供解锁这些输出的条件。输出包含接收比特币的地址和金额。

btcd 中的交易结构

btcd 中,交易结构定义在 wire 包中,具体如下:

type MsgTx struct {
	Version  int32
	TxIn     []*TxIn
	TxOut    []*TxOut
	LockTime uint32
}

字段解析

  1. Version: 交易版本号,用于将来扩展。当前版本为 1 或 2。
  2. TxIn: 交易输入列表,一个交易可以有多个输入。
  3. TxOut: 交易输出列表,一个交易可以有多个输出。
  4. LockTime: 交易锁定时间,表示交易何时可以被添加到区块链中。

输入结构(TxIn)

交易输入引用了之前的输出,并提供了解锁这些输出的条件。btcd 中的输入结构定义如下:

type TxIn struct {
	PreviousOutPoint OutPoint
	SignatureScript  []byte
	Witness          TxWitness
	Sequence         uint32
}

字段解析

  1. PreviousOutPoint: 引用之前的交易输出,包括交易ID和输出索引。
  2. SignatureScript: 解锁前一个输出的脚本(非 SegWit 交易)。
  3. Sequence: 序列号,用于相对时间锁定。
  4. Witness: 见证数据,用于 SegWit 交易。

输出结构(TxOut)

交易输出定义了接收比特币的地址和金额。btcd 中的输出结构定义如下:

type TxOut struct {
	Value    int64
	PkScript []byte
}

字段解析

  1. Value: 输出金额,以聪(satoshis)为单位。
  2. PkScript: 锁定脚本,定义了如何解锁该输出。

示例交易

以下是一个简单的交易示例,展示了如何构建一个交易:

package main

import (
    "github.com/btcsuite/btcd/wire"
    "github.com/btcsuite/btcutil"
)

func main() {
    // 创建一个新的交易
    tx := wire.NewMsgTx(wire.TxVersion)

    // 添加输入
    prevOut := wire.NewOutPoint(&prevTxHash, 0)
    txIn := wire.NewTxIn(prevOut, nil, nil)
    tx.AddTxIn(txIn)

    // 添加输出
    address, _ := btcutil.DecodeAddress("1BitcoinAddress", &chaincfg.MainNetParams)
    pkScript, _ := txscript.PayToAddrScript(address)
    txOut := wire.NewTxOut(100000000, pkScript) // 1 BTC
    tx.AddTxOut(txOut)

    // 设置锁定时间
    tx.LockTime = 0

    // 交易现在可以被序列化并广播到网络
}

Sequence 字段

btcd 中的交易结构包含一个名为 Sequence 的字段,它在比特币协议中有几个重要的用途,主要与交易的时间锁定和替换有关。

Sequence 字段概述

Sequence 字段是交易输入(TxIn)的一部分,它是一个 32 位的无符号整数。这个字段最初是为了支持交易的替换(Replace-by-Fee, RBF)和时间锁定(Locktime)而设计的。

具体用途

1. 相对时间锁定(Relative Locktime)

相对时间锁定允许交易在一定的时间条件满足后才能被确认。这种机制通过 Sequence 字段和 BIP-68 实现。BIP-68 将 Sequence 字段重新定义为包含两个部分:

  • 低 16 位:用于定义相对时间锁定的值。
  • 高 16 位:用于标志和版本控制。

具体来说,低 16 位可以表示区块高度或时间(以 512 秒为单位),高 16 位的第 22 位用于标志是否启用相对时间锁定。

例如:

  • 如果低 16 位的值小于 0x8000,则表示区块高度。
  • 如果低 16 位的值大于或等于 0x8000,则表示时间。

2. 替换交易(Replace-by-Fee, RBF)

RBF 允许未确认的交易被新的交易替换,前提是新的交易需要支付更高的费用。BIP-125 定义了如何使用 Sequence 字段来标记支持 RBF 的交易:如果 Sequence 字段的值低于 0xFFFFFFFE,则表示该交易支持 RBF,可以被新的交易替换。

示例

假设我们有一个交易输入,其 Sequence 字段的值为 0x00000001。这表示该输入有一个相对时间锁定,必须等待至少一个区块高度才能被确认。

package main

import (
    "github.com/btcsuite/btcd/wire"
    "github.com/btcsuite/btcutil"
)

func main() {
    // 创建一个新的交易
    tx := wire.NewMsgTx(wire.TxVersion)

    // 添加输入
    prevOut := wire.NewOutPoint(&prevTxHash, 0)
    txIn := wire.NewTxIn(prevOut, nil, nil)
    txIn.Sequence = 0x00000001 // 设置 Sequence 字段
    tx.AddTxIn(txIn)

    // 添加输出
    address, _ := btcutil.DecodeAddress("1BitcoinAddress", &chaincfg.MainNetParams)
    pkScript, _ := txscript.PayToAddrScript(address)
    txOut := wire.NewTxOut(100000000, pkScript) // 1 BTC
    tx.AddTxOut(txOut)

    // 设置锁定时间
    tx.LockTime = 0

    // 交易现在可以被序列化并广播到网络
}

孟斯特

声明:本作品采用署名-非商业性使用-相同方式共享 4.0 国际 (CC BY-NC-SA 4.0)进行许可,使用时请注明出处。

Author: mengbin

blog: mengbin

Github: mengbin92

cnblogs: 恋水无意

腾讯云开发者社区:孟斯特