OSDN Git Service

724345002287674b65df7bf82d70873457e1ba23
[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: "fee insufficient",
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, 10000000001, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
81                                 },
82                         },
83                         err:      true,
84                         gasValid: false,
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:      true,
102                         gasValid: false,
103                 },
104                 {
105                         category: "fee insufficient",
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:      true,
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:     "input utxo is zero",
290                         insts:    []*signingInst{singleSignInst},
291                         txData: types.TxData{
292                                 Version: 1,
293                                 Inputs: []*types.TxInput{
294                                         types.NewSpendInput(nil,
295                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
296                                                 *consensus.BTMAssetID, 0, 0, nil),
297                                 },
298                                 Outputs: []*types.TxOutput{
299                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 0, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
300                                 },
301                         },
302                         err:      true,
303                         gasValid: false,
304                 },
305                 {
306                         category: "input output unbalance",
307                         desc:     "no btm input",
308                         txData: types.TxData{
309                                 Version: 1,
310                                 Inputs:  []*types.TxInput{},
311                                 Outputs: []*types.TxOutput{
312                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
313                                 },
314                         },
315                         err:      true,
316                         gasValid: false,
317                 },
318                 {
319                         category: "overflow",
320                         desc:     "spend btm input overflow",
321                         insts:    []*signingInst{singleSignInst, singleSignInst},
322                         txData: types.TxData{
323                                 Version: 1,
324                                 Inputs: []*types.TxInput{
325                                         types.NewSpendInput(nil,
326                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
327                                                 *consensus.BTMAssetID, math.MaxUint64, 0, nil),
328                                         types.NewSpendInput(nil,
329                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
330                                                 *consensus.BTMAssetID, 10000000000, 1, nil),
331                                 },
332                                 Outputs: []*types.TxOutput{
333                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
334                                 },
335                         },
336                         err:      true,
337                         gasValid: false,
338                 },
339                 {
340                         category: "overflow",
341                         desc:     "spend non btm input overflow",
342                         insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
343                         txData: types.TxData{
344                                 Version: 1,
345                                 Inputs: []*types.TxInput{
346                                         types.NewSpendInput(nil,
347                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
348                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), math.MaxInt64, 0, nil),
349                                         types.NewSpendInput(nil,
350                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
351                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, 0, nil),
352                                         types.NewSpendInput(nil,
353                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
354                                                 *consensus.BTMAssetID, 10000000000, 1, nil),
355                                 },
356                                 Outputs: []*types.TxOutput{
357                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
358                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 100, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
359                                 },
360                         },
361                         err:      true,
362                         gasValid: false,
363                 },
364                 {
365                         category: "overflow",
366                         desc:     "spend 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("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
377                                 },
378                         },
379                         err:      true,
380                         gasValid: false,
381                 },
382                 {
383                         category: "overflow",
384                         desc:     "retire 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                                 },
393                                 Outputs: []*types.TxOutput{
394                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("6a")),
395                                 },
396                         },
397                         err:      true,
398                         gasValid: false,
399                 },
400                 {
401                         category: "overflow",
402                         desc:     "non btm output overflow",
403                         insts:    []*signingInst{singleSignInst, singleSignInst},
404                         txData: types.TxData{
405                                 Version: 1,
406                                 Inputs: []*types.TxInput{
407                                         types.NewSpendInput(nil,
408                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
409                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
410                                         types.NewSpendInput(nil,
411                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
412                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
413                                 },
414                                 Outputs: []*types.TxOutput{
415                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
416                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
417                                 },
418                         },
419                         err:      true,
420                         gasValid: false,
421                 },
422                 {
423                         category: "overflow",
424                         desc:     "retire non btm output overflow",
425                         insts:    []*signingInst{singleSignInst, singleSignInst},
426                         txData: types.TxData{
427                                 Version: 1,
428                                 Inputs: []*types.TxInput{
429                                         types.NewSpendInput(nil,
430                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
431                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
432                                         types.NewSpendInput(nil,
433                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
434                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, nil),
435                                 },
436                                 Outputs: []*types.TxOutput{
437                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
438                                         types.NewIntraChainOutput(*consensus.BTMAssetID, math.MaxUint64, testutil.MustDecodeHexString("6a")),
439                                 },
440                         },
441                         err:      true,
442                         gasValid: false,
443                 },
444                 {
445                         category: "overflow",
446                         desc:     "output with over range amount but sum in equal",
447                         insts:    []*signingInst{singleSignInst, singleSignInst},
448                         txData: types.TxData{
449                                 Version: 1,
450                                 Inputs: []*types.TxInput{
451                                         types.NewSpendInput(nil,
452                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
453                                                 *consensus.BTMAssetID, 100000000, 0, nil),
454                                 },
455                                 Outputs: []*types.TxOutput{
456                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 18446744073609551616, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
457                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 18446744073609551616, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
458                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 290000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
459                                 },
460                         },
461                         err:      true,
462                         gasValid: false,
463                 },
464                 {
465                         category: "verify signature fail",
466                         desc:     "btm single sign",
467                         insts:    []*signingInst{singleSignInst},
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("00140876db6ca8f4542a836f0edd42b87d095d081182")), // 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:     "btm multi sign",
485                         insts:    []*signingInst{multiSignInst},
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, testutil.MustDecodeHexString("00200824e931fb806bd77fdcd291aad3bd0a4493443a4120062bd659e64a3e0bac66")), // wrong control program
492                                 },
493                                 Outputs: []*types.TxOutput{
494                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
495                                 },
496                         },
497                         err:      true,
498                         gasValid: false,
499                 },
500                 {
501                         category: "verify signature fail",
502                         desc:     "spend non btm single sign",
503                         insts:    []*signingInst{singleSignInst, singleSignInst},
504                         txData: types.TxData{
505                                 Version: 1,
506                                 Inputs: []*types.TxInput{
507                                         types.NewSpendInput(nil,
508                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
509                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
510                                         types.NewSpendInput(nil,
511                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
512                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
513                                 },
514                                 Outputs: []*types.TxOutput{
515                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
516                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
517                                 },
518                         },
519                         err:      true,
520                         gasValid: true,
521                 },
522                 {
523                         category: "verify signature fail",
524                         desc:     "spend non btm multi sign",
525                         insts:    []*signingInst{singleSignInst, multiSignInst},
526                         txData: types.TxData{
527                                 Version: 1,
528                                 Inputs: []*types.TxInput{
529                                         types.NewSpendInput(nil,
530                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
531                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
532                                         types.NewSpendInput(nil,
533                                                 bc.Hash{V0: 6970879411704044573, V1: 10086395903308657573, V2: 10107608596190358115, V3: 8645856247221333302},
534                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 1, testutil.MustDecodeHexString("00140876db6ca8f4542a836f0edd42b87d095d081182")), // wrong control program
535                                 },
536                                 Outputs: []*types.TxOutput{
537                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
538                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
539                                 },
540                         },
541                         err:      true,
542                         gasValid: true,
543                 },
544                 {
545                         category: "double spend",
546                         desc:     "btm asset double spend",
547                         insts:    []*signingInst{singleSignInst, singleSignInst},
548                         txData: types.TxData{
549                                 Version: 1,
550                                 Inputs: []*types.TxInput{
551                                         types.NewSpendInput(nil,
552                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
553                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
554                                         types.NewSpendInput(nil,
555                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
556                                                 *consensus.BTMAssetID, 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
557                                 },
558                                 Outputs: []*types.TxOutput{
559                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 19000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
560                                 },
561                         },
562                         err:      true,
563                         gasValid: true,
564                 },
565                 {
566                         category: "double spend",
567                         desc:     "non btm asset double spend",
568                         insts:    []*signingInst{singleSignInst, singleSignInst, singleSignInst},
569                         txData: types.TxData{
570                                 Version: 1,
571                                 Inputs: []*types.TxInput{
572                                         types.NewSpendInput(nil,
573                                                 bc.Hash{V0: 14760873410800997144, V1: 1698395500822741684, V2: 5965908492734661392, V3: 9445539829830863994},
574                                                 *consensus.BTMAssetID, 10000000000, 0, nil),
575                                         types.NewSpendInput(
576                                                 nil,
577                                                 bc.Hash{V0: 3485387979411255237, V1: 15603105575416882039, V2: 5974145557334619041, V3: 16513948410238218452},
578                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
579                                         types.NewSpendInput(
580                                                 nil,
581                                                 bc.Hash{V0: 3485387979411255237, V1: 15603105575416882039, V2: 5974145557334619041, V3: 16513948410238218452},
582                                                 testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 10000000000, 0, testutil.MustDecodeHexString("001420a1af4fc11399e6cd7253abf1bbd4d0af17daad")),
583                                 },
584                                 Outputs: []*types.TxOutput{
585                                         types.NewIntraChainOutput(*consensus.BTMAssetID, 9000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
586                                         types.NewIntraChainOutput(testutil.MustDecodeAsset("97575084e5161406a0977da729fbf51ad230e0ff0aec607a97e4336611c8707f"), 20000000000, testutil.MustDecodeHexString("00145931e1b7b65897f47845ac08fc136e0c0a4ff166")),
587                                 },
588                         },
589                         err:      true,
590                         gasValid: true,
591                 },
592         }
593
594         for i, c := range cases {
595                 mockCtrlProgram(c.txData, c.insts)
596
597                 c.txData.SerializedSize = 1
598
599                 tx := types.NewTx(c.txData)
600                 mockSignTx(tx, c.insts)
601                 bcTx := types.MapTx(&c.txData)
602
603                 gasStatus, err := validation.ValidateTx(bcTx, &bc.Block{
604                         BlockHeader:  &bc.BlockHeader{Height: 1},
605                         Transactions: []*bc.Tx{bcTx},
606                 })
607                 if !c.err && err != nil {
608                         t.Errorf("case #%d (%s) expect no error, got error %s", i, c.desc, err)
609                 }
610
611                 if c.err && err == nil {
612                         t.Errorf("case #%d (%s) expect error, got no error", i, c.desc)
613                 }
614
615                 if c.gasValid != gasStatus.GasValid {
616                         t.Errorf("case #%d (%s) got GasValid %t, want %t", i, c.desc, gasStatus.GasValid, c.gasValid)
617                 }
618         }
619 }
620
621 type signingInst struct {
622         rootPrvKeys      []string
623         quorum           int
624         keyIndex         uint64
625         ctrlProgramIndex uint64
626         change           bool
627 }
628
629 func mockCtrlProgram(txData types.TxData, insts []*signingInst) {
630         for i, input := range txData.Inputs {
631                 _, xPubs := mustGetRootKeys(insts[i].rootPrvKeys)
632
633                 switch inp := input.TypedInput.(type) {
634                 case *types.SpendInput:
635                         if inp.ControlProgram != nil {
636                                 continue
637                         }
638                         acc := &account.Account{Signer: &signers.Signer{KeyIndex: insts[i].keyIndex, DeriveRule: signers.BIP0044, XPubs: xPubs, Quorum: insts[i].quorum}}
639                         program, err := account.CreateCtrlProgram(acc, insts[i].ctrlProgramIndex, insts[i].change)
640                         if err != nil {
641                                 panic(err)
642                         }
643                         inp.ControlProgram = program.ControlProgram
644                 }
645         }
646 }
647
648 func mockSignTx(tx *types.Tx, insts []*signingInst) {
649         for i, input := range tx.TxData.Inputs {
650                 if input.Arguments() != nil {
651                         continue
652                 }
653                 var arguments [][]byte
654                 inst := insts[i]
655                 switch inp := input.TypedInput.(type) {
656                 case *types.SpendInput:
657                         path, err := signers.Path(&signers.Signer{KeyIndex: inst.keyIndex, DeriveRule: signers.BIP0044}, signers.AccountKeySpace, inst.change, inst.ctrlProgramIndex)
658                         if err != nil {
659                                 panic(err)
660                         }
661
662                         xPrvs, xPubs := mustGetRootKeys(inst.rootPrvKeys)
663                         for _, xPrv := range xPrvs {
664                                 childPrv := xPrv.Derive(path)
665                                 sigHashBytes := tx.SigHash(uint32(i)).Byte32()
666                                 arguments = append(arguments, childPrv.Sign(sigHashBytes[:]))
667                         }
668
669                         if len(xPrvs) == 1 {
670                                 childPrv := xPrvs[0].Derive(path)
671                                 derivePK := childPrv.XPub()
672                                 arguments = append(arguments, derivePK.PublicKey())
673                         } else {
674                                 derivedXPubs := chainkd.DeriveXPubs(xPubs, path)
675                                 derivedPKs := chainkd.XPubKeys(derivedXPubs)
676                                 script, err := vmutil.P2SPMultiSigProgram(derivedPKs, inst.quorum)
677                                 if err != nil {
678                                         panic(err)
679                                 }
680
681                                 arguments = append(arguments, script)
682                         }
683                         inp.Arguments = arguments
684                 }
685         }
686 }
687
688 func mustGetRootKeys(prvs []string) ([]chainkd.XPrv, []chainkd.XPub) {
689         xPubs := make([]chainkd.XPub, len(prvs))
690         xPrvs := make([]chainkd.XPrv, len(prvs))
691         for i, xPrv := range prvs {
692                 xPrvBytes, err := hex.DecodeString(xPrv)
693                 if err != nil {
694                         panic(err)
695                 }
696
697                 if len(xPrvBytes) != 64 {
698                         panic("the size of xPrv must 64")
699                 }
700
701                 var dest [64]byte
702                 copy(dest[:], xPrv)
703                 xPrvs[i] = chainkd.XPrv(dest)
704                 xPubs[i] = xPrvs[i].XPub()
705         }
706         return xPrvs, xPubs
707 }