2013-05-08 21:31:00 +02:00
|
|
|
// Copyright (c) 2013 Conformal Systems LLC.
|
|
|
|
// Use of this source code is governed by an ISC
|
|
|
|
// license that can be found in the LICENSE file.
|
|
|
|
|
|
|
|
package btcwire
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"io"
|
|
|
|
)
|
|
|
|
|
2013-09-25 20:57:01 +02:00
|
|
|
// 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
|
|
|
|
|
2013-07-27 23:34:47 +02:00
|
|
|
// TxVersion is the current latest supported transaction version.
|
|
|
|
const TxVersion = 1
|
|
|
|
|
2013-05-08 21:31:00 +02:00
|
|
|
// MaxTxInSequenceNum is the maximum sequence number the sequence field
|
|
|
|
// of a transaction input can be.
|
|
|
|
const MaxTxInSequenceNum uint32 = 0xffffffff
|
|
|
|
|
2013-07-27 23:18:13 +02:00
|
|
|
// OutPoint defines a bitcoin data type that is used to track previous
|
2013-05-08 21:31:00 +02:00
|
|
|
// 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,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TxIn defines a bitcoin transaction input.
|
|
|
|
type TxIn struct {
|
|
|
|
PreviousOutpoint OutPoint
|
|
|
|
SignatureScript []byte
|
|
|
|
Sequence uint32
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
|
|
|
// 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 uint32
|
|
|
|
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.
|
2013-08-05 23:24:50 +02:00
|
|
|
func (tx *MsgTx) TxSha() (ShaHash, error) {
|
2013-05-12 21:01:50 +02:00
|
|
|
// 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. Also, SetBytes can't fail here due to the
|
|
|
|
// fact DoubleSha256 always returns a []byte of the right size
|
|
|
|
// regardless of input.
|
|
|
|
var buf bytes.Buffer
|
|
|
|
var sha ShaHash
|
2013-08-05 23:24:50 +02:00
|
|
|
_ = tx.Serialize(&buf)
|
2013-05-12 21:01:50 +02:00
|
|
|
_ = sha.SetBytes(DoubleSha256(buf.Bytes()))
|
|
|
|
|
|
|
|
// Even though this function can't currently fail, it still returns
|
|
|
|
// a potential error to help future proof the API should a failure
|
|
|
|
// become possible.
|
|
|
|
return sha, nil
|
2013-05-08 21:31:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Copy creates a deep copy of a transaction so that the original does not get
|
|
|
|
// modified when the copy is manipulated.
|
|
|
|
func (tx *MsgTx) Copy() *MsgTx {
|
2013-09-25 20:57:01 +02:00
|
|
|
// Create new tx and start by copying primitive values and making space
|
|
|
|
// for the transaction inputs and outputs.
|
2013-05-08 21:31:00 +02:00
|
|
|
newTx := MsgTx{
|
|
|
|
Version: tx.Version,
|
2013-09-25 20:57:01 +02:00
|
|
|
TxIn: make([]*TxIn, 0, len(tx.TxIn)),
|
|
|
|
TxOut: make([]*TxOut, 0, len(tx.TxOut)),
|
2013-05-08 21:31:00 +02:00
|
|
|
LockTime: tx.LockTime,
|
|
|
|
}
|
|
|
|
|
|
|
|
// Deep copy the old TxIn data.
|
|
|
|
for _, oldTxIn := range tx.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 tx.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.
|
2013-08-05 17:53:27 +02:00
|
|
|
// See Deserialize for decoding transactions stored to disk, such as in a
|
|
|
|
// database, as opposed to decoding transactions from the wire.
|
2013-05-08 21:31:00 +02:00
|
|
|
func (msg *MsgTx) BtcDecode(r io.Reader, pver uint32) error {
|
|
|
|
err := readElement(r, &msg.Version)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err := readVarInt(r, pver)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-09-25 20:57:01 +02:00
|
|
|
msg.TxIn = make([]*TxIn, 0, count)
|
2013-05-08 21:31:00 +02:00
|
|
|
for i := uint64(0); i < count; i++ {
|
|
|
|
ti := TxIn{}
|
|
|
|
err = readTxIn(r, pver, msg.Version, &ti)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
msg.TxIn = append(msg.TxIn, &ti)
|
|
|
|
}
|
|
|
|
|
|
|
|
count, err = readVarInt(r, pver)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
2013-09-25 20:57:01 +02:00
|
|
|
msg.TxOut = make([]*TxOut, 0, count)
|
2013-05-08 21:31:00 +02:00
|
|
|
for i := uint64(0); i < count; i++ {
|
|
|
|
to := TxOut{}
|
|
|
|
err = readTxOut(r, pver, msg.Version, &to)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
msg.TxOut = append(msg.TxOut, &to)
|
|
|
|
}
|
|
|
|
|
|
|
|
err = readElement(r, &msg.LockTime)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-08-05 17:53:27 +02:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2013-05-08 21:31:00 +02:00
|
|
|
// BtcEncode encodes the receiver to w using the bitcoin protocol encoding.
|
|
|
|
// This is part of the Message interface implementation.
|
2013-08-05 17:53:27 +02:00
|
|
|
// See Serialize for encoding transactions to be stored to disk, such as in a
|
|
|
|
// database, as opposed to encoding transactions for the wire.
|
2013-05-08 21:31:00 +02:00
|
|
|
func (msg *MsgTx) BtcEncode(w io.Writer, pver uint32) error {
|
|
|
|
err := writeElement(w, msg.Version)
|
|
|
|
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, to)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err = writeElement(w, msg.LockTime)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2013-08-05 17:53:27 +02:00
|
|
|
// 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)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-05-08 21:31:00 +02:00
|
|
|
// 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 {
|
2013-09-19 23:46:14 +02:00
|
|
|
return MaxBlockPayload
|
2013-05-08 21:31:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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 {
|
2013-09-25 20:57:01 +02:00
|
|
|
return &MsgTx{
|
|
|
|
Version: TxVersion,
|
|
|
|
TxIn: make([]*TxIn, 0, defaultTxInOutAlloc),
|
|
|
|
TxOut: make([]*TxOut, 0, defaultTxInOutAlloc),
|
|
|
|
}
|
2013-05-08 21:31:00 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// readOutPoint reads the next sequence of bytes from r as an OutPoint.
|
|
|
|
func readOutPoint(r io.Reader, pver uint32, version uint32, op *OutPoint) error {
|
|
|
|
err := readElements(r, &op.Hash, &op.Index)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeOutPoint encodes op to the bitcoin protocol encoding for an OutPoint
|
|
|
|
// to w.
|
|
|
|
func writeOutPoint(w io.Writer, pver uint32, version uint32, op *OutPoint) error {
|
|
|
|
err := writeElements(w, op.Hash, op.Index)
|
|
|
|
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 uint32, ti *TxIn) error {
|
|
|
|
op := OutPoint{}
|
|
|
|
err := readOutPoint(r, pver, version, &op)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ti.PreviousOutpoint = op
|
|
|
|
|
|
|
|
count, err := readVarInt(r, pver)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b := make([]byte, count)
|
|
|
|
err = readElement(r, b)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
ti.SignatureScript = b
|
|
|
|
|
|
|
|
err = readElement(r, &ti.Sequence)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
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 uint32, ti *TxIn) error {
|
|
|
|
err := writeOutPoint(w, pver, version, &ti.PreviousOutpoint)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
slen := uint64(len(ti.SignatureScript))
|
|
|
|
err = writeVarInt(w, pver, slen)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b := []byte(ti.SignatureScript)
|
|
|
|
_, err = w.Write(b)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = writeElement(w, &ti.Sequence)
|
|
|
|
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 uint32, to *TxOut) error {
|
|
|
|
err := readElement(r, &to.Value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
slen, err := readVarInt(r, pver)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
b := make([]byte, slen)
|
|
|
|
err = readElement(r, b)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
to.PkScript = b
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// writeTxOut encodes to into the bitcoin protocol encoding for a transaction
|
|
|
|
// output (TxOut) to w.
|
|
|
|
func writeTxOut(w io.Writer, pver uint32, to *TxOut) error {
|
|
|
|
err := writeElement(w, to.Value)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
pkLen := uint64(len(to.PkScript))
|
|
|
|
err = writeVarInt(w, pver, pkLen)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
err = writeElement(w, to.PkScript)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|