github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/blockchain/txbuilder/finalize.go (about)

     1  package txbuilder
     2  
     3  import (
     4  	"bytes"
     5  	"context"
     6  
     7  	cfg "github.com/bytom/bytom/config"
     8  	"github.com/bytom/bytom/errors"
     9  	"github.com/bytom/bytom/protocol"
    10  	"github.com/bytom/bytom/protocol/bc/types"
    11  	"github.com/bytom/bytom/protocol/vm"
    12  )
    13  
    14  var (
    15  	// ErrRejected means the network rejected a tx (as a double-spend)
    16  	ErrRejected = errors.New("transaction rejected")
    17  	// ErrMissingRawTx means missing transaction
    18  	ErrMissingRawTx = errors.New("missing raw tx")
    19  	// ErrBadInstructionCount means too many signing instructions compare with inputs
    20  	ErrBadInstructionCount = errors.New("too many signing instructions in template")
    21  	// ErrOrphanTx means submit transaction is orphan
    22  	ErrOrphanTx = errors.New("finalize can't find transaction input utxo")
    23  	// ErrExtTxFee means transaction fee exceed max limit
    24  	ErrExtTxFee = errors.New("transaction fee exceed max limit")
    25  	// ErrNoGasInput means transaction has no gas input
    26  	ErrNoGasInput = errors.New("transaction has no gas input")
    27  )
    28  
    29  // FinalizeTx validates a transaction signature template,
    30  // assembles a fully signed tx, and stores the effects of
    31  // its changes on the UTXO set.
    32  func FinalizeTx(ctx context.Context, c *protocol.Chain, tx *types.Tx) error {
    33  	if tx.Fee() > cfg.CommonConfig.Wallet.MaxTxFee {
    34  		return ErrExtTxFee
    35  	}
    36  
    37  	if err := checkTxSighashCommitment(tx); err != nil {
    38  		return err
    39  	}
    40  
    41  	// This part is use for prevent tx size  is 0
    42  	data, err := tx.TxData.MarshalText()
    43  	if err != nil {
    44  		return err
    45  	}
    46  	tx.TxData.SerializedSize = uint64(len(data) / 2)
    47  	tx.Tx.SerializedSize = uint64(len(data) / 2)
    48  
    49  	isOrphan, err := c.ValidateTx(tx)
    50  	if errors.Root(err) == protocol.ErrBadTx {
    51  		return errors.Sub(ErrRejected, err)
    52  	}
    53  	if err != nil {
    54  		return errors.WithDetail(err, "tx rejected: "+err.Error())
    55  	}
    56  	if isOrphan {
    57  		return ErrOrphanTx
    58  	}
    59  	return nil
    60  }
    61  
    62  var (
    63  	// ErrNoTxSighashCommitment is returned when no input commits to the
    64  	// complete transaction.
    65  	// To permit idempotence of transaction submission, we require at
    66  	// least one input to commit to the complete transaction (what you get
    67  	// when you build a transaction with allow_additional_actions=false).
    68  	ErrNoTxSighashCommitment = errors.New("no commitment to tx sighash")
    69  
    70  	// ErrNoTxSighashAttempt is returned when there was no attempt made to sign
    71  	// this transaction.
    72  	ErrNoTxSighashAttempt = errors.New("no tx sighash attempted")
    73  
    74  	// ErrTxSignatureFailure is returned when there was an attempt to sign this
    75  	// transaction, but it failed.
    76  	ErrTxSignatureFailure = errors.New("tx signature was attempted but failed")
    77  )
    78  
    79  func checkTxSighashCommitment(tx *types.Tx) error {
    80  	// TODO: this is the local sender check rules, we might don't need it due to the rule is difference
    81  	return nil
    82  	var lastError error
    83  
    84  	for i, inp := range tx.Inputs {
    85  		var args [][]byte
    86  		switch t := inp.TypedInput.(type) {
    87  		case *types.SpendInput:
    88  			args = t.Arguments
    89  		case *types.IssuanceInput:
    90  			args = t.Arguments
    91  		}
    92  		// Note: These numbers will need to change if more args are added such that the minimum length changes
    93  		switch {
    94  		// A conforming arguments list contains
    95  		// [... arg1 arg2 ... argN N sig1 sig2 ... sigM prog]
    96  		// The args are the opaque arguments to prog. In the case where
    97  		// N is 0 (prog takes no args), and assuming there must be at
    98  		// least one signature, args has a minimum length of 3.
    99  		case len(args) == 0:
   100  			lastError = ErrNoTxSighashAttempt
   101  			continue
   102  		case len(args) < 3:
   103  			lastError = ErrTxSignatureFailure
   104  			continue
   105  		}
   106  		lastError = ErrNoTxSighashCommitment
   107  		prog := args[len(args)-1]
   108  		if len(prog) != 35 {
   109  			continue
   110  		}
   111  		if prog[0] != byte(vm.OP_DATA_32) {
   112  			continue
   113  		}
   114  		if !bytes.Equal(prog[33:], []byte{byte(vm.OP_TXSIGHASH), byte(vm.OP_EQUAL)}) {
   115  			continue
   116  		}
   117  		h := tx.SigHash(uint32(i))
   118  		if !bytes.Equal(h.Bytes(), prog[1:33]) {
   119  			continue
   120  		}
   121  		// At least one input passes commitment checks
   122  		return nil
   123  	}
   124  
   125  	return lastError
   126  }