OSDN Git Service

270bb3b8b146a1d61e84f15e0c66ce8740aa8e3b
[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 err != nil {
59                 if errors.Root(err) == err {
60                         return errors.Sub(ErrRejected, err)
61                 }
62                 return err
63         }
64
65         if isOrphan {
66                 return ErrOrphanTx
67         }
68         return nil
69 }
70
71 var (
72         // ErrNoTxSighashCommitment is returned when no input commits to the
73         // complete transaction.
74         // To permit idempotence of transaction submission, we require at
75         // least one input to commit to the complete transaction (what you get
76         // when you build a transaction with allow_additional_actions=false).
77         ErrNoTxSighashCommitment = errors.New("no commitment to tx sighash")
78
79         // ErrNoTxSighashAttempt is returned when there was no attempt made to sign
80         // this transaction.
81         ErrNoTxSighashAttempt = errors.New("no tx sighash attempted")
82
83         // ErrTxSignatureFailure is returned when there was an attempt to sign this
84         // transaction, but it failed.
85         ErrTxSignatureFailure = errors.New("tx signature was attempted but failed")
86 )
87
88 func checkTxSighashCommitment(tx *types.Tx) error {
89         // TODO: this is the local sender check rules, we might don't need it due to the rule is difference
90         return nil
91         var lastError error
92
93         for i, inp := range tx.Inputs {
94                 var args [][]byte
95                 switch t := inp.TypedInput.(type) {
96                 case *types.SpendInput:
97                         args = t.Arguments
98                 }
99                 // Note: These numbers will need to change if more args are added such that the minimum length changes
100                 switch {
101                 // A conforming arguments list contains
102                 // [... arg1 arg2 ... argN N sig1 sig2 ... sigM prog]
103                 // The args are the opaque arguments to prog. In the case where
104                 // N is 0 (prog takes no args), and assuming there must be at
105                 // least one signature, args has a minimum length of 3.
106                 case len(args) == 0:
107                         lastError = ErrNoTxSighashAttempt
108                         continue
109                 case len(args) < 3:
110                         lastError = ErrTxSignatureFailure
111                         continue
112                 }
113                 lastError = ErrNoTxSighashCommitment
114                 prog := args[len(args)-1]
115                 if len(prog) != 35 {
116                         continue
117                 }
118                 if prog[0] != byte(vm.OP_DATA_32) {
119                         continue
120                 }
121                 if !bytes.Equal(prog[33:], []byte{byte(vm.OP_TXSIGHASH), byte(vm.OP_EQUAL)}) {
122                         continue
123                 }
124                 h := tx.SigHash(uint32(i))
125                 if !bytes.Equal(h.Bytes(), prog[1:33]) {
126                         continue
127                 }
128                 // At least one input passes commitment checks
129                 return nil
130         }
131
132         return lastError
133 }
134
135 func checkGasInputIDs(tx *types.Tx) error {
136         for _, inp := range tx.Inputs {
137                 switch inp.InputType() {
138                 case types.CrossChainInputType:
139                         return nil
140                 }
141         }
142
143         if len(tx.GasInputIDs) == 0 {
144                 return ErrNoGasInput
145         }
146         return nil
147 }