OSDN Git Service

add free gas (#295)
[bytom/vapor.git] / protocol / validation / test / tx_ugly_test.go
1 package test
2
3 import (
4         "encoding/hex"
5         "math"
6         "testing"
7
8         "github.com/vapor/account"
9         "github.com/vapor/blockchain/signers"
10         "github.com/vapor/consensus"
11         "github.com/vapor/crypto/ed25519/chainkd"
12         "github.com/vapor/protocol/bc"
13         "github.com/vapor/protocol/bc/types"
14         "github.com/vapor/protocol/validation"
15         "github.com/vapor/protocol/vm/vmutil"
16         "github.com/vapor/testutil"
17 )
18
19 func TestValidateUglyTx(t *testing.T) {
20         singleSignInst := &signingInst{
21                 rootPrvKeys: []string{
22                         "38d2c44314c401b3ea7c23c54e12c36a527aee46a7f26b82443a46bf40583e439dea25de09b0018b35a741d8cd9f6ec06bc11db49762617485f5309ab72a12d4",
23                 },
24                 quorum:           1,
25                 keyIndex:         1,
26                 ctrlProgramIndex: 1,
27                 change:           false,
28         }
29         multiSignInst := &signingInst{
30                 rootPrvKeys: []string{
31                         "a080aca2d9d7948d005c92d0729c618e56fb5551a52dfa04dc4caaf3c8b8a94c89a9795f5bbfd2b885ce7a9d3e3efa5386436c3681b21f9263a0b0a544346b48",
32                         "105295324626e33bb7d8e8a57c6a0aa495346d7fc342a4891ece00424494cf48f75cefa0f8c61674a12238cfa711b4bc26cb22f38b6e2206c691b83943a58312",
33                         "c02bb73d1aee56f8935fb7704f71f668eb37ec223baf5723b38a186669b465427d1bdbc2c4397c1259d12b6229aaf6154aaccdeb8addce3a780a1cbc1025ad25",
34                         "a0c2225685e4c4439f12c264d1573db063ddbc929d4b8a3e1641e8abb4df504a56b1200b9925138d79febe6e1156fcfaf0d1878f25cbccc5db4c8fea55bde198",
35                         "20d06d4fd261ab554e01104f019392f89566acace727e6bb6de4544aa3a6b248480232155332e6e5de10a62e4a9a4c1d9e3b7f9cb4fd196142ef1d080b8bbaec",
36                 },
37                 quorum:           3,
38                 keyIndex:         1,
39                 ctrlProgramIndex: 1,
40                 change:           false,
41         }
42         cases := []struct {
43                 category string
44                 desc     string
45                 insts    []*signingInst
46                 txData   types.TxData
47                 gasValid bool
48                 err      bool
49         }{
50                 {
51                         category: "fee insufficient",
52                         desc:     "sum of btm output greater than btm input",
53                         insts:    []*signingInst{singleSignInst},
54                         txData: types.TxData{
55                                 Version: 1,
56                                 Inputs: []*types.TxInput{
57                                         types.NewSpendInput(nil,
58                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
59                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
60                                 },
61                                 Outputs: []*types.TxOutput{
62                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000001, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
63                                 },
64                         },
65                         err:      true,
66                         gasValid: false,
67                 },
68                 {
69                         category: "normal with no fee",
70                         desc:     "sum of btm output equals to input btm",
71                         insts:    []*signingInst{singleSignInst},
72                         txData: types.TxData{
73                                 Version: 1,
74                                 Inputs: []*types.TxInput{
75                                         types.NewSpendInput(nil,
76                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
77                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
78                                 },
79                                 Outputs: []*types.TxOutput{
80                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
81                                 },
82                         },
83                         err:      false,
84                         gasValid: true,
85                 },
86                 {
87                         category: "fee insufficient",
88                         desc:     "sum of btm input greater than btm output, but still insufficient",
89                         insts:    []*signingInst{singleSignInst},
90                         txData: types.TxData{
91                                 Version: 1,
92                                 Inputs: []*types.TxInput{
93                                         types.NewSpendInput(nil,
94                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
95                                                 *consensus.BTMAssetID, 10000000001, 0, nil),
96                                 },
97                                 Outputs: []*types.TxOutput{
98                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
99                                 },
100                         },
101                         err:      false,
102                         gasValid: true,
103                 },
104                 {
105                         category: "normal with no fee",
106                         desc:     "no btm input",
107                         insts:    []*signingInst{singleSignInst},
108                         txData: types.TxData{
109                                 Version: 1,
110                                 Inputs: []*types.TxInput{
111                                         types.NewSpendInput(nil,
112                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
113                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, nil),
114                                 },
115                                 Outputs: []*types.TxOutput{
116                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
117                                 },
118                         },
119                         err:      false,
120                         gasValid: true,
121                 },
122                 {
123                         category: "input output unbalance",
124                         desc:     "only has btm input, no output",
125                         insts:    []*signingInst{singleSignInst},
126                         txData: types.TxData{
127                                 Version: 1,
128                                 Inputs: []*types.TxInput{
129                                         types.NewSpendInput(nil,
130                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
131                                                 *consensus.BTMAssetID, 10000000001, 0, nil),
132                                 },
133                                 Outputs: []*types.TxOutput{},
134                         },
135                         err:      true,
136                         gasValid: false,
137                 },
138                 {
139                         category: "input output unbalance",
140                         desc:     "spend asset A, no corresponding output",
141                         insts:    []*signingInst{singleSignInst, singleSignInst},
142                         txData: types.TxData{
143                                 Version: 1,
144                                 Inputs: []*types.TxInput{
145                                         types.NewSpendInput(nil,
146                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
147                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
148                                         types.NewSpendInput(nil,
149                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
150                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
151                                 },
152                                 Outputs: []*types.TxOutput{
153                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
154                                 },
155                         },
156                         err:      true,
157                         gasValid: false,
158                 },
159                 {
160                         category: "input output unbalance",
161                         desc:     "spend asset A, output asset B",
162                         insts:    []*signingInst{singleSignInst, singleSignInst},
163                         txData: types.TxData{
164                                 Version: 1,
165                                 Inputs: []*types.TxInput{
166                                         types.NewSpendInput(nil,
167                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
168                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
169                                         types.NewSpendInput(nil,
170                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
171                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
172                                 },
173                                 Outputs: []*types.TxOutput{
174                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
175                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707e"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
176                                 },
177                         },
178                         err:      true,
179                         gasValid: false,
180                 },
181                 {
182                         category: "input output unbalance",
183                         desc:     "sum of output asset A greater than spend asset A",
184                         insts:    []*signingInst{singleSignInst, singleSignInst},
185                         txData: types.TxData{
186                                 Version: 1,
187                                 Inputs: []*types.TxInput{
188                                         types.NewSpendInput(nil,
189                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
190                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
191                                         types.NewSpendInput(nil,
192                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
193                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
194                                 },
195                                 Outputs: []*types.TxOutput{
196                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
197                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
198                                 },
199                         },
200                         err:      true,
201                         gasValid: false,
202                 },
203                 {
204                         category: "input output unbalance",
205                         desc:     "sum of output asset A less than spend asset A",
206                         insts:    []*signingInst{singleSignInst, singleSignInst},
207                         txData: types.TxData{
208                                 Version: 1,
209                                 Inputs: []*types.TxInput{
210                                         types.NewSpendInput(nil,
211                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
212                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
213                                         types.NewSpendInput(nil,
214                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
215                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
216                                 },
217                                 Outputs: []*types.TxOutput{
218                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
219                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
220                                 },
221                         },
222                         err:      true,
223                         gasValid: false,
224                 },
225                 {
226                         category: "input output unbalance",
227                         desc:     "sum of retire asset A greater than spend asset A",
228                         insts:    []*signingInst{singleSignInst, singleSignInst},
229                         txData: types.TxData{
230                                 Version: 1,
231                                 Inputs: []*types.TxInput{
232                                         types.NewSpendInput(nil,
233                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
234                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
235                                         types.NewSpendInput(nil,
236                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
237                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
238                                 },
239                                 Outputs: []*types.TxOutput{
240                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
241                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("6a")),
242                                 },
243                         },
244                         err:      true,
245                         gasValid: false,
246                 },
247                 {
248                         category: "input output unbalance",
249                         desc:     "sum of retire asset A less than spend asset A",
250                         insts:    []*signingInst{singleSignInst, singleSignInst},
251                         txData: types.TxData{
252                                 Version: 1,
253                                 Inputs: []*types.TxInput{
254                                         types.NewSpendInput(nil,
255                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
256                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
257                                         types.NewSpendInput(nil,
258                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
259                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
260                                 },
261                                 Outputs: []*types.TxOutput{
262                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
263                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 5000000000, testutil.MustDecodeHexString("6a")),
264                                 },
265                         },
266                         err:      true,
267                         gasValid: false,
268                 },
269                 {
270                         category: "input output unbalance",
271                         desc:     "use retired utxo",
272                         insts:    []*signingInst{singleSignInst, singleSignInst},
273                         txData: types.TxData{
274                                 Version: 1,
275                                 Inputs: []*types.TxInput{
276                                         types.NewSpendInput(nil,
277                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
278                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("6a")),
279                                 },
280                                 Outputs: []*types.TxOutput{
281                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
282                                 },
283                         },
284                         err:      true,
285                         gasValid: false,
286                 },
287                 {
288                         category: "input output unbalance",
289                         desc:     "no btm input",
290                         txData: types.TxData{
291                                 Version: 1,
292                                 Inputs:  []*types.TxInput{},
293                                 Outputs: []*types.TxOutput{
294                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
295                                 },
296                         },
297                         err:      true,
298                         gasValid: false,
299                 },
300                 {
301                         category: "overflow",
302                         desc:     "spend btm input overflow",
303                         insts:    []*signingInst{singleSignInst, singleSignInst},
304                         txData: types.TxData{
305                                 Version: 1,
306                                 Inputs: []*types.TxInput{
307                                         types.NewSpendInput(nil,
308                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
309                                                 *consensus.BTMAssetID, math.MaxUint64, 0, nil),
310                                         types.NewSpendInput(nil,
311                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
312                                                 *consensus.BTMAssetID, 10000000000, 1, nil),
313                                 },
314                                 Outputs: []*types.TxOutput{
315                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
316                                 },
317                         },
318                         err:      true,
319                         gasValid: false,
320                 },
321                 {
322                         category: "overflow",
323                         desc:     "spend non btm input overflow",
324                         insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
325                         txData: types.TxData{
326                                 Version: 1,
327                                 Inputs: []*types.TxInput{
328                                         types.NewSpendInput(nil,
329                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
330                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), math.MaxInt64, 0, nil),
331                                         types.NewSpendInput(nil,
332                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
333                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, 0, nil),
334                                         types.NewSpendInput(nil,
335                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
336                                                 *consensus.BTMAssetID, 10000000000, 1, nil),
337                                 },
338                                 Outputs: []*types.TxOutput{
339                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
340                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
341                                 },
342                         },
343                         err:      true,
344                         gasValid: false,
345                 },
346                 {
347                         category: "overflow",
348                         desc:     "spend btm output overflow",
349                         insts:    []*signingInst{singleSignInst, singleSignInst},
350                         txData: types.TxData{
351                                 Version: 1,
352                                 Inputs: []*types.TxInput{
353                                         types.NewSpendInput(nil,
354                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
355                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
356                                 },
357                                 Outputs: []*types.TxOutput{
358                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
359                                 },
360                         },
361                         err:      true,
362                         gasValid: false,
363                 },
364                 {
365                         category: "overflow",
366                         desc:     "retire btm output overflow",
367                         insts:    []*signingInst{singleSignInst, singleSignInst},
368                         txData: types.TxData{
369                                 Version: 1,
370                                 Inputs: []*types.TxInput{
371                                         types.NewSpendInput(nil,
372                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
373                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
374                                 },
375                                 Outputs: []*types.TxOutput{
376                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("6a")),
377                                 },
378                         },
379                         err:      true,
380                         gasValid: false,
381                 },
382                 {
383                         category: "overflow",
384                         desc:     "non btm output overflow",
385                         insts:    []*signingInst{singleSignInst, singleSignInst},
386                         txData: types.TxData{
387                                 Version: 1,
388                                 Inputs: []*types.TxInput{
389                                         types.NewSpendInput(nil,
390                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
391                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
392                                         types.NewSpendInput(nil,
393                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
394                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
395                                 },
396                                 Outputs: []*types.TxOutput{
397                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
398                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
399                                 },
400                         },
401                         err:      true,
402                         gasValid: false,
403                 },
404                 {
405                         category: "overflow",
406                         desc:     "retire non btm output overflow",
407                         insts:    []*signingInst{singleSignInst, singleSignInst},
408                         txData: types.TxData{
409                                 Version: 1,
410                                 Inputs: []*types.TxInput{
411                                         types.NewSpendInput(nil,
412                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
413                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
414                                         types.NewSpendInput(nil,
415                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
416                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
417                                 },
418                                 Outputs: []*types.TxOutput{
419                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
420                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("6a")),
421                                 },
422                         },
423                         err:      true,
424                         gasValid: false,
425                 },
426                 {
427                         category: "overflow",
428                         desc:     "output with over range amount but sum in equal",
429                         insts:    []*signingInst{singleSignInst, singleSignInst},
430                         txData: types.TxData{
431                                 Version: 1,
432                                 Inputs: []*types.TxInput{
433                                         types.NewSpendInput(nil,
434                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
435                                                 *consensus.BTMAssetID, 100000000, 0, nil),
436                                 },
437                                 Outputs: []*types.TxOutput{
438                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 18446744073609551616, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
439                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 18446744073609551616, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
440                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 290000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
441                                 },
442                         },
443                         err:      true,
444                         gasValid: false,
445                 },
446                 {
447                         category: "verify signature fail",
448                         desc:     "btm single sign",
449                         insts:    []*signingInst{singleSignInst},
450                         txData: types.TxData{
451                                 Version: 1,
452                                 Inputs: []*types.TxInput{
453                                         types.NewSpendInput(nil,
454                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
455                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
456                                 },
457                                 Outputs: []*types.TxOutput{
458                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
459                                 },
460                         },
461                         err:      true,
462                         gasValid: false,
463                 },
464                 {
465                         category: "verify signature fail",
466                         desc:     "btm multi sign",
467                         insts:    []*signingInst{multiSignInst},
468                         txData: types.TxData{
469                                 Version: 1,
470                                 Inputs: []*types.TxInput{
471                                         types.NewSpendInput(nil,
472                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
473                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("00200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66")), // wrong control program
474                                 },
475                                 Outputs: []*types.TxOutput{
476                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
477                                 },
478                         },
479                         err:      true,
480                         gasValid: false,
481                 },
482                 {
483                         category: "verify signature fail",
484                         desc:     "spend non btm single sign",
485                         insts:    []*signingInst{singleSignInst, singleSignInst},
486                         txData: types.TxData{
487                                 Version: 1,
488                                 Inputs: []*types.TxInput{
489                                         types.NewSpendInput(nil,
490                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
491                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
492                                         types.NewSpendInput(nil,
493                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
494                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
495                                 },
496                                 Outputs: []*types.TxOutput{
497                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
498                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
499                                 },
500                         },
501                         err:      true,
502                         gasValid: true,
503                 },
504                 {
505                         category: "verify signature fail",
506                         desc:     "spend non btm multi sign",
507                         insts:    []*signingInst{singleSignInst, multiSignInst},
508                         txData: types.TxData{
509                                 Version: 1,
510                                 Inputs: []*types.TxInput{
511                                         types.NewSpendInput(nil,
512                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
513                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
514                                         types.NewSpendInput(nil,
515                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
516                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
517                                 },
518                                 Outputs: []*types.TxOutput{
519                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
520                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
521                                 },
522                         },
523                         err:      true,
524                         gasValid: true,
525                 },
526                 {
527                         category: "double spend",
528                         desc:     "btm asset double spend",
529                         insts:    []*signingInst{singleSignInst, singleSignInst},
530                         txData: types.TxData{
531                                 Version: 1,
532                                 Inputs: []*types.TxInput{
533                                         types.NewSpendInput(nil,
534                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
535                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
536                                         types.NewSpendInput(nil,
537                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
538                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
539                                 },
540                                 Outputs: []*types.TxOutput{
541                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 19000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
542                                 },
543                         },
544                         err:      true,
545                         gasValid: false,
546                 },
547                 {
548                         category: "double spend",
549                         desc:     "non btm asset double spend",
550                         insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
551                         txData: types.TxData{
552                                 Version: 1,
553                                 Inputs: []*types.TxInput{
554                                         types.NewSpendInput(nil,
555                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
556                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
557                                         types.NewSpendInput(
558                                                 nil,
559                                                 bc.Hash{V0: 3485387979411255237, V1: 15603105575416882039, V2: 5974145557334619041, V3: 16513948410238218452},
560                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
561                                         types.NewSpendInput(
562                                                 nil,
563                                                 bc.Hash{V0: 3485387979411255237, V1: 15603105575416882039, V2: 5974145557334619041, V3: 16513948410238218452},
564                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
565                                 },
566                                 Outputs: []*types.TxOutput{
567                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
568                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
569                                 },
570                         },
571                         err:      true,
572                         gasValid: false,
573                 },
574         }
575
576         for i, c := range cases {
577                 mockCtrlProgram(c.txData, c.insts)
578
579                 c.txData.SerializedSize = 1
580
581                 tx := types.NewTx(c.txData)
582                 mockSignTx(tx, c.insts)
583                 bcTx := types.MapTx(&c.txData)
584
585                 gasStatus, err := validation.ValidateTx(bcTx, &bc.Block{
586                         BlockHeader:  &bc.BlockHeader{Height: 1},
587                         Transactions: []*bc.Tx{bcTx},
588                 })
589                 if !c.err && err != nil {
590                         t.Errorf("case #%d (%s) expect no error, got error %s", i, c.desc, err)
591                 }
592
593                 if c.err && err == nil {
594                         t.Errorf("case #%d (%s) expect error, got no error", i, c.desc)
595                 }
596
597                 if c.gasValid != gasStatus.GasValid {
598                         t.Errorf("case #%d (%s) got GasValid %t, want %t", i, c.desc, gasStatus.GasValid, c.gasValid)
599                 }
600         }
601 }
602
603 type signingInst struct {
604         rootPrvKeys      []string
605         quorum           int
606         keyIndex         uint64
607         ctrlProgramIndex uint64
608         change           bool
609 }
610
611 func mockCtrlProgram(txData types.TxData, insts []*signingInst) {
612         for i, input := range txData.Inputs {
613                 _, xPubs := mustGetRootKeys(insts[i].rootPrvKeys)
614
615                 switch inp := input.TypedInput.(type) {
616                 case *types.SpendInput:
617                         if inp.ControlProgram != nil {
618                                 continue
619                         }
620                         acc := &account.Account{Signer: &signers.Signer{KeyIndex: insts[i].keyIndex, DeriveRule: signers.BIP0044, XPubs: xPubs, Quorum: insts[i].quorum}}
621                         program, err := account.CreateCtrlProgram(acc, insts[i].ctrlProgramIndex, insts[i].change)
622                         if err != nil {
623                                 panic(err)
624                         }
625                         inp.ControlProgram = program.ControlProgram
626                 }
627         }
628 }
629
630 func mockSignTx(tx *types.Tx, insts []*signingInst) {
631         for i, input := range tx.TxData.Inputs {
632                 if input.Arguments() != nil {
633                         continue
634                 }
635                 var arguments [][]byte
636                 inst := insts[i]
637                 switch inp := input.TypedInput.(type) {
638                 case *types.SpendInput:
639                         path, err := signers.Path(&signers.Signer{KeyIndex: inst.keyIndex, DeriveRule: signers.BIP0044}, signers.AccountKeySpace, inst.change, inst.ctrlProgramIndex)
640                         if err != nil {
641                                 panic(err)
642                         }
643
644                         xPrvs, xPubs := mustGetRootKeys(inst.rootPrvKeys)
645                         for _, xPrv := range xPrvs {
646                                 childPrv := xPrv.Derive(path)
647                                 sigHashBytes := tx.SigHash(uint32(i)).Byte32()
648                                 arguments = append(arguments, childPrv.Sign(sigHashBytes[:]))
649                         }
650
651                         if len(xPrvs) == 1 {
652                                 childPrv := xPrvs[0].Derive(path)
653                                 derivePK := childPrv.XPub()
654                                 arguments = append(arguments, derivePK.PublicKey())
655                         } else {
656                                 derivedXPubs := chainkd.DeriveXPubs(xPubs, path)
657                                 derivedPKs := chainkd.XPubKeys(derivedXPubs)
658                                 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, inst.quorum)
659                                 if err != nil {
660                                         panic(err)
661                                 }
662
663                                 arguments = append(arguments, script)
664                         }
665                         inp.Arguments = arguments
666                 }
667         }
668 }
669
670 func mustGetRootKeys(prvs []string) ([]chainkd.XPrv, []chainkd.XPub) {
671         xPubs := make([]chainkd.XPub, len(prvs))
672         xPrvs := make([]chainkd.XPrv, len(prvs))
673         for i, xPrv := range prvs {
674                 xPrvBytes, err := hex.DecodeString(xPrv)
675                 if err != nil {
676                         panic(err)
677                 }
678
679                 if len(xPrvBytes) != 64 {
680                         panic("the size of xPrv must 64")
681                 }
682
683                 var dest [64]byte
684                 copy(dest[:], xPrv)
685                 xPrvs[i] = chainkd.XPrv(dest)
686                 xPubs[i] = xPrvs[i].XPub()
687         }
688         return xPrvs, xPubs
689 }