github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/bc/types/transaction.go (about)

     1  package types
     2  
     3  import (
     4  	"bytes"
     5  	"encoding/hex"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/bytom/bytom/encoding/blockchain"
    10  	"github.com/bytom/bytom/errors"
    11  	"github.com/bytom/bytom/protocol/bc"
    12  )
    13  
    14  const serRequired = 0x7 // Bit mask accepted serialization flag.
    15  
    16  // Tx holds a transaction along with its hash.
    17  type Tx struct {
    18  	TxData
    19  	*bc.Tx `json:"-"`
    20  }
    21  
    22  // NewTx returns a new Tx containing data and its hash. If you have already
    23  // computed the hash, use struct literal notation to make a Tx object directly.
    24  func NewTx(data TxData) *Tx {
    25  	return &Tx{
    26  		TxData: data,
    27  		Tx:     MapTx(&data),
    28  	}
    29  }
    30  
    31  // OutputID return the hash of the output position
    32  func (tx *Tx) OutputID(outputIndex int) *bc.Hash {
    33  	return tx.ResultIds[outputIndex]
    34  }
    35  
    36  // UnmarshalText fulfills the encoding.TextUnmarshaler interface.
    37  func (tx *Tx) UnmarshalText(p []byte) error {
    38  	if err := tx.TxData.UnmarshalText(p); err != nil {
    39  		return err
    40  	}
    41  
    42  	tx.Tx = MapTx(&tx.TxData)
    43  	return nil
    44  }
    45  
    46  // SetInputArguments sets the Arguments field in input n.
    47  func (tx *Tx) SetInputArguments(n uint32, args [][]byte) {
    48  	tx.Inputs[n].SetArguments(args)
    49  	id := tx.Tx.InputIDs[n]
    50  	e := tx.Entries[id]
    51  	switch e := e.(type) {
    52  	case *bc.Issuance:
    53  		e.WitnessArguments = args
    54  	case *bc.Spend:
    55  		e.WitnessArguments = args
    56  	}
    57  }
    58  
    59  // TxData encodes a transaction in the blockchain.
    60  type TxData struct {
    61  	Version        uint64
    62  	SerializedSize uint64
    63  	TimeRange      uint64
    64  	Inputs         []*TxInput
    65  	Outputs        []*TxOutput
    66  }
    67  
    68  // MarshalText fulfills the json.Marshaler interface.
    69  func (tx *TxData) MarshalText() ([]byte, error) {
    70  	var buf bytes.Buffer
    71  	if _, err := tx.WriteTo(&buf); err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	b := make([]byte, hex.EncodedLen(buf.Len()))
    76  	hex.Encode(b, buf.Bytes())
    77  	return b, nil
    78  }
    79  
    80  // UnmarshalText fulfills the encoding.TextUnmarshaler interface.
    81  func (tx *TxData) UnmarshalText(p []byte) error {
    82  	b := make([]byte, hex.DecodedLen(len(p)))
    83  	if _, err := hex.Decode(b, p); err != nil {
    84  		return err
    85  	}
    86  
    87  	r := blockchain.NewReader(b)
    88  	if err := tx.readFrom(r); err != nil {
    89  		return err
    90  	}
    91  
    92  	if trailing := r.Len(); trailing > 0 {
    93  		return fmt.Errorf("trailing garbage (%d bytes)", trailing)
    94  	}
    95  	return nil
    96  }
    97  
    98  func (tx *TxData) readFrom(r *blockchain.Reader) (err error) {
    99  	startSerializedSize := r.Len()
   100  	var serflags [1]byte
   101  	if _, err = io.ReadFull(r, serflags[:]); err != nil {
   102  		return errors.Wrap(err, "reading serialization flags")
   103  	}
   104  	if serflags[0] != serRequired {
   105  		return fmt.Errorf("unsupported serflags %#x", serflags[0])
   106  	}
   107  
   108  	if tx.Version, err = blockchain.ReadVarint63(r); err != nil {
   109  		return errors.Wrap(err, "reading transaction version")
   110  	}
   111  	if tx.TimeRange, err = blockchain.ReadVarint63(r); err != nil {
   112  		return err
   113  	}
   114  
   115  	n, err := blockchain.ReadVarint31(r)
   116  	if err != nil {
   117  		return errors.Wrap(err, "reading number of transaction inputs")
   118  	}
   119  
   120  	for ; n > 0; n-- {
   121  		ti := new(TxInput)
   122  		if err = ti.readFrom(r); err != nil {
   123  			return errors.Wrapf(err, "reading input %d", len(tx.Inputs))
   124  		}
   125  		tx.Inputs = append(tx.Inputs, ti)
   126  	}
   127  
   128  	n, err = blockchain.ReadVarint31(r)
   129  	if err != nil {
   130  		return errors.Wrap(err, "reading number of transaction outputs")
   131  	}
   132  
   133  	for ; n > 0; n-- {
   134  		to := new(TxOutput)
   135  		if err = to.readFrom(r); err != nil {
   136  			return errors.Wrapf(err, "reading output %d", len(tx.Outputs))
   137  		}
   138  		tx.Outputs = append(tx.Outputs, to)
   139  	}
   140  	tx.SerializedSize = uint64(startSerializedSize - r.Len())
   141  	return nil
   142  }
   143  
   144  // WriteTo writes tx to w.
   145  func (tx *TxData) WriteTo(w io.Writer) (int64, error) {
   146  	ew := errors.NewWriter(w)
   147  	if err := tx.writeTo(ew, serRequired); err != nil {
   148  		return 0, err
   149  	}
   150  	return ew.Written(), ew.Err()
   151  }
   152  
   153  func (tx *TxData) writeTo(w io.Writer, serflags byte) error {
   154  	if _, err := w.Write([]byte{serflags}); err != nil {
   155  		return errors.Wrap(err, "writing serialization flags")
   156  	}
   157  	if _, err := blockchain.WriteVarint63(w, tx.Version); err != nil {
   158  		return errors.Wrap(err, "writing transaction version")
   159  	}
   160  	if _, err := blockchain.WriteVarint63(w, tx.TimeRange); err != nil {
   161  		return errors.Wrap(err, "writing transaction maxtime")
   162  	}
   163  
   164  	if _, err := blockchain.WriteVarint31(w, uint64(len(tx.Inputs))); err != nil {
   165  		return errors.Wrap(err, "writing tx input count")
   166  	}
   167  
   168  	for i, ti := range tx.Inputs {
   169  		if err := ti.writeTo(w); err != nil {
   170  			return errors.Wrapf(err, "writing tx input %d", i)
   171  		}
   172  	}
   173  
   174  	if _, err := blockchain.WriteVarint31(w, uint64(len(tx.Outputs))); err != nil {
   175  		return errors.Wrap(err, "writing tx output count")
   176  	}
   177  
   178  	for i, to := range tx.Outputs {
   179  		if err := to.writeTo(w); err != nil {
   180  			return errors.Wrapf(err, "writing tx output %d", i)
   181  		}
   182  	}
   183  	return nil
   184  }