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 }