OSDN Git Service

ed5bf03b98acb63f3556526e4df81d66944ae7f1
[bytom/vapor.git] / protocol / vm / numeric_test.go
1 package vm
2
3 import (
4         "fmt"
5         "math"
6         "testing"
7
8         "github.com/vapor/testutil"
9 )
10
11 func TestNumericOps(t *testing.T) {
12         type testStruct struct {
13                 op      Op
14                 startVM *virtualMachine
15                 wantErr error
16                 wantVM  *virtualMachine
17         }
18         cases := []testStruct{{
19                 op: OP_1ADD,
20                 startVM: &virtualMachine{
21                         runLimit:  50000,
22                         dataStack: [][]byte{{2}},
23                 },
24                 wantVM: &virtualMachine{
25                         runLimit:  49998,
26                         dataStack: [][]byte{{3}},
27                 },
28         }, {
29                 op: OP_1SUB,
30                 startVM: &virtualMachine{
31                         runLimit:  50000,
32                         dataStack: [][]byte{{2}},
33                 },
34                 wantVM: &virtualMachine{
35                         runLimit:  49998,
36                         dataStack: [][]byte{{1}},
37                 },
38         }, {
39                 op: OP_2MUL,
40                 startVM: &virtualMachine{
41                         runLimit:  50000,
42                         dataStack: [][]byte{{2}},
43                 },
44                 wantVM: &virtualMachine{
45                         runLimit:  49998,
46                         dataStack: [][]byte{{4}},
47                 },
48         }, {
49                 op: OP_2DIV,
50                 startVM: &virtualMachine{
51                         runLimit:  50000,
52                         dataStack: [][]byte{{2}},
53                 },
54                 wantVM: &virtualMachine{
55                         runLimit:  49998,
56                         dataStack: [][]byte{{1}},
57                 },
58         }, {
59                 op: OP_2DIV,
60                 startVM: &virtualMachine{
61                         runLimit:  50000,
62                         dataStack: [][]byte{Int64Bytes(-2)},
63                 },
64                 wantVM: &virtualMachine{
65                         runLimit:  49998,
66                         dataStack: [][]byte{Int64Bytes(-1)},
67                 },
68         }, {
69                 op: OP_2DIV,
70                 startVM: &virtualMachine{
71                         runLimit:  50000,
72                         dataStack: [][]byte{Int64Bytes(-1)},
73                 },
74                 wantVM: &virtualMachine{
75                         runLimit:  49998,
76                         dataStack: [][]byte{Int64Bytes(-1)},
77                 },
78         }, {
79                 op: OP_NEGATE,
80                 startVM: &virtualMachine{
81                         runLimit:  50000,
82                         dataStack: [][]byte{{2}},
83                 },
84                 wantVM: &virtualMachine{
85                         runLimit:     49998,
86                         deferredCost: 7,
87                         dataStack:    [][]byte{Int64Bytes(-2)},
88                 },
89         }, {
90                 op: OP_ABS,
91                 startVM: &virtualMachine{
92                         runLimit:  50000,
93                         dataStack: [][]byte{{2}},
94                 },
95                 wantVM: &virtualMachine{
96                         runLimit:  49998,
97                         dataStack: [][]byte{{2}},
98                 },
99         }, {
100                 op: OP_ABS,
101                 startVM: &virtualMachine{
102                         runLimit:  50000,
103                         dataStack: [][]byte{Int64Bytes(-2)},
104                 },
105                 wantVM: &virtualMachine{
106                         runLimit:     49998,
107                         deferredCost: -7,
108                         dataStack:    [][]byte{{2}},
109                 },
110         }, {
111                 op: OP_NOT,
112                 startVM: &virtualMachine{
113                         runLimit:  50000,
114                         dataStack: [][]byte{{2}},
115                 },
116                 wantVM: &virtualMachine{
117                         runLimit:     49998,
118                         deferredCost: -1,
119                         dataStack:    [][]byte{{}},
120                 },
121         }, {
122                 op: OP_0NOTEQUAL,
123                 startVM: &virtualMachine{
124                         runLimit:  50000,
125                         dataStack: [][]byte{{2}},
126                 },
127                 wantVM: &virtualMachine{
128                         runLimit:  49998,
129                         dataStack: [][]byte{{1}},
130                 },
131         }, {
132                 op: OP_ADD,
133                 startVM: &virtualMachine{
134                         runLimit:  50000,
135                         dataStack: [][]byte{{2}, {1}},
136                 },
137                 wantVM: &virtualMachine{
138                         runLimit:     49998,
139                         deferredCost: -9,
140                         dataStack:    [][]byte{{3}},
141                 },
142         }, {
143                 op: OP_SUB,
144                 startVM: &virtualMachine{
145                         runLimit:  50000,
146                         dataStack: [][]byte{{2}, {1}},
147                 },
148                 wantVM: &virtualMachine{
149                         runLimit:     49998,
150                         deferredCost: -9,
151                         dataStack:    [][]byte{{1}},
152                 },
153         }, {
154                 op: OP_MUL,
155                 startVM: &virtualMachine{
156                         runLimit:  50000,
157                         dataStack: [][]byte{{2}, {1}},
158                 },
159                 wantVM: &virtualMachine{
160                         runLimit:     49992,
161                         deferredCost: -9,
162                         dataStack:    [][]byte{{2}},
163                 },
164         }, {
165                 op: OP_DIV,
166                 startVM: &virtualMachine{
167                         runLimit:  50000,
168                         dataStack: [][]byte{{2}, {1}},
169                 },
170                 wantVM: &virtualMachine{
171                         runLimit:     49992,
172                         deferredCost: -9,
173                         dataStack:    [][]byte{{2}},
174                 },
175         }, {
176                 op: OP_DIV,
177                 startVM: &virtualMachine{
178                         runLimit:  50000,
179                         dataStack: [][]byte{Int64Bytes(-2), {1}},
180                 },
181                 wantVM: &virtualMachine{
182                         runLimit:     49992,
183                         deferredCost: -9,
184                         dataStack:    [][]byte{Int64Bytes(-2)},
185                 },
186         }, {
187                 op: OP_DIV,
188                 startVM: &virtualMachine{
189                         runLimit:  50000,
190                         dataStack: [][]byte{Int64Bytes(-2), Int64Bytes(-1)},
191                 },
192                 wantVM: &virtualMachine{
193                         runLimit:     49992,
194                         deferredCost: -23,
195                         dataStack:    [][]byte{{2}},
196                 },
197         }, {
198                 op: OP_DIV,
199                 startVM: &virtualMachine{
200                         runLimit:  50000,
201                         dataStack: [][]byte{Int64Bytes(-3), Int64Bytes(2)},
202                 },
203                 wantVM: &virtualMachine{
204                         runLimit:     49992,
205                         deferredCost: -9,
206                         dataStack:    [][]byte{Int64Bytes(-1)},
207                 },
208         }, {
209                 op: OP_DIV,
210                 startVM: &virtualMachine{
211                         runLimit:  50000,
212                         dataStack: [][]byte{{2}, {}},
213                 },
214                 wantErr: ErrDivZero,
215         }, {
216                 op: OP_MOD,
217                 startVM: &virtualMachine{
218                         runLimit:  50000,
219                         dataStack: [][]byte{{2}, {1}},
220                 },
221                 wantVM: &virtualMachine{
222                         runLimit:     49992,
223                         deferredCost: -10,
224                         dataStack:    [][]byte{{}},
225                 },
226         }, {
227                 op: OP_MOD,
228                 startVM: &virtualMachine{
229                         runLimit:  50000,
230                         dataStack: [][]byte{Int64Bytes(-12), {10}},
231                 },
232                 wantVM: &virtualMachine{
233                         runLimit:     49992,
234                         deferredCost: -16,
235                         dataStack:    [][]byte{{8}},
236                 },
237         }, {
238                 op: OP_MOD,
239                 startVM: &virtualMachine{
240                         runLimit:  50000,
241                         dataStack: [][]byte{{2}, {0}},
242                 },
243                 wantErr: ErrDivZero,
244         }, {
245                 op: OP_LSHIFT,
246                 startVM: &virtualMachine{
247                         runLimit:  50000,
248                         dataStack: [][]byte{{2}, {1}},
249                 },
250                 wantVM: &virtualMachine{
251                         runLimit:     49992,
252                         deferredCost: -9,
253                         dataStack:    [][]byte{{4}},
254                 },
255         }, {
256                 op: OP_LSHIFT,
257                 startVM: &virtualMachine{
258                         runLimit:  50000,
259                         dataStack: [][]byte{Int64Bytes(-2), {1}},
260                 },
261                 wantVM: &virtualMachine{
262                         runLimit:     49992,
263                         deferredCost: -9,
264                         dataStack:    [][]byte{Int64Bytes(-4)},
265                 },
266         }, {
267                 op: OP_RSHIFT,
268                 startVM: &virtualMachine{
269                         runLimit:  50000,
270                         dataStack: [][]byte{{2}, {1}},
271                 },
272                 wantVM: &virtualMachine{
273                         runLimit:     49992,
274                         deferredCost: -9,
275                         dataStack:    [][]byte{{1}},
276                 },
277         }, {
278                 op: OP_RSHIFT,
279                 startVM: &virtualMachine{
280                         runLimit:  50000,
281                         dataStack: [][]byte{Int64Bytes(-2), {1}},
282                 },
283                 wantVM: &virtualMachine{
284                         runLimit:     49992,
285                         deferredCost: -9,
286                         dataStack:    [][]byte{Int64Bytes(-1)},
287                 },
288         }, {
289                 op: OP_BOOLAND,
290                 startVM: &virtualMachine{
291                         runLimit:  50000,
292                         dataStack: [][]byte{{2}, {1}},
293                 },
294                 wantVM: &virtualMachine{
295                         runLimit:     49998,
296                         deferredCost: -9,
297                         dataStack:    [][]byte{{1}},
298                 },
299         }, {
300                 op: OP_BOOLOR,
301                 startVM: &virtualMachine{
302                         runLimit:  50000,
303                         dataStack: [][]byte{{2}, {1}},
304                 },
305                 wantVM: &virtualMachine{
306                         runLimit:     49998,
307                         deferredCost: -9,
308                         dataStack:    [][]byte{{1}},
309                 },
310         }, {
311                 op: OP_NUMEQUAL,
312                 startVM: &virtualMachine{
313                         runLimit:  50000,
314                         dataStack: [][]byte{{2}, {1}},
315                 },
316                 wantVM: &virtualMachine{
317                         runLimit:     49998,
318                         deferredCost: -10,
319                         dataStack:    [][]byte{{}},
320                 },
321         }, {
322                 op: OP_NUMEQUALVERIFY,
323                 startVM: &virtualMachine{
324                         runLimit:  50000,
325                         dataStack: [][]byte{{2}, {2}},
326                 },
327                 wantVM: &virtualMachine{
328                         runLimit:     49998,
329                         deferredCost: -18,
330                         dataStack:    [][]byte{},
331                 },
332         }, {
333                 op: OP_NUMEQUALVERIFY,
334                 startVM: &virtualMachine{
335                         runLimit:  50000,
336                         dataStack: [][]byte{{1}, {2}},
337                 },
338                 wantErr: ErrVerifyFailed,
339         }, {
340                 op: OP_NUMNOTEQUAL,
341                 startVM: &virtualMachine{
342                         runLimit:  50000,
343                         dataStack: [][]byte{{2}, {1}},
344                 },
345                 wantVM: &virtualMachine{
346                         runLimit:     49998,
347                         deferredCost: -9,
348                         dataStack:    [][]byte{{1}},
349                 },
350         }, {
351                 op: OP_LESSTHAN,
352                 startVM: &virtualMachine{
353                         runLimit:  50000,
354                         dataStack: [][]byte{{2}, {1}},
355                 },
356                 wantVM: &virtualMachine{
357                         runLimit:     49998,
358                         deferredCost: -10,
359                         dataStack:    [][]byte{{}},
360                 },
361         }, {
362                 op: OP_LESSTHANOREQUAL,
363                 startVM: &virtualMachine{
364                         runLimit:  50000,
365                         dataStack: [][]byte{{2}, {1}},
366                 },
367                 wantVM: &virtualMachine{
368                         runLimit:     49998,
369                         deferredCost: -10,
370                         dataStack:    [][]byte{{}},
371                 },
372         }, {
373                 op: OP_GREATERTHAN,
374                 startVM: &virtualMachine{
375                         runLimit:  50000,
376                         dataStack: [][]byte{{2}, {1}},
377                 },
378                 wantVM: &virtualMachine{
379                         runLimit:     49998,
380                         deferredCost: -9,
381                         dataStack:    [][]byte{{1}},
382                 },
383         }, {
384                 op: OP_GREATERTHANOREQUAL,
385                 startVM: &virtualMachine{
386                         runLimit:  50000,
387                         dataStack: [][]byte{{2}, {1}},
388                 },
389                 wantVM: &virtualMachine{
390                         runLimit:     49998,
391                         deferredCost: -9,
392                         dataStack:    [][]byte{{1}},
393                 },
394         }, {
395                 op: OP_MIN,
396                 startVM: &virtualMachine{
397                         runLimit:  50000,
398                         dataStack: [][]byte{{2}, {1}},
399                 },
400                 wantVM: &virtualMachine{
401                         runLimit:     49998,
402                         deferredCost: -9,
403                         dataStack:    [][]byte{{1}},
404                 },
405         }, {
406                 op: OP_MIN,
407                 startVM: &virtualMachine{
408                         runLimit:  50000,
409                         dataStack: [][]byte{{1}, {2}},
410                 },
411                 wantVM: &virtualMachine{
412                         runLimit:     49998,
413                         deferredCost: -9,
414                         dataStack:    [][]byte{{1}},
415                 },
416         }, {
417                 op: OP_MAX,
418                 startVM: &virtualMachine{
419                         runLimit:  50000,
420                         dataStack: [][]byte{{2}, {1}},
421                 },
422                 wantVM: &virtualMachine{
423                         runLimit:     49998,
424                         deferredCost: -9,
425                         dataStack:    [][]byte{{2}},
426                 },
427         }, {
428                 op: OP_MAX,
429                 startVM: &virtualMachine{
430                         runLimit:  50000,
431                         dataStack: [][]byte{{1}, {2}},
432                 },
433                 wantVM: &virtualMachine{
434                         runLimit:     49998,
435                         deferredCost: -9,
436                         dataStack:    [][]byte{{2}},
437                 },
438         }, {
439                 op: OP_WITHIN,
440                 startVM: &virtualMachine{
441                         runLimit:  50000,
442                         dataStack: [][]byte{{1}, {1}, {2}},
443                 },
444                 wantVM: &virtualMachine{
445                         runLimit:     49996,
446                         deferredCost: -18,
447                         dataStack:    [][]byte{{1}},
448                 },
449         }}
450
451         numops := []Op{
452                 OP_1ADD, OP_1SUB, OP_2MUL, OP_2DIV, OP_NEGATE, OP_ABS, OP_NOT, OP_0NOTEQUAL,
453                 OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, OP_LSHIFT, OP_RSHIFT, OP_BOOLAND,
454                 OP_BOOLOR, OP_NUMEQUAL, OP_NUMEQUALVERIFY, OP_NUMNOTEQUAL, OP_LESSTHAN,
455                 OP_LESSTHANOREQUAL, OP_GREATERTHAN, OP_GREATERTHANOREQUAL, OP_MIN, OP_MAX, OP_WITHIN,
456         }
457
458         for _, op := range numops {
459                 cases = append(cases, testStruct{
460                         op: op,
461                         startVM: &virtualMachine{
462                                 runLimit:  0,
463                                 dataStack: [][]byte{{2}, {2}, {2}},
464                         },
465                         wantErr: ErrRunLimitExceeded,
466                 })
467         }
468
469         for i, c := range cases {
470                 err := ops[c.op].fn(c.startVM)
471
472                 if err != c.wantErr {
473                         t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
474                         continue
475                 }
476                 if c.wantErr != nil {
477                         continue
478                 }
479
480                 if !testutil.DeepEqual(c.startVM, c.wantVM) {
481                         t.Errorf("case %d, op %s: unexpected vm result\n\tgot:  %+v\n\twant: %+v\n", i, ops[c.op].name, c.startVM, c.wantVM)
482                 }
483         }
484 }
485
486 func TestRangeErrs(t *testing.T) {
487         cases := []struct {
488                 prog           string
489                 expectRangeErr bool
490         }{
491                 {"0 1ADD", false},
492                 {fmt.Sprintf("%d 1ADD", int64(math.MinInt64)), false},
493                 {fmt.Sprintf("%d 1ADD", int64(math.MaxInt64)-1), false},
494                 {fmt.Sprintf("%d 1ADD", int64(math.MaxInt64)), true},
495                 {"0 1SUB", false},
496                 {fmt.Sprintf("%d 1SUB", int64(math.MaxInt64)), false},
497                 {fmt.Sprintf("%d 1SUB", int64(math.MinInt64)+1), false},
498                 {fmt.Sprintf("%d 1SUB", int64(math.MinInt64)), true},
499                 {"1 2MUL", false},
500                 {fmt.Sprintf("%d 2MUL", int64(math.MaxInt64)/2-1), false},
501                 {fmt.Sprintf("%d 2MUL", int64(math.MaxInt64)/2+1), true},
502                 {fmt.Sprintf("%d 2MUL", int64(math.MinInt64)/2+1), false},
503                 {fmt.Sprintf("%d 2MUL", int64(math.MinInt64)/2-1), true},
504                 {"1 NEGATE", false},
505                 {"-1 NEGATE", false},
506                 {fmt.Sprintf("%d NEGATE", int64(math.MaxInt64)), false},
507                 {fmt.Sprintf("%d NEGATE", int64(math.MinInt64)), true},
508                 {"1 ABS", false},
509                 {"-1 ABS", false},
510                 {fmt.Sprintf("%d ABS", int64(math.MaxInt64)), false},
511                 {fmt.Sprintf("%d ABS", int64(math.MinInt64)), true},
512                 {"2 3 ADD", false},
513                 {fmt.Sprintf("%d %d ADD", int64(math.MinInt64), int64(math.MaxInt64)), false},
514                 {fmt.Sprintf("%d %d ADD", int64(math.MaxInt64)/2-1, int64(math.MaxInt64)/2-2), false},
515                 {fmt.Sprintf("%d %d ADD", int64(math.MaxInt64)/2+1, int64(math.MaxInt64)/2+2), true},
516                 {fmt.Sprintf("%d %d ADD", int64(math.MinInt64)/2+1, int64(math.MinInt64)/2+2), false},
517                 {fmt.Sprintf("%d %d ADD", int64(math.MinInt64)/2-1, int64(math.MinInt64)/2-2), true},
518                 {"2 3 SUB", false},
519                 {fmt.Sprintf("1 %d SUB", int64(math.MaxInt64)), false},
520                 {fmt.Sprintf("-1 %d SUB", int64(math.MinInt64)), false},
521                 {fmt.Sprintf("1 %d SUB", int64(math.MinInt64)), true},
522                 {fmt.Sprintf("-1 %d SUB", int64(math.MaxInt64)), false},
523                 {fmt.Sprintf("-2 %d SUB", int64(math.MaxInt64)), true},
524                 {"1 2 LSHIFT", false},
525                 {"-1 2 LSHIFT", false},
526                 {"-1 63 LSHIFT", false},
527                 {"-1 64 LSHIFT", true},
528                 {"0 64 LSHIFT", false},
529                 {"1 62 LSHIFT", false},
530                 {"1 63 LSHIFT", true},
531                 {fmt.Sprintf("%d 0 LSHIFT", int64(math.MaxInt64)), false},
532                 {fmt.Sprintf("%d 1 LSHIFT", int64(math.MaxInt64)), true},
533                 {fmt.Sprintf("%d 1 LSHIFT", int64(math.MaxInt64)/2), false},
534                 {fmt.Sprintf("%d 2 LSHIFT", int64(math.MaxInt64)/2), true},
535                 {fmt.Sprintf("%d 0 LSHIFT", int64(math.MinInt64)), false},
536                 {fmt.Sprintf("%d 1 LSHIFT", int64(math.MinInt64)), true},
537                 {fmt.Sprintf("%d 1 LSHIFT", int64(math.MinInt64)/2), false},
538                 {fmt.Sprintf("%d 2 LSHIFT", int64(math.MinInt64)/2), true},
539         }
540
541         for i, c := range cases {
542                 prog, _ := Assemble(c.prog)
543                 vm := &virtualMachine{
544                         program:  prog,
545                         runLimit: 50000,
546                 }
547                 err := vm.run()
548                 switch err {
549                 case nil:
550                         if c.expectRangeErr {
551                                 t.Errorf("case %d (%s): expected range error, got none", i, c.prog)
552                         }
553                 case ErrRange:
554                         if !c.expectRangeErr {
555                                 t.Errorf("case %d (%s): got unexpected range error", i, c.prog)
556                         }
557                 default:
558                         if c.expectRangeErr {
559                                 t.Errorf("case %d (%s): expected range error, got %s", i, c.prog, err)
560                         } else {
561                                 t.Errorf("case %d (%s): got unexpected error %s", i, c.prog, err)
562                         }
563                 }
564         }
565 }