decred.org/dcrdex@v1.0.5/dex/networks/ltc/tx.go (about) 1 package ltc 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "errors" 7 "fmt" 8 "io" 9 10 "github.com/btcsuite/btcd/chaincfg/chainhash" 11 "github.com/btcsuite/btcd/wire" 12 13 "lukechampine.com/blake3" 14 ) 15 16 var byteOrder = binary.LittleEndian 17 18 const ( 19 pver uint32 = 0 // only protocol version 0 supported 20 maxTxInPerMessage = wire.MaxMessagePayload/41 + 1 // wire.maxTxInPerMessage 21 maxTxOutPerMessage = wire.MaxMessagePayload/ // wire.maxTxOutPerMessage 22 wire.MinTxOutPayload + 1 23 maxWitnessItemsPerInput = 4_000_000 // from wire 24 maxWitnessItemSize = 4_000_000 // from wire 25 ) 26 27 type decoder struct { 28 buf [8]byte 29 rd io.Reader 30 tee *bytes.Buffer // anything read from rd is Written to tee 31 } 32 33 func newDecoder(r io.Reader) *decoder { 34 return &decoder{rd: r} 35 } 36 37 func (d *decoder) Read(b []byte) (n int, err error) { 38 n, err = d.rd.Read(b) 39 if err != nil { 40 return 0, err 41 } 42 if d.tee != nil { 43 d.tee.Write(b) 44 } 45 return n, nil 46 } 47 48 func (d *decoder) readByte() (byte, error) { 49 b := d.buf[:1] 50 if _, err := io.ReadFull(d, b); err != nil { 51 return 0, err 52 } 53 return b[0], nil 54 } 55 56 func (d *decoder) readUint16() (uint16, error) { 57 b := d.buf[:2] 58 if _, err := io.ReadFull(d, b); err != nil { 59 return 0, err 60 } 61 return byteOrder.Uint16(b), nil 62 } 63 64 func (d *decoder) readUint32() (uint32, error) { 65 b := d.buf[:4] 66 if _, err := io.ReadFull(d, b); err != nil { 67 return 0, err 68 } 69 return byteOrder.Uint32(b), nil 70 } 71 72 func (d *decoder) readUint64() (uint64, error) { 73 b := d.buf[:] 74 if _, err := io.ReadFull(d, b); err != nil { 75 return 0, err 76 } 77 return byteOrder.Uint64(b), nil 78 } 79 80 // readOutPoint reads the next sequence of bytes from r as an OutPoint. 81 func (d *decoder) readOutPoint(op *wire.OutPoint) error { 82 _, err := io.ReadFull(d, op.Hash[:]) 83 if err != nil { 84 return err 85 } 86 87 op.Index, err = d.readUint32() 88 return err 89 } 90 91 // wire.ReadVarInt a.k.a. CompactSize, not VARINT 92 // https://en.bitcoin.it/wiki/Protocol_documentation#Variable_length_integer 93 func (d *decoder) readCompactSize() (uint64, error) { 94 // Compact Size 95 // size < 253 -- 1 byte 96 // size <= USHRT_MAX -- 3 bytes (253 + 2 bytes) 97 // size <= UINT_MAX -- 5 bytes (254 + 4 bytes) 98 // size > UINT_MAX -- 9 bytes (255 + 8 bytes) 99 chSize, err := d.readByte() 100 if err != nil { 101 return 0, err 102 } 103 switch chSize { 104 case 253: 105 sz, err := d.readUint16() 106 if err != nil { 107 return 0, err 108 } 109 return uint64(sz), nil 110 case 254: 111 sz, err := d.readUint32() 112 if err != nil { 113 return 0, err 114 } 115 return uint64(sz), nil 116 case 255: 117 sz, err := d.readUint64() 118 if err != nil { 119 return 0, err 120 } 121 return sz, nil 122 default: // < 253 123 return uint64(chSize), nil 124 } 125 } 126 127 // variable length quantity, not supposed to be part of the wire protocol. 128 // Not the same as CompactSize type in the C++ code, but rather VARINT. 129 // https://en.wikipedia.org/wiki/Variable-length_quantity 130 // This function is borrowed from dcrd. 131 func (d *decoder) readVLQ() (uint64, error) { 132 var n uint64 133 for { 134 val, err := d.readByte() 135 if err != nil { 136 return 0, err 137 } 138 n = (n << 7) | uint64(val&0x7f) 139 if val&0x80 != 0x80 { 140 break 141 } 142 n++ 143 } 144 145 return n, nil 146 } 147 148 // readTxIn reads the next sequence of bytes from r as a transaction input. 149 func (d *decoder) readTxIn(ti *wire.TxIn) error { 150 err := d.readOutPoint(&ti.PreviousOutPoint) 151 if err != nil { 152 return err 153 } 154 155 ti.SignatureScript, err = wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "sigScript") 156 if err != nil { 157 return err 158 } 159 160 ti.Sequence, err = d.readUint32() 161 return err 162 } 163 164 // readTxOut reads the next sequence of bytes from r as a transaction output. 165 func (d *decoder) readTxOut(to *wire.TxOut) error { 166 v, err := d.readUint64() 167 if err != nil { 168 return err 169 } 170 171 pkScript, err := wire.ReadVarBytes(d, pver, wire.MaxMessagePayload, "pkScript") 172 if err != nil { 173 return err 174 } 175 176 to.Value = int64(v) 177 to.PkScript = pkScript 178 179 return nil 180 } 181 182 func (d *decoder) discardBytes(n int64) error { 183 m, err := io.CopyN(io.Discard, d, n) 184 if err != nil { 185 return err 186 } 187 if m != n { 188 return fmt.Errorf("only discarded %d of %d bytes", m, n) 189 } 190 return nil 191 } 192 193 func (d *decoder) discardVect() error { 194 sz, err := d.readCompactSize() 195 if err != nil { 196 return err 197 } 198 return d.discardBytes(int64(sz)) 199 } 200 201 func (d *decoder) readMWTX() ([]byte, bool, error) { 202 // src/mweb/mweb_models.h - struct Tx 203 // "A convenience wrapper around a possibly-null MWEB transcation." 204 // Read the uint8_t is_set of OptionalPtr. 205 haveMWTX, err := d.readByte() 206 if err != nil { 207 return nil, false, err 208 } 209 if haveMWTX == 0 { 210 return nil, true, nil // HogEx - that's all folks 211 } 212 213 // src/libmw/include/mw/models/tx/Transaction.h - class Transaction 214 // READWRITE(obj.m_kernelOffset); // class BlindingFactor 215 // READWRITE(obj.m_stealthOffset); // class BlindingFactor 216 // READWRITE(obj.m_body); // class TxBody 217 218 // src/libmw/include/mw/models/crypto/BlindingFactor.h - class BlindingFactor 219 // just 32 bytes: 220 // BigInt<32> m_value; 221 // READWRITE(obj.m_value); 222 // x2 for both kernel_offset and stealth_offset BlindingFactor 223 if err = d.discardBytes(64); err != nil { 224 return nil, false, err 225 } 226 227 // TxBody 228 kern0, err := d.readMWTXBody() 229 if err != nil { 230 return nil, false, err 231 } 232 return kern0, false, nil 233 } 234 235 func (d *decoder) readMWTXBody() ([]byte, error) { 236 // src/libmw/include/mw/models/tx/TxBody.h - class TxBody 237 // READWRITE(obj.m_inputs, obj.m_outputs, obj.m_kernels); 238 // std::vector<Input> m_inputs; 239 // std::vector<Output> m_outputs; 240 // std::vector<Kernel> m_kernels; 241 242 // inputs 243 numIn, err := d.readCompactSize() 244 if err != nil { 245 return nil, err 246 } 247 for i := 0; i < int(numIn); i++ { 248 // src/libmw/include/mw/models/tx/Input.h - class Input 249 // - features uint8_t 250 // - outputID mw::Hash - 32 bytes BigInt<32> 251 // - commit Commitment - 33 bytes BigInt<SIZE> for SIZE 33 252 // - outputPubKey PublicKey - 33 bytes BigInt<33> 253 // (if features includes STEALTH_KEY_FEATURE_BIT) input_pubkey PublicKey 254 // (if features includes EXTRA_DATA_FEATURE_BIT) extraData vector<uint8_t> 255 // - signature Signature - 64 bytes BigInt<SIZE> for SIZE 64 256 // 257 // enum FeatureBit { 258 // STEALTH_KEY_FEATURE_BIT = 0x01, 259 // EXTRA_DATA_FEATURE_BIT = 0x02 260 // }; 261 feats, err := d.readByte() 262 if err != nil { 263 return nil, err 264 } 265 if err = d.discardBytes(32 + 33 + 33); err != nil { // outputID, commitment, outputPubKey 266 return nil, err 267 } 268 if feats&0x1 != 0 { // input pubkey 269 if err = d.discardBytes(33); err != nil { 270 return nil, err 271 } 272 } 273 if feats&0x2 != 0 { // extraData 274 if err = d.discardVect(); err != nil { 275 return nil, err 276 } 277 } 278 if err = d.discardBytes(64); err != nil { // sig 279 return nil, err 280 } 281 } // inputs 282 283 // outputs 284 numOut, err := d.readCompactSize() 285 if err != nil { 286 return nil, err 287 } 288 for i := 0; i < int(numOut); i++ { 289 // src/libmw/include/mw/models/tx/Output.h - class Output 290 // commit 291 // sender pubkey 292 // receiver pubkey 293 // message OutputMessage --- fuuuuuuuu 294 // proof RangeProof 295 // signature 296 if err = d.discardBytes(33 + 33 + 33); err != nil { // commitment, sender pk, receiver pk 297 return nil, err 298 } 299 300 // OutputMessage 301 feats, err := d.readByte() 302 if err != nil { 303 return nil, err 304 } 305 // enum FeatureBit { 306 // STANDARD_FIELDS_FEATURE_BIT = 0x01, 307 // EXTRA_DATA_FEATURE_BIT = 0x02 308 // }; 309 if feats&0x1 != 0 { // pubkey | view_tag uint8_t | masked_value uint64_t | nonce 16-bytes 310 if err = d.discardBytes(33 + 1 + 8 + 16); err != nil { 311 return nil, err 312 } 313 } 314 if feats&0x2 != 0 { // extraData 315 if err = d.discardVect(); err != nil { 316 return nil, err 317 } 318 } 319 320 // RangeProof "The proof itself, at most 675 bytes long." 321 // std::vector<uint8_t> m_bytes; -- except it's actually used like a [675]byte... 322 if err = d.discardBytes(675 + 64); err != nil { // proof + sig 323 return nil, err 324 } 325 } // outputs 326 327 // kernels 328 numKerns, err := d.readCompactSize() 329 if err != nil { 330 return nil, err 331 } 332 // Capture the first kernel since pure MW txns (no canonical inputs or 333 // outputs) that live in the MWEB but are also seen in mempool have their 334 // hash computed as blake3_256(kernel0). 335 var kern0 []byte 336 d.tee = new(bytes.Buffer) 337 for i := 0; i < int(numKerns); i++ { 338 // src/libmw/include/mw/models/tx/Kernel.h - class Kernel 339 340 // enum FeatureBit { 341 // FEE_FEATURE_BIT = 0x01, 342 // PEGIN_FEATURE_BIT = 0x02, 343 // PEGOUT_FEATURE_BIT = 0x04, 344 // HEIGHT_LOCK_FEATURE_BIT = 0x08, 345 // STEALTH_EXCESS_FEATURE_BIT = 0x10, 346 // EXTRA_DATA_FEATURE_BIT = 0x20, 347 // ALL_FEATURE_BITS = FEE_FEATURE_BIT | PEGIN... 348 // }; 349 feats, err := d.readByte() 350 if err != nil { 351 return nil, err 352 } 353 if feats&0x1 != 0 { // fee 354 _, err = d.readVLQ() // vlq for amount? in the wire protocol?!? 355 if err != nil { 356 return nil, err 357 } 358 } 359 if feats&0x2 != 0 { // pegin amt 360 _, err = d.readVLQ() 361 if err != nil { 362 return nil, err 363 } 364 } 365 if feats&0x4 != 0 { // pegouts vector 366 sz, err := d.readCompactSize() 367 if err != nil { 368 return nil, err 369 } 370 for i := uint64(0); i < sz; i++ { 371 _, err = d.readVLQ() // pegout amt 372 if err != nil { 373 return nil, err 374 } 375 if err = d.discardVect(); err != nil { // pkScript 376 return nil, err 377 } 378 } 379 } 380 if feats&0x8 != 0 { // lockHeight 381 _, err = d.readVLQ() 382 if err != nil { 383 return nil, err 384 } 385 } 386 if feats&0x10 != 0 { // stealth_excess pubkey 387 if err = d.discardBytes(33); err != nil { 388 return nil, err 389 } 390 } 391 if feats&0x20 != 0 { // extraData vector 392 if err = d.discardVect(); err != nil { 393 return nil, err 394 } 395 } 396 // "excess" commitment and signature 397 if err = d.discardBytes(33 + 64); err != nil { 398 return nil, err 399 } 400 401 if i == 0 { 402 kern0 = d.tee.Bytes() 403 d.tee = nil 404 } 405 } // kernels 406 407 return kern0, nil 408 } 409 410 type Tx struct { 411 *wire.MsgTx 412 IsHogEx bool 413 Kern0 []byte 414 } 415 416 func (tx *Tx) TxHash() chainhash.Hash { 417 // A pure-MW tx can only be in mempool or the EB, not the canonical block. 418 if len(tx.Kern0) > 0 && len(tx.TxIn) == 0 && len(tx.TxOut) == 0 { 419 // CTransaction::ComputeHash in src/primitives/transaction.cpp. 420 // Fortunately also a 32 byte hash so we can use chainhash.Hash. 421 return blake3.Sum256(tx.Kern0) 422 } 423 return tx.MsgTx.TxHash() 424 } 425 426 // DeserializeTx 427 func DeserializeTx(r io.Reader) (*Tx, error) { 428 // mostly taken from wire/msgtx.go 429 msgTx := &wire.MsgTx{} 430 dec := newDecoder(r) 431 432 version, err := dec.readUint32() 433 if err != nil { 434 return nil, err 435 } 436 // if version != 0 { 437 // return nil, fmt.Errorf("only tx version 0 supported, got %d", version) 438 // } 439 msgTx.Version = int32(version) 440 441 count, err := dec.readCompactSize() 442 if err != nil { 443 return nil, err 444 } 445 446 // A count of zero (meaning no TxIn's to the uninitiated) means that the 447 // value is a TxFlagMarker, and hence indicates the presence of a flag. 448 var flag [1]byte 449 if count == 0 { 450 // The count varint was in fact the flag marker byte. Next, we need to 451 // read the flag value, which is a single byte. 452 if _, err = io.ReadFull(r, flag[:]); err != nil { 453 return nil, err 454 } 455 456 // Flag bits 0 or 3 must be set. 457 if flag[0]&0b1001 == 0 { 458 return nil, fmt.Errorf("witness tx but flag byte is %x", flag) 459 } 460 461 // With the Segregated Witness specific fields decoded, we can 462 // now read in the actual txin count. 463 count, err = dec.readCompactSize() 464 if err != nil { 465 return nil, err 466 } 467 } 468 469 if count > maxTxInPerMessage { 470 return nil, fmt.Errorf("too many transaction inputs to fit into "+ 471 "max message size [count %d, max %d]", count, maxTxInPerMessage) 472 } 473 474 msgTx.TxIn = make([]*wire.TxIn, count) 475 for i := range msgTx.TxIn { 476 txIn := &wire.TxIn{} 477 err = dec.readTxIn(txIn) 478 if err != nil { 479 return nil, err 480 } 481 msgTx.TxIn[i] = txIn 482 } 483 484 count, err = dec.readCompactSize() 485 if err != nil { 486 return nil, err 487 } 488 if count > maxTxOutPerMessage { 489 return nil, fmt.Errorf("too many transactions outputs to fit into "+ 490 "max message size [count %d, max %d]", count, maxTxOutPerMessage) 491 } 492 493 msgTx.TxOut = make([]*wire.TxOut, count) 494 for i := range msgTx.TxOut { 495 txOut := &wire.TxOut{} 496 err = dec.readTxOut(txOut) 497 if err != nil { 498 return nil, err 499 } 500 msgTx.TxOut[i] = txOut 501 } 502 503 if flag[0]&0x01 != 0 { 504 for _, txIn := range msgTx.TxIn { 505 witCount, err := dec.readCompactSize() 506 if err != nil { 507 return nil, err 508 } 509 if witCount > maxWitnessItemsPerInput { 510 return nil, fmt.Errorf("too many witness items: %d > max %d", 511 witCount, maxWitnessItemsPerInput) 512 } 513 txIn.Witness = make(wire.TxWitness, witCount) 514 for j := range txIn.Witness { 515 txIn.Witness[j], err = wire.ReadVarBytes(r, pver, 516 maxWitnessItemSize, "script witness item") 517 if err != nil { 518 return nil, err 519 } 520 } 521 } 522 } 523 524 // check for a MW tx based on flag 0x08 525 // src/primitives/transaction.h - class CTransaction 526 // Serialized like normal tx except with an optional MWEB::Tx after outputs 527 // and before locktime. 528 var kern0 []byte 529 var isHogEx bool 530 if flag[0]&0x08 != 0 { 531 kern0, isHogEx, err = dec.readMWTX() 532 if err != nil { 533 return nil, err 534 } 535 if isHogEx && len(msgTx.TxOut) == 0 { 536 return nil, errors.New("no outputs on HogEx txn") 537 } 538 } 539 540 msgTx.LockTime, err = dec.readUint32() 541 if err != nil { 542 return nil, err 543 } 544 545 return &Tx{msgTx, isHogEx, kern0}, nil 546 }