You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
591 lines
18 KiB
591 lines
18 KiB
// Copyright (c) 2013-2015 The btcsuite developers |
|
// Use of this source code is governed by an ISC |
|
// license that can be found in the LICENSE file. |
|
|
|
package wire |
|
|
|
import ( |
|
"bytes" |
|
"encoding/binary" |
|
"fmt" |
|
"io" |
|
"strconv" |
|
) |
|
|
|
const ( |
|
// TxVersion is the current latest supported transaction version. |
|
TxVersion = 1 |
|
|
|
// MaxTxInSequenceNum is the maximum sequence number the sequence field |
|
// of a transaction input can be. |
|
MaxTxInSequenceNum uint32 = 0xffffffff |
|
|
|
// MaxPrevOutIndex is the maximum index the index field of a previous |
|
// outpoint can be. |
|
MaxPrevOutIndex uint32 = 0xffffffff |
|
) |
|
|
|
// defaultTxInOutAlloc is the default size used for the backing array for |
|
// transaction inputs and outputs. The array will dynamically grow as needed, |
|
// but this figure is intended to provide enough space for the number of |
|
// inputs and outputs in a typical transaction without needing to grow the |
|
// backing array multiple times. |
|
const defaultTxInOutAlloc = 15 |
|
|
|
const ( |
|
// minTxInPayload is the minimum payload size for a transaction input. |
|
// PreviousOutPoint.Hash + PreviousOutPoint.Index 4 bytes + Varint for |
|
// SignatureScript length 1 byte + Sequence 4 bytes. |
|
minTxInPayload = 9 + HashSize |
|
|
|
// maxTxInPerMessage is the maximum number of transactions inputs that |
|
// a transaction which fits into a message could possibly have. |
|
maxTxInPerMessage = (MaxMessagePayload / minTxInPayload) + 1 |
|
|
|
// minTxOutPayload is the minimum payload size for a transaction output. |
|
// Value 8 bytes + Varint for PkScript length 1 byte. |
|
minTxOutPayload = 9 |
|
|
|
// maxTxOutPerMessage is the maximum number of transactions outputs that |
|
// a transaction which fits into a message could possibly have. |
|
maxTxOutPerMessage = (MaxMessagePayload / minTxOutPayload) + 1 |
|
|
|
// minTxPayload is the minimum payload size for a transaction. Note |
|
// that any realistically usable transaction must have at least one |
|
// input or output, but that is a rule enforced at a higher layer, so |
|
// it is intentionally not included here. |
|
// Version 4 bytes + Varint number of transaction inputs 1 byte + Varint |
|
// number of transaction outputs 1 byte + LockTime 4 bytes + min input |
|
// payload + min output payload. |
|
minTxPayload = 10 |
|
) |
|
|
|
// OutPoint defines a bitcoin data type that is used to track previous |
|
// transaction outputs. |
|
type OutPoint struct { |
|
Hash ShaHash |
|
Index uint32 |
|
} |
|
|
|
// NewOutPoint returns a new bitcoin transaction outpoint point with the |
|
// provided hash and index. |
|
func NewOutPoint(hash *ShaHash, index uint32) *OutPoint { |
|
return &OutPoint{ |
|
Hash: *hash, |
|
Index: index, |
|
} |
|
} |
|
|
|
// String returns the OutPoint in the human-readable form "hash:index". |
|
func (o OutPoint) String() string { |
|
// Allocate enough for hash string, colon, and 10 digits. Although |
|
// at the time of writing, the number of digits can be no greater than |
|
// the length of the decimal representation of maxTxOutPerMessage, the |
|
// maximum message payload may increase in the future and this |
|
// optimization may go unnoticed, so allocate space for 10 decimal |
|
// digits, which will fit any uint32. |
|
buf := make([]byte, 2*HashSize+1, 2*HashSize+1+10) |
|
copy(buf, o.Hash.String()) |
|
buf[2*HashSize] = ':' |
|
buf = strconv.AppendUint(buf, uint64(o.Index), 10) |
|
return string(buf) |
|
} |
|
|
|
// TxIn defines a bitcoin transaction input. |
|
type TxIn struct { |
|
PreviousOutPoint OutPoint |
|
SignatureScript []byte |
|
Sequence uint32 |
|
} |
|
|
|
// SerializeSize returns the number of bytes it would take to serialize the |
|
// the transaction input. |
|
func (t *TxIn) SerializeSize() int { |
|
// Outpoint Hash 32 bytes + Outpoint Index 4 bytes + Sequence 4 bytes + |
|
// serialized varint size for the length of SignatureScript + |
|
// SignatureScript bytes. |
|
return 40 + VarIntSerializeSize(uint64(len(t.SignatureScript))) + |
|
len(t.SignatureScript) |
|
} |
|
|
|
// NewTxIn returns a new bitcoin transaction input with the provided |
|
// previous outpoint point and signature script with a default sequence of |
|
// MaxTxInSequenceNum. |
|
func NewTxIn(prevOut *OutPoint, signatureScript []byte) *TxIn { |
|
return &TxIn{ |
|
PreviousOutPoint: *prevOut, |
|
SignatureScript: signatureScript, |
|
Sequence: MaxTxInSequenceNum, |
|
} |
|
} |
|
|
|
// TxOut defines a bitcoin transaction output. |
|
type TxOut struct { |
|
Value int64 |
|
PkScript []byte |
|
} |
|
|
|
// SerializeSize returns the number of bytes it would take to serialize the |
|
// the transaction output. |
|
func (t *TxOut) SerializeSize() int { |
|
// Value 8 bytes + serialized varint size for the length of PkScript + |
|
// PkScript bytes. |
|
return 8 + VarIntSerializeSize(uint64(len(t.PkScript))) + len(t.PkScript) |
|
} |
|
|
|
// NewTxOut returns a new bitcoin transaction output with the provided |
|
// transaction value and public key script. |
|
func NewTxOut(value int64, pkScript []byte) *TxOut { |
|
return &TxOut{ |
|
Value: value, |
|
PkScript: pkScript, |
|
} |
|
} |
|
|
|
// MsgTx implements the Message interface and represents a bitcoin tx message. |
|
// It is used to deliver transaction information in response to a getdata |
|
// message (MsgGetData) for a given transaction. |
|
// |
|
// Use the AddTxIn and AddTxOut functions to build up the list of transaction |
|
// inputs and outputs. |
|
type MsgTx struct { |
|
Version int32 |
|
TxIn []*TxIn |
|
TxOut []*TxOut |
|
LockTime uint32 |
|
} |
|
|
|
// AddTxIn adds a transaction input to the message. |
|
func (msg *MsgTx) AddTxIn(ti *TxIn) { |
|
msg.TxIn = append(msg.TxIn, ti) |
|
} |
|
|
|
// AddTxOut adds a transaction output to the message. |
|
func (msg *MsgTx) AddTxOut(to *TxOut) { |
|
msg.TxOut = append(msg.TxOut, to) |
|
} |
|
|
|
// TxSha generates the ShaHash name for the transaction. |
|
func (msg *MsgTx) TxSha() ShaHash { |
|
// Encode the transaction and calculate double sha256 on the result. |
|
// Ignore the error returns since the only way the encode could fail |
|
// is being out of memory or due to nil pointers, both of which would |
|
// cause a run-time panic. |
|
buf := bytes.NewBuffer(make([]byte, 0, msg.SerializeSize())) |
|
_ = msg.Serialize(buf) |
|
return DoubleSha256SH(buf.Bytes()) |
|
} |
|
|
|
// Copy creates a deep copy of a transaction so that the original does not get |
|
// modified when the copy is manipulated. |
|
func (msg *MsgTx) Copy() *MsgTx { |
|
// Create new tx and start by copying primitive values and making space |
|
// for the transaction inputs and outputs. |
|
newTx := MsgTx{ |
|
Version: msg.Version, |
|
TxIn: make([]*TxIn, 0, len(msg.TxIn)), |
|
TxOut: make([]*TxOut, 0, len(msg.TxOut)), |
|
LockTime: msg.LockTime, |
|
} |
|
|
|
// Deep copy the old TxIn data. |
|
for _, oldTxIn := range msg.TxIn { |
|
// Deep copy the old previous outpoint. |
|
oldOutPoint := oldTxIn.PreviousOutPoint |
|
newOutPoint := OutPoint{} |
|
newOutPoint.Hash.SetBytes(oldOutPoint.Hash[:]) |
|
newOutPoint.Index = oldOutPoint.Index |
|
|
|
// Deep copy the old signature script. |
|
var newScript []byte |
|
oldScript := oldTxIn.SignatureScript |
|
oldScriptLen := len(oldScript) |
|
if oldScriptLen > 0 { |
|
newScript = make([]byte, oldScriptLen, oldScriptLen) |
|
copy(newScript, oldScript[:oldScriptLen]) |
|
} |
|
|
|
// Create new txIn with the deep copied data and append it to |
|
// new Tx. |
|
newTxIn := TxIn{ |
|
PreviousOutPoint: newOutPoint, |
|
SignatureScript: newScript, |
|
Sequence: oldTxIn.Sequence, |
|
} |
|
newTx.TxIn = append(newTx.TxIn, &newTxIn) |
|
} |
|
|
|
// Deep copy the old TxOut data. |
|
for _, oldTxOut := range msg.TxOut { |
|
// Deep copy the old PkScript |
|
var newScript []byte |
|
oldScript := oldTxOut.PkScript |
|
oldScriptLen := len(oldScript) |
|
if oldScriptLen > 0 { |
|
newScript = make([]byte, oldScriptLen, oldScriptLen) |
|
copy(newScript, oldScript[:oldScriptLen]) |
|
} |
|
|
|
// Create new txOut with the deep copied data and append it to |
|
// new Tx. |
|
newTxOut := TxOut{ |
|
Value: oldTxOut.Value, |
|
PkScript: newScript, |
|
} |
|
newTx.TxOut = append(newTx.TxOut, &newTxOut) |
|
} |
|
|
|
return &newTx |
|
} |
|
|
|
// BtcDecode decodes r using the bitcoin protocol encoding into the receiver. |
|
// This is part of the Message interface implementation. |
|
// See Deserialize for decoding transactions stored to disk, such as in a |
|
// database, as opposed to decoding transactions from the wire. |
|
func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error { |
|
var buf [4]byte |
|
_, err := io.ReadFull(r, buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
msg.Version = int32(binary.LittleEndian.Uint32(buf[:])) |
|
|
|
count, err := readVarInt(r, pver) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// Prevent more input transactions than could possibly fit into a |
|
// message. It would be possible to cause memory exhaustion and panics |
|
// without a sane upper bound on this count. |
|
if count > uint64(maxTxInPerMessage) { |
|
str := fmt.Sprintf("too many input transactions to fit into "+ |
|
"max message size [count %d, max %d]", count, |
|
maxTxInPerMessage) |
|
return messageError("MsgTx.BtcDecode", str) |
|
} |
|
|
|
msg.TxIn = make([]*TxIn, count) |
|
for i := uint64(0); i < count; i++ { |
|
ti := TxIn{} |
|
err = readTxIn(r, pver, msg.Version, &ti) |
|
if err != nil { |
|
return err |
|
} |
|
msg.TxIn[i] = &ti |
|
} |
|
|
|
count, err = readVarInt(r, pver) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
// Prevent more output transactions than could possibly fit into a |
|
// message. It would be possible to cause memory exhaustion and panics |
|
// without a sane upper bound on this count. |
|
if count > uint64(maxTxOutPerMessage) { |
|
str := fmt.Sprintf("too many output transactions to fit into "+ |
|
"max message size [count %d, max %d]", count, |
|
maxTxOutPerMessage) |
|
return messageError("MsgTx.BtcDecode", str) |
|
} |
|
|
|
msg.TxOut = make([]*TxOut, count) |
|
for i := uint64(0); i < count; i++ { |
|
to := TxOut{} |
|
err = readTxOut(r, pver, msg.Version, &to) |
|
if err != nil { |
|
return err |
|
} |
|
msg.TxOut[i] = &to |
|
} |
|
|
|
_, err = io.ReadFull(r, buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
msg.LockTime = binary.LittleEndian.Uint32(buf[:]) |
|
|
|
return nil |
|
} |
|
|
|
// Deserialize decodes a transaction from r into the receiver using a format |
|
// that is suitable for long-term storage such as a database while respecting |
|
// the Version field in the transaction. This function differs from BtcDecode |
|
// in that BtcDecode decodes from the bitcoin wire protocol as it was sent |
|
// across the network. The wire encoding can technically differ depending on |
|
// the protocol version and doesn't even really need to match the format of a |
|
// stored transaction at all. As of the time this comment was written, the |
|
// encoded transaction is the same in both instances, but there is a distinct |
|
// difference and separating the two allows the API to be flexible enough to |
|
// deal with changes. |
|
func (msg *MsgTx) Deserialize(r io.Reader) error { |
|
// At the current time, there is no difference between the wire encoding |
|
// at protocol version 0 and the stable long-term storage format. As |
|
// a result, make use of BtcDecode. |
|
return msg.BtcDecode(r, 0) |
|
} |
|
|
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding. |
|
// This is part of the Message interface implementation. |
|
// See Serialize for encoding transactions to be stored to disk, such as in a |
|
// database, as opposed to encoding transactions for the wire. |
|
func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error { |
|
var buf [4]byte |
|
binary.LittleEndian.PutUint32(buf[:], uint32(msg.Version)) |
|
_, err := w.Write(buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
count := uint64(len(msg.TxIn)) |
|
err = writeVarInt(w, pver, count) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
for _, ti := range msg.TxIn { |
|
err = writeTxIn(w, pver, msg.Version, ti) |
|
if err != nil { |
|
return err |
|
} |
|
} |
|
|
|
count = uint64(len(msg.TxOut)) |
|
err = writeVarInt(w, pver, count) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
for _, to := range msg.TxOut { |
|
err = writeTxOut(w, pver, msg.Version, to) |
|
if err != nil { |
|
return err |
|
} |
|
} |
|
|
|
binary.LittleEndian.PutUint32(buf[:], msg.LockTime) |
|
_, err = w.Write(buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// Serialize encodes the transaction to w using a format that suitable for |
|
// long-term storage such as a database while respecting the Version field in |
|
// the transaction. This function differs from BtcEncode in that BtcEncode |
|
// encodes the transaction to the bitcoin wire protocol in order to be sent |
|
// across the network. The wire encoding can technically differ depending on |
|
// the protocol version and doesn't even really need to match the format of a |
|
// stored transaction at all. As of the time this comment was written, the |
|
// encoded transaction is the same in both instances, but there is a distinct |
|
// difference and separating the two allows the API to be flexible enough to |
|
// deal with changes. |
|
func (msg *MsgTx) Serialize(w io.Writer) error { |
|
// At the current time, there is no difference between the wire encoding |
|
// at protocol version 0 and the stable long-term storage format. As |
|
// a result, make use of BtcEncode. |
|
return msg.BtcEncode(w, 0) |
|
|
|
} |
|
|
|
// SerializeSize returns the number of bytes it would take to serialize the |
|
// the transaction. |
|
func (msg *MsgTx) SerializeSize() int { |
|
// Version 4 bytes + LockTime 4 bytes + Serialized varint size for the |
|
// number of transaction inputs and outputs. |
|
n := 8 + VarIntSerializeSize(uint64(len(msg.TxIn))) + |
|
VarIntSerializeSize(uint64(len(msg.TxOut))) |
|
|
|
for _, txIn := range msg.TxIn { |
|
n += txIn.SerializeSize() |
|
} |
|
|
|
for _, txOut := range msg.TxOut { |
|
n += txOut.SerializeSize() |
|
} |
|
|
|
return n |
|
} |
|
|
|
// Command returns the protocol command string for the message. This is part |
|
// of the Message interface implementation. |
|
func (msg *MsgTx) Command() string { |
|
return CmdTx |
|
} |
|
|
|
// MaxPayloadLength returns the maximum length the payload can be for the |
|
// receiver. This is part of the Message interface implementation. |
|
func (msg *MsgTx) MaxPayloadLength(pver uint32) uint32 { |
|
return MaxBlockPayload |
|
} |
|
|
|
// PkScriptLocs returns a slice containing the start of each public key script |
|
// within the raw serialized transaction. The caller can easily obtain the |
|
// length of each script by using len on the script available via the |
|
// appropriate transaction output entry. |
|
func (msg *MsgTx) PkScriptLocs() []int { |
|
numTxOut := len(msg.TxOut) |
|
if numTxOut == 0 { |
|
return nil |
|
} |
|
|
|
// The starting offset in the serialized transaction of the first |
|
// transaction output is: |
|
// |
|
// Version 4 bytes + serialized varint size for the number of |
|
// transaction inputs and outputs + serialized size of each transaction |
|
// input. |
|
n := 4 + VarIntSerializeSize(uint64(len(msg.TxIn))) + |
|
VarIntSerializeSize(uint64(numTxOut)) |
|
for _, txIn := range msg.TxIn { |
|
n += txIn.SerializeSize() |
|
} |
|
|
|
// Calculate and set the appropriate offset for each public key script. |
|
pkScriptLocs := make([]int, numTxOut) |
|
for i, txOut := range msg.TxOut { |
|
// The offset of the script in the transaction output is: |
|
// |
|
// Value 8 bytes + serialized varint size for the length of |
|
// PkScript. |
|
n += 8 + VarIntSerializeSize(uint64(len(txOut.PkScript))) |
|
pkScriptLocs[i] = n |
|
n += len(txOut.PkScript) |
|
} |
|
|
|
return pkScriptLocs |
|
} |
|
|
|
// NewMsgTx returns a new bitcoin tx message that conforms to the Message |
|
// interface. The return instance has a default version of TxVersion and there |
|
// are no transaction inputs or outputs. Also, the lock time is set to zero |
|
// to indicate the transaction is valid immediately as opposed to some time in |
|
// future. |
|
func NewMsgTx() *MsgTx { |
|
return &MsgTx{ |
|
Version: TxVersion, |
|
TxIn: make([]*TxIn, 0, defaultTxInOutAlloc), |
|
TxOut: make([]*TxOut, 0, defaultTxInOutAlloc), |
|
} |
|
} |
|
|
|
// readOutPoint reads the next sequence of bytes from r as an OutPoint. |
|
func readOutPoint(r io.Reader, pver uint32, version int32, op *OutPoint) error { |
|
_, err := io.ReadFull(r, op.Hash[:]) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
var buf [4]byte |
|
_, err = io.ReadFull(r, buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
op.Index = binary.LittleEndian.Uint32(buf[:]) |
|
return nil |
|
} |
|
|
|
// writeOutPoint encodes op to the bitcoin protocol encoding for an OutPoint |
|
// to w. |
|
func writeOutPoint(w io.Writer, pver uint32, version int32, op *OutPoint) error { |
|
_, err := w.Write(op.Hash[:]) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
var buf [4]byte |
|
binary.LittleEndian.PutUint32(buf[:], op.Index) |
|
_, err = w.Write(buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
return nil |
|
} |
|
|
|
// readTxIn reads the next sequence of bytes from r as a transaction input |
|
// (TxIn). |
|
func readTxIn(r io.Reader, pver uint32, version int32, ti *TxIn) error { |
|
var op OutPoint |
|
err := readOutPoint(r, pver, version, &op) |
|
if err != nil { |
|
return err |
|
} |
|
ti.PreviousOutPoint = op |
|
|
|
ti.SignatureScript, err = readVarBytes(r, pver, MaxMessagePayload, |
|
"transaction input signature script") |
|
if err != nil { |
|
return err |
|
} |
|
|
|
var buf [4]byte |
|
_, err = io.ReadFull(r, buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
ti.Sequence = binary.LittleEndian.Uint32(buf[:]) |
|
|
|
return nil |
|
} |
|
|
|
// writeTxIn encodes ti to the bitcoin protocol encoding for a transaction |
|
// input (TxIn) to w. |
|
func writeTxIn(w io.Writer, pver uint32, version int32, ti *TxIn) error { |
|
err := writeOutPoint(w, pver, version, &ti.PreviousOutPoint) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
err = writeVarBytes(w, pver, ti.SignatureScript) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
var buf [4]byte |
|
binary.LittleEndian.PutUint32(buf[:], ti.Sequence) |
|
_, err = w.Write(buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// readTxOut reads the next sequence of bytes from r as a transaction output |
|
// (TxOut). |
|
func readTxOut(r io.Reader, pver uint32, version int32, to *TxOut) error { |
|
var buf [8]byte |
|
_, err := io.ReadFull(r, buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
to.Value = int64(binary.LittleEndian.Uint64(buf[:])) |
|
|
|
to.PkScript, err = readVarBytes(r, pver, MaxMessagePayload, |
|
"transaction output public key script") |
|
if err != nil { |
|
return err |
|
} |
|
|
|
return nil |
|
} |
|
|
|
// writeTxOut encodes to into the bitcoin protocol encoding for a transaction |
|
// output (TxOut) to w. |
|
func writeTxOut(w io.Writer, pver uint32, version int32, to *TxOut) error { |
|
var buf [8]byte |
|
binary.LittleEndian.PutUint64(buf[:], uint64(to.Value)) |
|
_, err := w.Write(buf[:]) |
|
if err != nil { |
|
return err |
|
} |
|
|
|
err = writeVarBytes(w, pver, to.PkScript) |
|
if err != nil { |
|
return err |
|
} |
|
return nil |
|
}
|
|
|