OSDN Git Service

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