Bitcoin Transaction: Go parsing library

KS implementation details

License: MIT

This page hosts a formal specification of Bitcoin Transaction using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Go source code to parse Bitcoin Transaction

bitcoin_transaction.go

// Code generated by kaitai-struct-compiler from a .ksy source file. DO NOT EDIT.

import (
	"github.com/kaitai-io/kaitai_struct_go_runtime/kaitai"
	"bytes"
)


/**
 * @see <a href="https://bitcoin.org/en/developer-guide#transactions
 * https://en.bitcoin.it/wiki/Transaction
 * ">Source</a>
 */
type BitcoinTransaction struct {
	Version uint32
	NumVins uint8
	Vins []*BitcoinTransaction_Vin
	NumVouts uint8
	Vouts []*BitcoinTransaction_Vout
	Locktime uint32
	_io *kaitai.Stream
	_root *BitcoinTransaction
	_parent interface{}
}
func NewBitcoinTransaction() *BitcoinTransaction {
	return &BitcoinTransaction{
	}
}

func (this *BitcoinTransaction) Read(io *kaitai.Stream, parent interface{}, root *BitcoinTransaction) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp1, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Version = uint32(tmp1)
	tmp2, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.NumVins = tmp2
	for i := 0; i < int(this.NumVins); i++ {
		_ = i
		tmp3 := NewBitcoinTransaction_Vin()
		err = tmp3.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Vins = append(this.Vins, tmp3)
	}
	tmp4, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.NumVouts = tmp4
	for i := 0; i < int(this.NumVouts); i++ {
		_ = i
		tmp5 := NewBitcoinTransaction_Vout()
		err = tmp5.Read(this._io, this, this._root)
		if err != nil {
			return err
		}
		this.Vouts = append(this.Vouts, tmp5)
	}
	tmp6, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.Locktime = uint32(tmp6)
	return err
}

/**
 * Version number.
 */

/**
 * Number of input transactions.
 */

/**
 * Input transactions.
 * An input refers to an output from a previous transaction.
 */

/**
 * Number of output transactions.
 */

/**
 * Output transactions.
 */
type BitcoinTransaction_Vin struct {
	Txid []byte
	OutputId uint32
	LenScript uint8
	ScriptSig *BitcoinTransaction_Vin_ScriptSignature
	EndOfVin []byte
	_io *kaitai.Stream
	_root *BitcoinTransaction
	_parent *BitcoinTransaction
	_raw_ScriptSig []byte
}
func NewBitcoinTransaction_Vin() *BitcoinTransaction_Vin {
	return &BitcoinTransaction_Vin{
	}
}

func (this *BitcoinTransaction_Vin) Read(io *kaitai.Stream, parent *BitcoinTransaction, root *BitcoinTransaction) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp7, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp7 = tmp7
	this.Txid = tmp7
	tmp8, err := this._io.ReadU4le()
	if err != nil {
		return err
	}
	this.OutputId = uint32(tmp8)
	tmp9, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenScript = tmp9
	tmp10, err := this._io.ReadBytes(int(this.LenScript))
	if err != nil {
		return err
	}
	tmp10 = tmp10
	this._raw_ScriptSig = tmp10
	_io__raw_ScriptSig := kaitai.NewStream(bytes.NewReader(this._raw_ScriptSig))
	tmp11 := NewBitcoinTransaction_Vin_ScriptSignature()
	err = tmp11.Read(_io__raw_ScriptSig, this, this._root)
	if err != nil {
		return err
	}
	this.ScriptSig = tmp11
	tmp12, err := this._io.ReadBytes(int(4))
	if err != nil {
		return err
	}
	tmp12 = tmp12
	this.EndOfVin = tmp12
	if !(bytes.Equal(this.EndOfVin, []uint8{255, 255, 255, 255})) {
		return kaitai.NewValidationNotEqualError([]uint8{255, 255, 255, 255}, this.EndOfVin, this._io, "/types/vin/seq/4")
	}
	return err
}

/**
 * Previous transaction hash.
 */

/**
 * ID indexing an ouput of the transaction refered by txid.
 * This output will be used as an input in the present transaction.
 */

/**
 * ScriptSig's length.
 */

/**
 * ScriptSig.
 * @see <a href="https://en.bitcoin.it/wiki/Transaction#Input
 * https://en.bitcoin.it/wiki/Script
 * ">Source</a>
 */

/**
 * Magic number indicating the end of the current input.
 */

type BitcoinTransaction_Vin_ScriptSignature_SighashType int
const (
	BitcoinTransaction_Vin_ScriptSignature_SighashType__SighashAll BitcoinTransaction_Vin_ScriptSignature_SighashType = 1
	BitcoinTransaction_Vin_ScriptSignature_SighashType__SighashNone BitcoinTransaction_Vin_ScriptSignature_SighashType = 2
	BitcoinTransaction_Vin_ScriptSignature_SighashType__SighashSingle BitcoinTransaction_Vin_ScriptSignature_SighashType = 3
	BitcoinTransaction_Vin_ScriptSignature_SighashType__SighashAnyonecanpay BitcoinTransaction_Vin_ScriptSignature_SighashType = 80
)
type BitcoinTransaction_Vin_ScriptSignature struct {
	LenSigStack uint8
	DerSig *BitcoinTransaction_Vin_ScriptSignature_DerSignature
	SigType BitcoinTransaction_Vin_ScriptSignature_SighashType
	LenPubkeyStack uint8
	Pubkey *BitcoinTransaction_Vin_ScriptSignature_PublicKey
	_io *kaitai.Stream
	_root *BitcoinTransaction
	_parent *BitcoinTransaction_Vin
}
func NewBitcoinTransaction_Vin_ScriptSignature() *BitcoinTransaction_Vin_ScriptSignature {
	return &BitcoinTransaction_Vin_ScriptSignature{
	}
}

func (this *BitcoinTransaction_Vin_ScriptSignature) Read(io *kaitai.Stream, parent *BitcoinTransaction_Vin, root *BitcoinTransaction) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp13, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenSigStack = tmp13
	tmp14 := NewBitcoinTransaction_Vin_ScriptSignature_DerSignature()
	err = tmp14.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.DerSig = tmp14
	tmp15, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.SigType = BitcoinTransaction_Vin_ScriptSignature_SighashType(tmp15)
	tmp16, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenPubkeyStack = tmp16
	tmp17 := NewBitcoinTransaction_Vin_ScriptSignature_PublicKey()
	err = tmp17.Read(this._io, this, this._root)
	if err != nil {
		return err
	}
	this.Pubkey = tmp17
	return err
}

/**
 * DER-encoded ECDSA signature.
 * @see <a href="https://en.wikipedia.org/wiki/X.690#DER_encoding
 * https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm
 * ">Source</a>
 */

/**
 * Type of signature.
 */

/**
 * Public key (bitcoin address of the recipient).
 */
type BitcoinTransaction_Vin_ScriptSignature_DerSignature struct {
	Sequence []byte
	LenSig uint8
	Sep1 []byte
	LenSigR uint8
	SigR []byte
	Sep2 []byte
	LenSigS uint8
	SigS []byte
	_io *kaitai.Stream
	_root *BitcoinTransaction
	_parent *BitcoinTransaction_Vin_ScriptSignature
}
func NewBitcoinTransaction_Vin_ScriptSignature_DerSignature() *BitcoinTransaction_Vin_ScriptSignature_DerSignature {
	return &BitcoinTransaction_Vin_ScriptSignature_DerSignature{
	}
}

func (this *BitcoinTransaction_Vin_ScriptSignature_DerSignature) Read(io *kaitai.Stream, parent *BitcoinTransaction_Vin_ScriptSignature, root *BitcoinTransaction) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp18, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp18 = tmp18
	this.Sequence = tmp18
	if !(bytes.Equal(this.Sequence, []uint8{48})) {
		return kaitai.NewValidationNotEqualError([]uint8{48}, this.Sequence, this._io, "/types/vin/types/script_signature/types/der_signature/seq/0")
	}
	tmp19, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenSig = tmp19
	tmp20, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp20 = tmp20
	this.Sep1 = tmp20
	if !(bytes.Equal(this.Sep1, []uint8{2})) {
		return kaitai.NewValidationNotEqualError([]uint8{2}, this.Sep1, this._io, "/types/vin/types/script_signature/types/der_signature/seq/2")
	}
	tmp21, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenSigR = tmp21
	tmp22, err := this._io.ReadBytes(int(this.LenSigR))
	if err != nil {
		return err
	}
	tmp22 = tmp22
	this.SigR = tmp22
	tmp23, err := this._io.ReadBytes(int(1))
	if err != nil {
		return err
	}
	tmp23 = tmp23
	this.Sep2 = tmp23
	if !(bytes.Equal(this.Sep2, []uint8{2})) {
		return kaitai.NewValidationNotEqualError([]uint8{2}, this.Sep2, this._io, "/types/vin/types/script_signature/types/der_signature/seq/5")
	}
	tmp24, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenSigS = tmp24
	tmp25, err := this._io.ReadBytes(int(this.LenSigS))
	if err != nil {
		return err
	}
	tmp25 = tmp25
	this.SigS = tmp25
	return err
}

/**
 * 'r' value's length.
 */

/**
 * 'r' value of the ECDSA signature.
 * @see <a href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm">Source</a>
 */

/**
 * 's' value's length.
 */

/**
 * 's' value of the ECDSA signature.
 * @see <a href="https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm">Source</a>
 */
type BitcoinTransaction_Vin_ScriptSignature_PublicKey struct {
	Type uint8
	X []byte
	Y []byte
	_io *kaitai.Stream
	_root *BitcoinTransaction
	_parent *BitcoinTransaction_Vin_ScriptSignature
}
func NewBitcoinTransaction_Vin_ScriptSignature_PublicKey() *BitcoinTransaction_Vin_ScriptSignature_PublicKey {
	return &BitcoinTransaction_Vin_ScriptSignature_PublicKey{
	}
}

func (this *BitcoinTransaction_Vin_ScriptSignature_PublicKey) Read(io *kaitai.Stream, parent *BitcoinTransaction_Vin_ScriptSignature, root *BitcoinTransaction) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp26, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.Type = tmp26
	tmp27, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp27 = tmp27
	this.X = tmp27
	tmp28, err := this._io.ReadBytes(int(32))
	if err != nil {
		return err
	}
	tmp28 = tmp28
	this.Y = tmp28
	return err
}

/**
 * 'x' coordinate of the public key on the elliptic curve.
 */

/**
 * 'y' coordinate of the public key on the elliptic curve.
 */
type BitcoinTransaction_Vout struct {
	Amount uint64
	LenScript uint8
	ScriptPubKey []byte
	_io *kaitai.Stream
	_root *BitcoinTransaction
	_parent *BitcoinTransaction
}
func NewBitcoinTransaction_Vout() *BitcoinTransaction_Vout {
	return &BitcoinTransaction_Vout{
	}
}

func (this *BitcoinTransaction_Vout) Read(io *kaitai.Stream, parent *BitcoinTransaction, root *BitcoinTransaction) (err error) {
	this._io = io
	this._parent = parent
	this._root = root

	tmp29, err := this._io.ReadU8le()
	if err != nil {
		return err
	}
	this.Amount = uint64(tmp29)
	tmp30, err := this._io.ReadU1()
	if err != nil {
		return err
	}
	this.LenScript = tmp30
	tmp31, err := this._io.ReadBytes(int(this.LenScript))
	if err != nil {
		return err
	}
	tmp31 = tmp31
	this.ScriptPubKey = tmp31
	return err
}

/**
 * Number of Satoshis to be transfered.
 */

/**
 * ScriptPubKey's length.
 */

/**
 * ScriptPubKey.
 * @see <a href="https://en.bitcoin.it/wiki/Transaction#Output
 * https://en.bitcoin.it/wiki/Script
 * ">Source</a>
 */