9 "github.com/bytom/vapor/encoding/blockchain"
10 "github.com/bytom/vapor/errors"
11 "github.com/bytom/vapor/protocol/bc"
14 const serRequired = 0x7 // Bit mask accepted serialization flag.
16 // Tx holds a transaction along with its hash.
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 {
31 // OutputID return the hash of the output position
32 func (tx *Tx) OutputID(outputIndex int) *bc.Hash {
33 return tx.ResultIds[outputIndex]
36 // UnmarshalText fulfills the encoding.TextUnmarshaler interface.
37 func (tx *Tx) UnmarshalText(p []byte) error {
38 if err := tx.TxData.UnmarshalText(p); err != nil {
42 tx.Tx = MapTx(&tx.TxData)
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]
51 switch e := e.(type) {
53 e.WitnessArguments = args
54 case *bc.CrossChainInput:
55 e.WitnessArguments = args
57 e.WitnessArguments = args
61 // TxData encodes a transaction in the blockchain.
70 // MarshalText fulfills the json.Marshaler interface.
71 func (tx *TxData) MarshalText() ([]byte, error) {
73 if _, err := tx.WriteTo(&buf); err != nil {
77 b := make([]byte, hex.EncodedLen(buf.Len()))
78 hex.Encode(b, buf.Bytes())
82 // UnmarshalText fulfills the encoding.TextUnmarshaler interface.
83 func (tx *TxData) UnmarshalText(p []byte) error {
84 b := make([]byte, hex.DecodedLen(len(p)))
85 if _, err := hex.Decode(b, p); err != nil {
89 r := blockchain.NewReader(b)
90 if err := tx.readFrom(r); err != nil {
94 if trailing := r.Len(); trailing > 0 {
95 return fmt.Errorf("trailing garbage (%d bytes)", trailing)
100 func (tx *TxData) readFrom(r *blockchain.Reader) (err error) {
101 startSerializedSize := r.Len()
103 if _, err = io.ReadFull(r, serflags[:]); err != nil {
104 return errors.Wrap(err, "reading serialization flags")
106 if serflags[0] != serRequired {
107 return fmt.Errorf("unsupported serflags %#x", serflags[0])
110 if tx.Version, err = blockchain.ReadVarint63(r); err != nil {
111 return errors.Wrap(err, "reading transaction version")
113 if tx.TimeRange, err = blockchain.ReadVarint63(r); err != nil {
117 n, err := blockchain.ReadVarint31(r)
119 return errors.Wrap(err, "reading number of transaction inputs")
124 if err = ti.readFrom(r); err != nil {
125 return errors.Wrapf(err, "reading input %d", len(tx.Inputs))
127 tx.Inputs = append(tx.Inputs, ti)
130 n, err = blockchain.ReadVarint31(r)
132 return errors.Wrap(err, "reading number of transaction outputs")
137 if err = to.readFrom(r); err != nil {
138 return errors.Wrapf(err, "reading output %d", len(tx.Outputs))
140 tx.Outputs = append(tx.Outputs, to)
142 tx.SerializedSize = uint64(startSerializedSize - r.Len())
146 // WriteTo writes tx to w.
147 func (tx *TxData) WriteTo(w io.Writer) (int64, error) {
148 ew := errors.NewWriter(w)
149 if err := tx.writeTo(ew, serRequired); err != nil {
152 return ew.Written(), ew.Err()
155 func (tx *TxData) writeTo(w io.Writer, serflags byte) error {
156 if _, err := w.Write([]byte{serflags}); err != nil {
157 return errors.Wrap(err, "writing serialization flags")
159 if _, err := blockchain.WriteVarint63(w, tx.Version); err != nil {
160 return errors.Wrap(err, "writing transaction version")
162 if _, err := blockchain.WriteVarint63(w, tx.TimeRange); err != nil {
163 return errors.Wrap(err, "writing transaction maxtime")
166 if _, err := blockchain.WriteVarint31(w, uint64(len(tx.Inputs))); err != nil {
167 return errors.Wrap(err, "writing tx input count")
170 for i, ti := range tx.Inputs {
171 if err := ti.writeTo(w); err != nil {
172 return errors.Wrapf(err, "writing tx input %d", i)
176 if _, err := blockchain.WriteVarint31(w, uint64(len(tx.Outputs))); err != nil {
177 return errors.Wrap(err, "writing tx output count")
180 for i, to := range tx.Outputs {
181 if err := to.writeTo(w); err != nil {
182 return errors.Wrapf(err, "writing tx output %d", i)