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  }