decred.org/dcrdex@v1.0.5/client/asset/firo/tx_deserialize.go (about) 1 package firo 2 3 import ( 4 "encoding/binary" 5 "fmt" 6 "io" 7 8 "github.com/btcsuite/btcd/wire" 9 ) 10 11 var byteOrder = binary.LittleEndian 12 13 const ( 14 // protocol version 0 15 pver uint32 = 0 16 // wire.maxTxInPerMessage 17 maxTxInPerMessage = wire.MaxMessagePayload/41 + 1 18 // wire.maxTxOutPerMessage 19 maxTxOutPerMessage = wire.MaxMessagePayload/wire.MinTxOutPayload + 1 20 ) 21 22 type TxType int 23 24 const ( 25 // Transaction types 26 TransactionNormal = 0 27 TransactionProviderRegister = 1 28 TransactionProviderUpdateService = 2 29 TransactionProviderUpdateRegistrar = 3 30 TransactionProviderUpdateRevoke = 4 31 TransactionCoinbase = 5 32 TransactionQuorumCommitment = 6 33 TransactionSpork = 7 34 TransactionLelantus = 8 35 TransactionSpark = 9 36 // TRANSACTION_ALIAS is a regular spark spend transaction, but contains 37 // additional info about a created/modified spark name. 38 TransactionAlias = 10 39 ) 40 41 type decoder struct { 42 buf [8]byte 43 rd io.Reader 44 } 45 46 func newDecoder(r io.Reader) *decoder { 47 return &decoder{rd: r} 48 } 49 50 func (d *decoder) Read(b []byte) (n int, err error) { 51 n, err = d.rd.Read(b) 52 if err != nil { 53 return 0, err 54 } 55 return n, nil 56 } 57 58 func (d *decoder) readByte() (byte, error) { 59 b := d.buf[:1] 60 if _, err := io.ReadFull(d, b); err != nil { 61 return 0, err 62 } 63 return b[0], nil 64 } 65 66 func (d *decoder) readUint16() (uint16, error) { 67 b := d.buf[:2] 68 if _, err := io.ReadFull(d, b); err != nil { 69 return 0, err 70 } 71 return byteOrder.Uint16(b), nil 72 } 73 74 func (d *decoder) readUint32() (uint32, error) { 75 b := d.buf[:4] 76 if _, err := io.ReadFull(d, b); err != nil { 77 return 0, err 78 } 79 return byteOrder.Uint32(b), nil 80 } 81 82 func (d *decoder) readUint64() (uint64, error) { 83 b := d.buf[:] 84 if _, err := io.ReadFull(d, b); err != nil { 85 return 0, err 86 } 87 return byteOrder.Uint64(b), nil 88 } 89 90 // readOutPoint reads the next sequence of bytes from r as an OutPoint. 91 func (d *decoder) readOutPoint(op *wire.OutPoint) error { 92 _, err := io.ReadFull(d, op.Hash[:]) 93 if err != nil { 94 return err 95 } 96 97 op.Index, err = d.readUint32() 98 return err 99 } 100 101 // wire.ReadVarInt a.k.a. CompactSize, not VARINT 102 // https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer 103 func (d *decoder) readCompactSize() (uint64, error) { 104 // Compact Size 105 // size < 253 -- 1 byte 106 // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) 107 // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) 108 // size > UINT_MAX -- 9 bytes (255 + 8 bytes) 109 chSize, err := d.readByte() 110 if err != nil { 111 return 0, err 112 } 113 switch chSize { 114 case 253: 115 sz, err := d.readUint16() 116 if err != nil { 117 return 0, err 118 } 119 return uint64(sz), nil 120 case 254: 121 sz, err := d.readUint32() 122 if err != nil { 123 return 0, err 124 } 125 return uint64(sz), nil 126 case 255: 127 sz, err := d.readUint64() 128 if err != nil { 129 return 0, err 130 } 131 return sz, nil 132 default: // < 253 133 return uint64(chSize), nil 134 } 135 } 136 137 // readTxIn reads the next sequence of bytes from r as a transaction input. 138 func (d *decoder) readTxIn(ti *wire.TxIn) error { 139 err := d.readOutPoint(&ti.PreviousOutPoint) 140 if err != nil { 141 return err 142 } 143 144 ti.SignatureScript, err = wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "sigScript") 145 if err != nil { 146 return err 147 } 148 149 ti.Sequence, err = d.readUint32() 150 return err 151 } 152 153 // readTxOut reads the next sequence of bytes from r as a transaction output. 154 func (d *decoder) readTxOut(to *wire.TxOut) error { 155 v, err := d.readUint64() 156 if err != nil { 157 return err 158 } 159 160 pkScript, err := wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "pkScript") 161 if err != nil { 162 return err 163 } 164 165 to.Value = int64(v) 166 to.PkScript = pkScript 167 168 return nil 169 } 170 171 // readVarBytes reads the next sequence of bytes from r and returns them. 172 func (d *decoder) readVarBytes() ([]byte, error) { 173 byteArray, err := wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "extra") 174 if err != nil { 175 return nil, err 176 } 177 return byteArray, nil 178 } 179 180 type txn struct { 181 msgTx *wire.MsgTx 182 txType TxType 183 } 184 185 // deserializeTransaction deserializes a transaction 186 func deserializeTransaction(r io.Reader) (*txn, error) { 187 tx := txn{ 188 msgTx: &wire.MsgTx{}, 189 txType: 0, 190 } 191 192 dec := newDecoder(r) 193 194 fullVersion, err := dec.readUint32() 195 if err != nil { 196 return nil, err 197 } 198 ver := fullVersion & 0x0000ffff 199 typ := (fullVersion >> 16) & 0x0000ffff 200 201 tx.msgTx.Version = int32(ver) 202 tx.txType = TxType(typ) 203 204 switch tx.txType { 205 case TransactionNormal, 206 TransactionProviderRegister, 207 TransactionProviderUpdateService, 208 TransactionProviderUpdateRegistrar, 209 TransactionProviderUpdateRevoke, 210 TransactionCoinbase, 211 TransactionLelantus, 212 TransactionSpark, 213 TransactionAlias: 214 { 215 deserializeTx(dec, &tx, tx.txType) 216 } 217 case TransactionQuorumCommitment, 218 TransactionSpork: 219 err = deserializeNonSpendingTx(dec, &tx, tx.txType) 220 default: 221 err = fmt.Errorf("unknown transaction type %d", tx.txType) 222 } 223 224 return &tx, err 225 } 226 227 // deserializeTx deserializes a transaction 228 func deserializeTx(dec *decoder, tx *txn, txType TxType) error { 229 count, err := dec.readCompactSize() 230 if err != nil { 231 return err 232 } 233 234 if count == 0 { 235 return fmt.Errorf("input count is 0 -- but no segwit transactions for Firo") 236 } 237 238 if count > maxTxInPerMessage { 239 return fmt.Errorf("too many transaction inputs to fit into "+ 240 "max message size [count %d, max %d]", count, maxTxInPerMessage) 241 } 242 243 tx.msgTx.TxIn = make([]*wire.TxIn, count) 244 for i := range tx.msgTx.TxIn { 245 txIn := &wire.TxIn{} 246 err = dec.readTxIn(txIn) 247 if err != nil { 248 return err 249 } 250 tx.msgTx.TxIn[i] = txIn 251 } 252 253 count, err = dec.readCompactSize() 254 if err != nil { 255 return err 256 } 257 if count > maxTxOutPerMessage { 258 return fmt.Errorf("too many transactions outputs to fit into "+ 259 "max message size [count %d, max %d]", count, maxTxOutPerMessage) 260 } 261 262 tx.msgTx.TxOut = make([]*wire.TxOut, count) 263 for i := range tx.msgTx.TxOut { 264 txOut := &wire.TxOut{} 265 err = dec.readTxOut(txOut) 266 if err != nil { 267 return err 268 } 269 tx.msgTx.TxOut[i] = txOut 270 } 271 272 tx.msgTx.LockTime, err = dec.readUint32() 273 if err != nil { 274 return err 275 } 276 277 if txType == TransactionNormal { 278 return nil 279 } 280 281 // read vExtraPayload 282 _, err = dec.readVarBytes() 283 return err 284 } 285 286 // deserializeNonSpendingTx deserializes spork, quorum txs which have no inputs and 287 // no outputs 288 func deserializeNonSpendingTx(dec *decoder, tx *txn, txType TxType) error { 289 count, err := dec.readCompactSize() 290 if err != nil { 291 return err 292 } 293 294 if count != 0 { 295 return fmt.Errorf("tx (type=%d) expected 0 txins - got %d", txType, count) 296 } 297 298 count, err = dec.readCompactSize() 299 if err != nil { 300 return err 301 } 302 303 if count != 0 { 304 return fmt.Errorf("tx (type=%d) expected 0 txouts - got %d", txType, count) 305 } 306 307 tx.msgTx.LockTime, err = dec.readUint32() 308 if err != nil { 309 return err 310 } 311 312 _, err = dec.readVarBytes() 313 return err 314 }