OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / protocol / vm / stack_test.go
1 package vm
2
3 import (
4         "fmt"
5         "reflect"
6         "runtime"
7         "strings"
8         "testing"
9
10         "github.com/vapor/testutil"
11 )
12
13 func TestStackOps(t *testing.T) {
14         type testStruct struct {
15                 op      Op
16                 startVM *virtualMachine
17                 wantErr error
18                 wantVM  *virtualMachine
19         }
20
21         cases := []testStruct{{
22                 op: OP_TOALTSTACK,
23                 startVM: &virtualMachine{
24                         runLimit:  50000,
25                         dataStack: [][]byte{{1}},
26                 },
27                 wantVM: &virtualMachine{
28                         runLimit:  49998,
29                         dataStack: [][]byte{},
30                         altStack:  [][]byte{{1}},
31                 },
32         }, {
33                 op: OP_FROMALTSTACK,
34                 startVM: &virtualMachine{
35                         runLimit: 50000,
36                         altStack: [][]byte{{1}},
37                 },
38                 wantVM: &virtualMachine{
39                         runLimit:  49998,
40                         altStack:  [][]byte{},
41                         dataStack: [][]byte{{1}},
42                 },
43         }, {
44                 op: OP_FROMALTSTACK,
45                 startVM: &virtualMachine{
46                         runLimit: 50000,
47                         altStack: [][]byte{},
48                 },
49                 wantErr: ErrAltStackUnderflow,
50         }, {
51                 op: OP_2DROP,
52                 startVM: &virtualMachine{
53                         runLimit:  50000,
54                         dataStack: [][]byte{{1}, {1}},
55                 },
56                 wantVM: &virtualMachine{
57                         runLimit:  50016,
58                         dataStack: [][]byte{},
59                 },
60         }, {
61                 op: OP_2DUP,
62                 startVM: &virtualMachine{
63                         runLimit:  50000,
64                         dataStack: [][]byte{{2}, {1}},
65                 },
66                 wantVM: &virtualMachine{
67                         runLimit:  49980,
68                         dataStack: [][]byte{{2}, {1}, {2}, {1}},
69                 },
70         }, {
71                 op: OP_3DUP,
72                 startVM: &virtualMachine{
73                         runLimit:  50000,
74                         dataStack: [][]byte{{3}, {2}, {1}},
75                 },
76                 wantVM: &virtualMachine{
77                         runLimit:  49970,
78                         dataStack: [][]byte{{3}, {2}, {1}, {3}, {2}, {1}},
79                 },
80         }, {
81                 op: OP_2OVER,
82                 startVM: &virtualMachine{
83                         runLimit:  50000,
84                         dataStack: [][]byte{{4}, {3}, {2}, {1}},
85                 },
86                 wantVM: &virtualMachine{
87                         runLimit:  49980,
88                         dataStack: [][]byte{{4}, {3}, {2}, {1}, {4}, {3}},
89                 },
90         }, {
91                 op: OP_2OVER,
92                 startVM: &virtualMachine{
93                         runLimit:  2,
94                         dataStack: [][]byte{{4}, {3}, {2}, {1}},
95                 },
96                 wantErr: ErrRunLimitExceeded,
97         }, {
98                 op: OP_2ROT,
99                 startVM: &virtualMachine{
100                         runLimit:  50000,
101                         dataStack: [][]byte{{6}, {5}, {4}, {3}, {2}, {1}},
102                 },
103                 wantVM: &virtualMachine{
104                         runLimit:  49998,
105                         dataStack: [][]byte{{4}, {3}, {2}, {1}, {6}, {5}},
106                 },
107         }, {
108                 op: OP_2SWAP,
109                 startVM: &virtualMachine{
110                         runLimit:  50000,
111                         dataStack: [][]byte{{4}, {3}, {2}, {1}},
112                 },
113                 wantVM: &virtualMachine{
114                         runLimit:  49998,
115                         dataStack: [][]byte{{2}, {1}, {4}, {3}},
116                 },
117         }, {
118                 op: OP_IFDUP,
119                 startVM: &virtualMachine{
120                         runLimit:  50000,
121                         dataStack: [][]byte{{1}},
122                 },
123                 wantVM: &virtualMachine{
124                         runLimit:  49990,
125                         dataStack: [][]byte{{1}, {1}},
126                 },
127         }, {
128                 op: OP_IFDUP,
129                 startVM: &virtualMachine{
130                         runLimit:  50000,
131                         dataStack: [][]byte{{}},
132                 },
133                 wantVM: &virtualMachine{
134                         runLimit:  49999,
135                         dataStack: [][]byte{{}},
136                 },
137         }, {
138                 op: OP_IFDUP,
139                 startVM: &virtualMachine{
140                         runLimit:  1,
141                         dataStack: [][]byte{{1}},
142                 },
143                 wantErr: ErrRunLimitExceeded,
144         }, {
145                 op: OP_DEPTH,
146                 startVM: &virtualMachine{
147                         runLimit:  50000,
148                         dataStack: [][]byte{{1}},
149                 },
150                 wantVM: &virtualMachine{
151                         runLimit:  49990,
152                         dataStack: [][]byte{{1}, {1}},
153                 },
154         }, {
155                 op: OP_DEPTH,
156                 startVM: &virtualMachine{
157                         runLimit:  1,
158                         dataStack: [][]byte{{1}},
159                 },
160                 wantErr: ErrRunLimitExceeded,
161         }, {
162                 op: OP_DROP,
163                 startVM: &virtualMachine{
164                         runLimit:  50000,
165                         dataStack: [][]byte{{1}},
166                 },
167                 wantVM: &virtualMachine{
168                         runLimit:  50008,
169                         dataStack: [][]byte{},
170                 },
171         }, {
172                 op: OP_DUP,
173                 startVM: &virtualMachine{
174                         runLimit:  50000,
175                         dataStack: [][]byte{{1}},
176                 },
177                 wantVM: &virtualMachine{
178                         runLimit:  49990,
179                         dataStack: [][]byte{{1}, {1}},
180                 },
181         }, {
182                 op: OP_DUP,
183                 startVM: &virtualMachine{
184                         runLimit:  1,
185                         dataStack: [][]byte{{1}},
186                 },
187                 wantErr: ErrRunLimitExceeded,
188         }, {
189                 op: OP_NIP,
190                 startVM: &virtualMachine{
191                         runLimit:  50000,
192                         dataStack: [][]byte{{2}, {1}},
193                 },
194                 wantVM: &virtualMachine{
195                         runLimit:  50008,
196                         dataStack: [][]byte{{1}},
197                 },
198         }, {
199                 op: OP_OVER,
200                 startVM: &virtualMachine{
201                         runLimit:  50000,
202                         dataStack: [][]byte{{2}, {1}},
203                 },
204                 wantVM: &virtualMachine{
205                         runLimit:  49990,
206                         dataStack: [][]byte{{2}, {1}, {2}},
207                 },
208         }, {
209                 op: OP_OVER,
210                 startVM: &virtualMachine{
211                         runLimit:  1,
212                         dataStack: [][]byte{{2}, {1}},
213                 },
214                 wantErr: ErrRunLimitExceeded,
215         }, {
216                 op: OP_PICK,
217                 startVM: &virtualMachine{
218                         runLimit:  50000,
219                         dataStack: [][]byte{{3}, {2}, {1}, {2}},
220                 },
221                 wantVM: &virtualMachine{
222                         runLimit:  49998,
223                         dataStack: [][]byte{{3}, {2}, {1}, {3}},
224                 },
225         }, {
226                 op: OP_PICK,
227                 startVM: &virtualMachine{
228                         runLimit:  2,
229                         dataStack: [][]byte{{0xff, 0xff}, {2}, {1}, {2}},
230                 },
231                 wantErr: ErrRunLimitExceeded,
232         }, {
233                 op: OP_ROLL,
234                 startVM: &virtualMachine{
235                         runLimit:  50000,
236                         dataStack: [][]byte{{3}, {2}, {1}, {2}},
237                 },
238                 wantVM: &virtualMachine{
239                         runLimit:  50007,
240                         dataStack: [][]byte{{2}, {1}, {3}},
241                 },
242         }, {
243                 op: OP_ROT,
244                 startVM: &virtualMachine{
245                         runLimit:  50000,
246                         dataStack: [][]byte{{3}, {2}, {1}},
247                 },
248                 wantVM: &virtualMachine{
249                         runLimit:  49998,
250                         dataStack: [][]byte{{2}, {1}, {3}},
251                 },
252         }, {
253                 op: OP_SWAP,
254                 startVM: &virtualMachine{
255                         runLimit:  50000,
256                         dataStack: [][]byte{{2}, {1}},
257                 },
258                 wantVM: &virtualMachine{
259                         runLimit:  49999,
260                         dataStack: [][]byte{{1}, {2}},
261                 },
262         }, {
263                 op: OP_TUCK,
264                 startVM: &virtualMachine{
265                         runLimit:  50000,
266                         dataStack: [][]byte{{2}, {1}},
267                 },
268                 wantVM: &virtualMachine{
269                         runLimit:  49990,
270                         dataStack: [][]byte{{1}, {2}, {1}},
271                 },
272         }, {
273                 op: OP_TUCK,
274                 startVM: &virtualMachine{
275                         runLimit:  1,
276                         dataStack: [][]byte{{2}, {1}},
277                 },
278                 wantErr: ErrRunLimitExceeded,
279         }}
280         stackops := []Op{
281                 OP_DEPTH, OP_FROMALTSTACK, OP_TOALTSTACK, OP_2DROP, OP_2DUP, OP_3DUP,
282                 OP_2OVER, OP_2ROT, OP_2SWAP, OP_IFDUP, OP_DROP, OP_DUP, OP_NIP,
283                 OP_OVER, OP_PICK, OP_ROLL, OP_ROT, OP_SWAP, OP_TUCK,
284         }
285         for _, op := range stackops {
286                 cases = append(cases, testStruct{
287                         op:      op,
288                         startVM: &virtualMachine{runLimit: 0},
289                         wantErr: ErrRunLimitExceeded,
290                 })
291         }
292
293         for i, c := range cases {
294                 err := ops[c.op].fn(c.startVM)
295
296                 if err != c.wantErr {
297                         t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
298                         continue
299                 }
300                 if c.wantErr != nil {
301                         continue
302                 }
303
304                 if !testutil.DeepEqual(c.startVM, c.wantVM) {
305                         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)
306                 }
307         }
308 }
309
310 func TestStackUnderflow(t *testing.T) {
311         cases := []struct {
312                 narg int // number of stack items required
313                 op   func(*virtualMachine) error
314         }{
315                 // bitwise
316                 {1, opInvert},
317                 {2, opAnd},
318                 {2, opOr},
319                 {2, opXor},
320                 {2, opEqual},
321                 {2, opEqualVerify},
322
323                 // control
324                 {1, opVerify},
325                 {3, opCheckPredicate},
326                 {1, opJumpIf},
327
328                 // crypto
329                 {1, opSha256},
330                 {1, opSha3},
331                 {3, opCheckSig},
332                 {3, opCheckMultiSig}, // special, see also TestCryptoOps
333
334                 // introspection
335                 {5, opCheckOutput},
336
337                 // numeric
338                 {1, op1Add},
339                 {1, op1Sub},
340                 {1, op2Mul},
341                 {1, op2Div},
342                 {1, opNegate},
343                 {1, opAbs},
344                 {1, opNot},
345                 {1, op0NotEqual},
346                 {2, opAdd},
347                 {2, opSub},
348                 {2, opMul},
349                 {2, opDiv},
350                 {2, opMod},
351                 {2, opLshift},
352                 {2, opRshift},
353                 {2, opBoolAnd},
354                 {2, opBoolOr},
355                 {2, opNumEqual},
356                 {2, opNumEqualVerify},
357                 {2, opNumNotEqual},
358                 {2, opLessThan},
359                 {2, opGreaterThan},
360                 {2, opLessThanOrEqual},
361                 {2, opGreaterThanOrEqual},
362                 {2, opMin},
363                 {2, opMax},
364                 {3, opWithin},
365
366                 // splice
367                 {2, opCat},
368                 {3, opSubstr},
369                 {2, opLeft},
370                 {2, opRight},
371                 {1, opSize},
372                 {2, opCatpushdata},
373
374                 // stack
375                 {1, opToAltStack},
376                 {2, op2Drop},
377                 {2, op2Dup},
378                 {3, op3Dup},
379                 {4, op2Over},
380                 {6, op2Rot},
381                 {4, op2Swap},
382                 {1, opIfDup},
383                 {1, opDrop},
384                 {1, opDup},
385                 {2, opNip},
386                 {2, opOver},
387                 {2, opPick}, // TODO(kr): special; check data-dependent # of pops
388                 {2, opRoll}, // TODO(kr): special; check data-dependent # of pops
389                 {3, opRot},
390                 {2, opSwap},
391                 {2, opTuck},
392         }
393
394         for _, test := range cases {
395                 t.Run(funcName(test.op), func(t *testing.T) {
396
397                         for i := 0; i < test.narg; i++ {
398                                 t.Run(fmt.Sprintf("%d args", i), func(t *testing.T) {
399
400                                         vm := &virtualMachine{
401                                                 runLimit:  50000,
402                                                 dataStack: make([][]byte, i),
403                                         }
404                                         err := test.op(vm)
405                                         if err != ErrDataStackUnderflow {
406                                                 t.Errorf("err = %v, want ErrStackUnderflow", err)
407                                         }
408
409                                 })
410                         }
411
412                 })
413         }
414 }
415
416 func funcName(f interface{}) string {
417         v := reflect.ValueOf(f)
418         if v.Kind() != reflect.Func {
419                 return ""
420         }
421         s := runtime.FuncForPC(v.Pointer()).Name()
422         return s[strings.LastIndex(s, ".")+1:]
423 }