github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/btc/tx.go (about) 1 package btc 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "encoding/binary" 7 "encoding/hex" 8 "errors" 9 "fmt" 10 "io" 11 "sync" 12 ) 13 14 const ( 15 SIGHASH_ALL = 1 16 SIGHASH_NONE = 2 17 SIGHASH_SINGLE = 3 18 SIGHASH_ANYONECANPAY = 0x80 19 20 SIGHASH_DEFAULT = 0 //!< Taproot only; implied when sighash byte is missing, and equivalent to SIGHASH_ALL 21 SIGHASH_OUTPUT_MASK = 3 22 SIGHASH_INPUT_MASK = 0x80 23 ) 24 25 type TxPrevOut struct { 26 Hash [32]byte 27 Vout uint32 28 } 29 30 type TxIn struct { 31 Input TxPrevOut 32 ScriptSig []byte 33 Sequence uint32 34 //PrvOut *TxOut // this field is used only during verification 35 } 36 37 type TxOut struct { 38 Value uint64 39 Pk_script []byte 40 BlockHeight uint32 41 VoutCount uint32 // number of outputs in the transaction that it came from 42 WasCoinbase bool 43 } 44 45 type Tx struct { 46 Version uint32 47 TxIn []*TxIn 48 TxOut []*TxOut 49 SegWit [][][]byte 50 Lock_time uint32 51 52 // These three fields should be set in block.go: 53 Raw []byte 54 Size, NoWitSize uint32 55 Hash Uint256 56 57 // This field is only set in chain's ProcessBlockTransactions: 58 Fee uint64 59 60 wTxID Uint256 61 62 hash_lock sync.Mutex 63 hashPrevouts []byte 64 hashSequence []byte 65 hashOutputs []byte 66 67 Spent_outputs []*TxOut // this is used by TaprootSigHash() 68 m_prevouts_single_hash []byte 69 m_sequences_single_hash []byte 70 m_outputs_single_hash []byte 71 m_spent_amounts_single_hash []byte 72 m_spent_scripts_single_hash []byte 73 } 74 75 type AddrValue struct { 76 Value uint64 77 Addr20 [20]byte 78 } 79 80 func (po *TxPrevOut) UIdx() uint64 { 81 return binary.LittleEndian.Uint64(po.Hash[:8]) ^ uint64(po.Vout) 82 } 83 84 func (to *TxOut) String(testnet bool) (s string) { 85 s = fmt.Sprintf("%.8f BTC", float64(to.Value)/1e8) 86 s += fmt.Sprint(" in block ", to.BlockHeight) 87 a := NewAddrFromPkScript(to.Pk_script, testnet) 88 if a != nil { 89 s += " to " + a.String() 90 } else { 91 s += " pk_scr:" + hex.EncodeToString(to.Pk_script) 92 } 93 return 94 } 95 96 // Non-SegWit format 97 func (t *Tx) WriteSerialized(wr io.Writer) { 98 // Version 99 binary.Write(wr, binary.LittleEndian, t.Version) 100 101 //TxIns 102 WriteVlen(wr, uint64(len(t.TxIn))) 103 for i := range t.TxIn { 104 wr.Write(t.TxIn[i].Input.Hash[:]) 105 binary.Write(wr, binary.LittleEndian, t.TxIn[i].Input.Vout) 106 WriteVlen(wr, uint64(len(t.TxIn[i].ScriptSig))) 107 wr.Write(t.TxIn[i].ScriptSig[:]) 108 binary.Write(wr, binary.LittleEndian, t.TxIn[i].Sequence) 109 } 110 111 //TxOuts 112 WriteVlen(wr, uint64(len(t.TxOut))) 113 for i := range t.TxOut { 114 binary.Write(wr, binary.LittleEndian, t.TxOut[i].Value) 115 WriteVlen(wr, uint64(len(t.TxOut[i].Pk_script))) 116 wr.Write(t.TxOut[i].Pk_script[:]) 117 } 118 119 //Lock_time 120 binary.Write(wr, binary.LittleEndian, t.Lock_time) 121 } 122 123 // Non-SegWit format 124 func (t *Tx) Serialize() []byte { 125 wr := new(bytes.Buffer) 126 t.WriteSerialized(wr) 127 return wr.Bytes() 128 } 129 130 // SignatureHash returns the transaction's hash, that is about to get signed/verified. 131 func (t *Tx) SignatureHash(scriptCode []byte, nIn int, hashType int32) []byte { 132 // Remove any OP_CODESEPARATOR 133 var idx int 134 var nd []byte 135 for idx < len(scriptCode) { 136 op, _, n, e := GetOpcode(scriptCode[idx:]) 137 if e != nil { 138 break 139 } 140 if op != 0xab { 141 nd = append(nd, scriptCode[idx:idx+n]...) 142 } 143 idx += n 144 } 145 scriptCode = nd 146 147 ht := hashType & 0x1f 148 149 sha := sha256.New() 150 151 binary.Write(sha, binary.LittleEndian, uint32(t.Version)) 152 153 if (hashType & SIGHASH_ANYONECANPAY) != 0 { 154 sha.Write([]byte{1}) // only 1 input 155 // The one input: 156 sha.Write(t.TxIn[nIn].Input.Hash[:]) 157 binary.Write(sha, binary.LittleEndian, uint32(t.TxIn[nIn].Input.Vout)) 158 WriteVlen(sha, uint64(len(scriptCode))) 159 sha.Write(scriptCode) 160 binary.Write(sha, binary.LittleEndian, uint32(t.TxIn[nIn].Sequence)) 161 } else { 162 WriteVlen(sha, uint64(len(t.TxIn))) 163 for i := range t.TxIn { 164 sha.Write(t.TxIn[i].Input.Hash[:]) 165 binary.Write(sha, binary.LittleEndian, uint32(t.TxIn[i].Input.Vout)) 166 167 if i == nIn { 168 WriteVlen(sha, uint64(len(scriptCode))) 169 sha.Write(scriptCode) 170 } else { 171 sha.Write([]byte{0}) 172 } 173 174 if (ht == SIGHASH_NONE || ht == SIGHASH_SINGLE) && i != nIn { 175 sha.Write([]byte{0, 0, 0, 0}) 176 } else { 177 binary.Write(sha, binary.LittleEndian, uint32(t.TxIn[i].Sequence)) 178 } 179 } 180 } 181 182 if ht == SIGHASH_NONE { 183 sha.Write([]byte{0}) 184 } else if ht == SIGHASH_SINGLE { 185 nOut := nIn 186 if nOut >= len(t.TxOut) { 187 // Return 1 as the satoshi client (utils.IsOn't ask me why 1, and not something else) 188 return []byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 189 } 190 WriteVlen(sha, uint64(nOut+1)) 191 for i := 0; i < nOut; i++ { 192 sha.Write([]byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0}) 193 } 194 binary.Write(sha, binary.LittleEndian, uint64(t.TxOut[nOut].Value)) 195 WriteVlen(sha, uint64(len(t.TxOut[nOut].Pk_script))) 196 sha.Write(t.TxOut[nOut].Pk_script) 197 } else { 198 WriteVlen(sha, uint64(len(t.TxOut))) 199 for i := range t.TxOut { 200 binary.Write(sha, binary.LittleEndian, uint64(t.TxOut[i].Value)) 201 WriteVlen(sha, uint64(len(t.TxOut[i].Pk_script))) 202 sha.Write(t.TxOut[i].Pk_script) 203 } 204 } 205 206 binary.Write(sha, binary.LittleEndian, t.Lock_time) 207 binary.Write(sha, binary.LittleEndian, hashType) 208 tmp := sha.Sum(nil) 209 sha.Reset() 210 sha.Write(tmp) 211 return sha.Sum(nil) 212 } 213 214 // Sign signs a specified transaction input. 215 func (tx *Tx) Sign(in int, pk_script []byte, hash_type byte, pubkey, priv_key []byte) error { 216 if in >= len(tx.TxIn) { 217 return errors.New("tx.Sign() - input index overflow") 218 } 219 220 //Calculate proper transaction hash 221 h := tx.SignatureHash(pk_script, in, int32(hash_type)) 222 223 // Sign 224 r, s, er := EcdsaSign(priv_key, h) 225 if er != nil { 226 return er 227 } 228 rb := r.Bytes() 229 sb := s.Bytes() 230 231 if rb[0] >= 0x80 { 232 rb = append([]byte{0x00}, rb...) 233 } 234 235 if sb[0] >= 0x80 { 236 sb = append([]byte{0x00}, sb...) 237 } 238 239 // Output the signing result into a buffer, in format expected by bitcoin protocol 240 busig := new(bytes.Buffer) 241 busig.WriteByte(0x30) 242 busig.WriteByte(byte(4 + len(rb) + len(sb))) 243 busig.WriteByte(0x02) 244 busig.WriteByte(byte(len(rb))) 245 busig.Write(rb) 246 busig.WriteByte(0x02) 247 busig.WriteByte(byte(len(sb))) 248 busig.Write(sb) 249 busig.WriteByte(byte(hash_type)) 250 251 // Output the signature and the public key into tx.ScriptSig 252 buscr := new(bytes.Buffer) 253 buscr.WriteByte(byte(busig.Len())) 254 buscr.Write(busig.Bytes()) 255 256 buscr.WriteByte(byte(len(pubkey))) 257 buscr.Write(pubkey) 258 259 // assign sign script ot the tx: 260 tx.TxIn[in].ScriptSig = buscr.Bytes() 261 262 return nil // no error 263 } 264 265 // SignWitness signs a specified transaction input. 266 func (tx *Tx) SignWitness(in int, pk_script []byte, amount uint64, hash_type byte, pubkey, priv_key []byte) error { 267 if in >= len(tx.TxIn) { 268 return errors.New("tx.Sign() - input index overflow") 269 } 270 271 //Calculate proper transaction hash 272 h := tx.WitnessSigHash(pk_script, amount, in, int32(hash_type)) 273 274 // Sign 275 r, s, er := EcdsaSign(priv_key, h) 276 if er != nil { 277 return er 278 } 279 rb := r.Bytes() 280 sb := s.Bytes() 281 282 if rb[0] >= 0x80 { 283 rb = append([]byte{0x00}, rb...) 284 } 285 286 if sb[0] >= 0x80 { 287 sb = append([]byte{0x00}, sb...) 288 } 289 290 // Output the signing result into a buffer, in format expected by bitcoin protocol 291 busig := new(bytes.Buffer) 292 busig.WriteByte(0x30) 293 busig.WriteByte(byte(4 + len(rb) + len(sb))) 294 busig.WriteByte(0x02) 295 busig.WriteByte(byte(len(rb))) 296 busig.Write(rb) 297 busig.WriteByte(0x02) 298 busig.WriteByte(byte(len(sb))) 299 busig.Write(sb) 300 busig.WriteByte(byte(hash_type)) 301 302 if tx.SegWit == nil { 303 tx.SegWit = make([][][]byte, len(tx.TxIn)) 304 } 305 306 tx.SegWit[in] = [][]byte{busig.Bytes(), pubkey} 307 308 return nil // no error 309 } 310 311 func (t *TxPrevOut) String() (s string) { 312 for i := 0; i < 32; i++ { 313 s += fmt.Sprintf("%02x", t.Hash[31-i]) 314 } 315 s += fmt.Sprintf("-%03d", t.Vout) 316 return 317 } 318 319 func (in *TxPrevOut) IsNull() bool { 320 return allzeros(in.Hash[:]) && in.Vout == 0xffffffff 321 } 322 323 func (tx *Tx) IsCoinBase() bool { 324 if len(tx.TxIn) == 1 { 325 inp := tx.TxIn[0].Input 326 if inp.IsNull() { 327 return true 328 } 329 } 330 return false 331 } 332 333 func (tx *Tx) CheckTransaction() error { 334 // Basic checks that utils.IsOn't depend on any context 335 if len(tx.TxIn) == 0 { 336 return errors.New("CheckTransaction() : vin empty - RPC_Result:bad-txns-vin-empty") 337 } 338 if len(tx.TxOut) == 0 { 339 return errors.New("CheckTransaction() : vout empty - RPC_Result:bad-txns-vout-empty") 340 } 341 342 // Size limits 343 if tx.NoWitSize*4 > MAX_BLOCK_WEIGHT { 344 return errors.New("CheckTransaction() : size limits failed - RPC_Result:bad-txns-oversize") 345 } 346 347 if tx.IsCoinBase() { 348 if len(tx.TxIn[0].ScriptSig) < 2 || len(tx.TxIn[0].ScriptSig) > 100 { 349 return errors.New(fmt.Sprintf("CheckTransaction() : coinbase script size %d - RPC_Result:bad-cb-length", 350 len(tx.TxIn[0].ScriptSig))) 351 } 352 } else { 353 for i := range tx.TxIn { 354 if tx.TxIn[i].Input.IsNull() { 355 return errors.New("CheckTransaction() : prevout is null - RPC_Result:bad-txns-prevout-null") 356 } 357 } 358 } 359 360 return nil 361 } 362 363 func (tx *Tx) IsFinal(blockheight, timestamp uint32) bool { 364 if tx.Lock_time == 0 { 365 return true 366 } 367 368 if tx.Lock_time < LOCKTIME_THRESHOLD { 369 if tx.Lock_time < blockheight { 370 return true 371 } 372 } else { 373 if tx.Lock_time < timestamp { 374 return true 375 } 376 } 377 378 for i := range tx.TxIn { 379 if tx.TxIn[i].Sequence != 0xffffffff { 380 return false 381 } 382 } 383 384 return true 385 } 386 387 // NewTxOut decodes a raw transaction output from a given bytes slice. 388 // Returns the output and the size it took in the buffer. 389 func NewTxOut(b []byte) (txout *TxOut, offs int) { 390 var le, n int 391 392 txout = new(TxOut) 393 394 txout.Value = binary.LittleEndian.Uint64(b[0:8]) 395 offs = 8 396 397 le, n = VLen(b[offs:]) 398 if n == 0 { 399 return nil, 0 400 } 401 offs += n 402 403 txout.Pk_script = make([]byte, le) 404 copy(txout.Pk_script[:], b[offs:offs+le]) 405 offs += le 406 407 return 408 } 409 410 // NewTxIn decodes a raw transaction input from a given bytes slice. 411 // Returns the input and the size it took in the buffer. 412 func NewTxIn(b []byte) (txin *TxIn, offs int) { 413 var le, n int 414 415 txin = new(TxIn) 416 417 copy(txin.Input.Hash[:], b[0:32]) 418 txin.Input.Vout = binary.LittleEndian.Uint32(b[32:36]) 419 offs = 36 420 421 le, n = VLen(b[offs:]) 422 if n == 0 { 423 return nil, 0 424 } 425 offs += n 426 427 txin.ScriptSig = make([]byte, le) 428 copy(txin.ScriptSig[:], b[offs:offs+le]) 429 offs += le 430 431 // Sequence 432 txin.Sequence = binary.LittleEndian.Uint32(b[offs : offs+4]) 433 offs += 4 434 435 return 436 } 437 438 // NewTx decodes a raw transaction from a given bytes slice. 439 // Returns the transaction and the size it took in the buffer. 440 // WARNING: This function does not set Tx.Hash, Tx.Size and Tx.Raw 441 func NewTx(b []byte) (tx *Tx, offs int) { 442 defer func() { // In case if the buffer was too short, to recover from a panic 443 if r := recover(); r != nil { 444 println("NewTx failed") 445 tx = nil 446 offs = 0 447 } 448 }() 449 450 var le, n, lel, idx int 451 var segwit bool 452 453 tx = new(Tx) 454 455 tx.Version = binary.LittleEndian.Uint32(b[0:4]) 456 offs = 4 457 458 if b[offs] == 0 && b[offs+1] == 1 { 459 segwit = true // flag is 0x01 460 offs += 2 461 } 462 463 // TxIn 464 le, n = VLen(b[offs:]) 465 if n == 0 { 466 return nil, 0 467 } 468 offs += n 469 tx.TxIn = make([]*TxIn, le) 470 for i := range tx.TxIn { 471 tx.TxIn[i], n = NewTxIn(b[offs:]) 472 offs += n 473 } 474 475 // TxOut 476 le, n = VLen(b[offs:]) 477 if n == 0 { 478 return nil, 0 479 } 480 offs += n 481 tx.TxOut = make([]*TxOut, le) 482 for i := range tx.TxOut { 483 tx.TxOut[i], n = NewTxOut(b[offs:]) 484 offs += n 485 } 486 487 if segwit { 488 tx.SegWit = make([][][]byte, len(tx.TxIn)) 489 for i := range tx.TxIn { 490 le, n = VLen(b[offs:]) 491 if n == 0 { 492 return nil, 0 493 } 494 offs += n 495 tx.SegWit[i] = make([][]byte, le) 496 for idx = 0; idx < le; idx++ { 497 lel, n = VLen(b[offs:]) 498 if n == 0 { 499 return nil, 0 500 } 501 offs += n 502 tx.SegWit[i][idx] = make([]byte, lel) 503 copy(tx.SegWit[i][idx], b[offs:offs+lel]) 504 offs += lel 505 } 506 } 507 } 508 509 tx.Lock_time = binary.LittleEndian.Uint32(b[offs : offs+4]) 510 offs += 4 511 512 return 513 } 514 515 func TxInSize(b []byte) int { 516 le, n := VLen(b[36:]) 517 if n == 0 { 518 return 0 519 } 520 return 36 + n + le + 4 521 } 522 523 func TxOutSize(b []byte) int { 524 le, n := VLen(b[8:]) 525 if n == 0 { 526 return 0 527 } 528 return 8 + n + le 529 } 530 531 func TxSize(b []byte) (offs int) { 532 defer func() { // In case if the buffer was too short, to recover from a panic 533 if r := recover(); r != nil { 534 println("NewSize failed") 535 offs = 0 536 } 537 }() 538 539 var le, txincnt, n, lel int 540 var segwit bool 541 542 offs = 4 // version 543 544 if b[offs] == 0 && b[offs+1] == 1 { 545 segwit = true // flag is 0x01 546 offs += 2 547 } 548 549 // TxIn 550 txincnt, n = VLen(b[offs:]) // in_cnt 551 if n == 0 { 552 return 0 553 } 554 offs += n 555 for le = txincnt; le > 0; le-- { 556 n = TxInSize(b[offs:]) 557 offs += n 558 } 559 560 // TxOut 561 le, n = VLen(b[offs:]) 562 if n == 0 { 563 return 0 564 } 565 offs += n 566 for ; le > 0; le-- { 567 n = TxOutSize(b[offs:]) 568 offs += n 569 } 570 571 if segwit { 572 for ; txincnt > 0; txincnt-- { 573 le, n = VLen(b[offs:]) 574 if n == 0 { 575 return 0 576 } 577 offs += n 578 for ; le > 0; le-- { 579 lel, n = VLen(b[offs:]) 580 if n == 0 { 581 return 0 582 } 583 offs += n + lel 584 } 585 } 586 } 587 588 offs += 4 // Lock_time 589 590 return 591 } 592 593 func (txin *TxIn) GetKeyAndSig() (sig *Signature, key *PublicKey, e error) { 594 sig, e = NewSignature(txin.ScriptSig[1 : 1+txin.ScriptSig[0]]) 595 if e != nil { 596 return 597 } 598 offs := 1 + txin.ScriptSig[0] 599 key, e = NewPublicKey(txin.ScriptSig[1+offs : 1+offs+txin.ScriptSig[offs]]) 600 return 601 } 602 603 func (tx *Tx) GetLegacySigOpCount() (nSigOps uint) { 604 for i := 0; i < len(tx.TxIn); i++ { 605 nSigOps += GetSigOpCount(tx.TxIn[i].ScriptSig, false) 606 } 607 for i := 0; i < len(tx.TxOut); i++ { 608 nSigOps += GetSigOpCount(tx.TxOut[i].Pk_script, false) 609 } 610 return 611 } 612 613 func (tx *Tx) WitnessSigHash(scriptCode []byte, amount uint64, nIn int, hashType int32) []byte { 614 var nullHash [32]byte 615 var hashPrevouts []byte 616 var hashSequence []byte 617 var hashOutputs []byte 618 619 tx.hash_lock.Lock() 620 defer tx.hash_lock.Unlock() 621 622 sha := sha256.New() 623 624 if (hashType & SIGHASH_ANYONECANPAY) == 0 { 625 if tx.hashPrevouts == nil { 626 for _, vin := range tx.TxIn { 627 sha.Write(vin.Input.Hash[:]) 628 binary.Write(sha, binary.LittleEndian, vin.Input.Vout) 629 } 630 hashPrevouts = sha.Sum(nil) 631 sha.Reset() 632 sha.Write(hashPrevouts) 633 tx.hashPrevouts = sha.Sum(nil) 634 sha.Reset() 635 } 636 hashPrevouts = tx.hashPrevouts 637 } else { 638 hashPrevouts = nullHash[:] 639 } 640 641 if (hashType&SIGHASH_ANYONECANPAY) == 0 && (hashType&0x1f) != SIGHASH_SINGLE && (hashType&0x1f) != SIGHASH_NONE { 642 if tx.hashSequence == nil { 643 for _, vin := range tx.TxIn { 644 binary.Write(sha, binary.LittleEndian, vin.Sequence) 645 } 646 hashSequence = sha.Sum(nil) 647 sha.Reset() 648 sha.Write(hashSequence) 649 tx.hashSequence = sha.Sum(nil) 650 sha.Reset() 651 } 652 hashSequence = tx.hashSequence 653 } else { 654 hashSequence = nullHash[:] 655 } 656 657 if (hashType&0x1f) != SIGHASH_SINGLE && (hashType&0x1f) != SIGHASH_NONE { 658 if tx.hashOutputs == nil { 659 for _, vout := range tx.TxOut { 660 binary.Write(sha, binary.LittleEndian, vout.Value) 661 WriteVlen(sha, uint64(len(vout.Pk_script))) 662 sha.Write(vout.Pk_script) 663 } 664 hashOutputs = sha.Sum(nil) 665 sha.Reset() 666 sha.Write(hashOutputs) 667 tx.hashOutputs = sha.Sum(nil) 668 sha.Reset() 669 } 670 hashOutputs = tx.hashOutputs 671 } else if (hashType&0x1f) == SIGHASH_SINGLE && nIn < len(tx.TxOut) { 672 binary.Write(sha, binary.LittleEndian, tx.TxOut[nIn].Value) 673 WriteVlen(sha, uint64(len(tx.TxOut[nIn].Pk_script))) 674 sha.Write(tx.TxOut[nIn].Pk_script) 675 hashOutputs = sha.Sum(nil) 676 sha.Reset() 677 sha.Write(hashOutputs) 678 hashOutputs = sha.Sum(nil) 679 sha.Reset() 680 } else { 681 hashOutputs = nullHash[:] 682 } 683 684 binary.Write(sha, binary.LittleEndian, tx.Version) 685 sha.Write(hashPrevouts) 686 sha.Write(hashSequence) 687 sha.Write(tx.TxIn[nIn].Input.Hash[:]) 688 binary.Write(sha, binary.LittleEndian, tx.TxIn[nIn].Input.Vout) 689 690 WriteVlen(sha, uint64(len(scriptCode))) 691 sha.Write(scriptCode) 692 binary.Write(sha, binary.LittleEndian, amount) 693 binary.Write(sha, binary.LittleEndian, tx.TxIn[nIn].Sequence) 694 sha.Write(hashOutputs) 695 696 binary.Write(sha, binary.LittleEndian, tx.Lock_time) 697 binary.Write(sha, binary.LittleEndian, hashType) 698 699 hashPrevouts = sha.Sum(nil) 700 sha.Reset() 701 sha.Write(hashPrevouts) 702 return sha.Sum(nil) 703 } 704 705 func (tx *Tx) CountWitnessSigOps(inp int, scriptPubKey []byte) uint { 706 scriptSig := tx.TxIn[inp].ScriptSig 707 var witness [][]byte 708 709 if len(tx.SegWit) > inp { 710 witness = tx.SegWit[inp] 711 } 712 713 witnessversion, witnessprogram := IsWitnessProgram(scriptPubKey) 714 if witnessprogram != nil { 715 return WitnessSigOps(witnessversion, witnessprogram, witness) 716 } 717 718 if IsP2SH(scriptPubKey) && IsPushOnly(scriptSig) { 719 var pc, n int 720 var data []byte 721 for pc < len(scriptSig) { 722 _, data, n, _ = GetOpcode(scriptSig[pc:]) 723 pc += n 724 } 725 witnessversion, witnessprogram := IsWitnessProgram(data) 726 if witnessprogram != nil { 727 return WitnessSigOps(witnessversion, witnessprogram, witness) 728 } 729 } 730 731 return 0 732 } 733 734 func (tx *Tx) SetHash(raw []byte) { 735 if raw == nil { 736 raw = tx.Raw 737 } else { 738 tx.Raw = raw 739 } 740 var h [32]byte 741 ShaHash(raw, h[:]) 742 tx.Size = uint32(len(raw)) 743 if tx.SegWit != nil { 744 tx.wTxID.Hash = h 745 nowit_raw := tx.Serialize() 746 tx.Hash.Calc(nowit_raw) 747 tx.NoWitSize = uint32(len(nowit_raw)) 748 } else { 749 tx.Hash.Hash = h 750 tx.NoWitSize = tx.Size 751 } 752 } 753 754 func (t *Tx) WTxID() *Uint256 { 755 if t.SegWit == nil { 756 return &t.Hash 757 } else { 758 return &t.wTxID 759 } 760 } 761 762 func (tx *Tx) Weight() int { 763 return 3*int(tx.NoWitSize) + int(tx.Size) 764 } 765 766 func (tx *Tx) VSize() int { 767 if tx.NoWitSize == tx.Size { 768 return int(tx.Size) 769 } 770 return (3*int(tx.NoWitSize+1) + int(tx.Size)) >> 2 771 } 772 773 // SegWit format 774 func (t *Tx) WriteSerializedNew(wr io.Writer) { 775 if t.SegWit == nil { 776 t.WriteSerialized(wr) 777 return 778 } 779 780 // Version 781 binary.Write(wr, binary.LittleEndian, t.Version) 782 783 // Marker & flag 784 wr.Write([]byte{0x00, 0x01}) 785 786 //TxIns 787 WriteVlen(wr, uint64(len(t.TxIn))) 788 for i := range t.TxIn { 789 wr.Write(t.TxIn[i].Input.Hash[:]) 790 binary.Write(wr, binary.LittleEndian, t.TxIn[i].Input.Vout) 791 WriteVlen(wr, uint64(len(t.TxIn[i].ScriptSig))) 792 wr.Write(t.TxIn[i].ScriptSig[:]) 793 binary.Write(wr, binary.LittleEndian, t.TxIn[i].Sequence) 794 } 795 796 //TxOuts 797 WriteVlen(wr, uint64(len(t.TxOut))) 798 for i := range t.TxOut { 799 binary.Write(wr, binary.LittleEndian, t.TxOut[i].Value) 800 WriteVlen(wr, uint64(len(t.TxOut[i].Pk_script))) 801 wr.Write(t.TxOut[i].Pk_script[:]) 802 } 803 804 // Witness 805 for _, sw := range t.SegWit { 806 WriteVlen(wr, uint64(len(sw))) 807 for _, sws := range sw { 808 WriteVlen(wr, uint64(len(sws))) 809 wr.Write(sws) 810 } 811 } 812 813 //Lock_time 814 binary.Write(wr, binary.LittleEndian, t.Lock_time) 815 } 816 817 // SegWit format 818 func (t *Tx) SerializeNew() []byte { 819 wr := new(bytes.Buffer) 820 t.WriteSerializedNew(wr) 821 return wr.Bytes() 822 } 823 824 // ContainsOrdFile checks if there is a file (inscription) inside the transaction 825 // ... as per github.com/casey/ord 826 // 827 // quick - if set, will not return the scripts (for further decoding) 828 // 829 // return true if inscription found 830 // if quck was not set, also returns all the segwit scripts with the data 831 // returns false, nil if the transaction does not contain any file 832 func (tx *Tx) ContainsOrdFile(quick bool) (yes bool, res [][]byte) { 833 // Browses through all the Inputs and all the witnesses... 834 for _, inp := range tx.SegWit { 835 for _, sw := range inp { 836 if len(sw) > 40 && sw[0] == 0x20 && bytes.Equal(sw[34:40], []byte{0x00, 0x63, 0x03, 0x6f, 0x72, 0x64}) { 837 yes = true 838 if quick { 839 return 840 } 841 res = append(res, sw) 842 } 843 } 844 } 845 return 846 }