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 }