OSDN Git Service

4e8c2b6ff6d6082fc15f3042da9c6673d4f061b6
[bytom/vapor.git] / protocol / vm / ops_test.go
1 package vm
2
3 import (
4         "fmt"
5         "reflect"
6         "testing"
7
8         "github.com/vapor/errors"
9         "github.com/vapor/math/checked"
10         "github.com/vapor/testutil"
11 )
12
13 func TestParseOp(t *testing.T) {
14         cases := []struct {
15                 prog    []byte
16                 pc      uint32
17                 want    Instruction
18                 wantErr error
19         }{{
20                 prog: []byte{byte(OP_ADD)},
21                 want: Instruction{Op: OP_ADD, Len: 1},
22         }, {
23                 prog: []byte{byte(OP_16)},
24                 want: Instruction{Op: OP_16, Data: []byte{16}, Len: 1},
25         }, {
26                 prog: []byte{byte(OP_DATA_5), 1, 1, 1, 1, 1},
27                 want: Instruction{Op: OP_DATA_5, Data: []byte{1, 1, 1, 1, 1}, Len: 6},
28         }, {
29                 prog: []byte{byte(OP_DATA_5), 1, 1, 1, 1, 1, 255},
30                 want: Instruction{Op: OP_DATA_5, Data: []byte{1, 1, 1, 1, 1}, Len: 6},
31         }, {
32                 prog: []byte{byte(OP_PUSHDATA1), 1, 1},
33                 want: Instruction{Op: OP_PUSHDATA1, Data: []byte{1}, Len: 3},
34         }, {
35                 prog: []byte{byte(OP_PUSHDATA1), 1, 1, 255},
36                 want: Instruction{Op: OP_PUSHDATA1, Data: []byte{1}, Len: 3},
37         }, {
38                 prog: []byte{byte(OP_PUSHDATA2), 1, 0, 1},
39                 want: Instruction{Op: OP_PUSHDATA2, Data: []byte{1}, Len: 4},
40         }, {
41                 prog: []byte{byte(OP_PUSHDATA2), 1, 0, 1, 255},
42                 want: Instruction{Op: OP_PUSHDATA2, Data: []byte{1}, Len: 4},
43         }, {
44                 prog: []byte{byte(OP_PUSHDATA4), 1, 0, 0, 0, 1},
45                 want: Instruction{Op: OP_PUSHDATA4, Data: []byte{1}, Len: 6},
46         }, {
47                 prog: []byte{byte(OP_PUSHDATA4), 1, 0, 0, 0, 1, 255},
48                 want: Instruction{Op: OP_PUSHDATA4, Data: []byte{1}, Len: 6},
49         }, {
50                 prog:    []byte{},
51                 wantErr: ErrShortProgram,
52         }, {
53                 prog:    []byte{byte(OP_0)},
54                 pc:      1,
55                 wantErr: ErrShortProgram,
56         }, {
57                 prog:    []byte{byte(OP_DATA_1)},
58                 wantErr: ErrShortProgram,
59         }, {
60                 prog:    []byte{byte(OP_PUSHDATA1)},
61                 wantErr: ErrShortProgram,
62         }, {
63                 prog:    []byte{byte(OP_PUSHDATA1), 1},
64                 wantErr: ErrShortProgram,
65         }, {
66                 prog:    []byte{byte(OP_PUSHDATA2)},
67                 wantErr: ErrShortProgram,
68         }, {
69                 prog:    []byte{byte(OP_PUSHDATA2), 1, 0},
70                 wantErr: ErrShortProgram,
71         }, {
72                 prog:    []byte{byte(OP_PUSHDATA4)},
73                 wantErr: ErrShortProgram,
74         }, {
75                 prog:    []byte{byte(OP_PUSHDATA4), 1, 0, 0, 0},
76                 wantErr: ErrShortProgram,
77         }, {
78                 pc:      71,
79                 prog:    []byte{0x6d, 0x6b, 0xaa, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x20, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x0, 0x0, 0x4e, 0xff, 0xff, 0xff, 0xff, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30},
80                 wantErr: checked.ErrOverflow,
81         }}
82
83         for _, c := range cases {
84                 t.Run(fmt.Sprintf("%d: %x", c.pc, c.prog), func(t *testing.T) {
85                         got, gotErr := ParseOp(c.prog, c.pc)
86
87                         if errors.Root(gotErr) != c.wantErr {
88                                 t.Errorf("ParseOp(%x, %d) error = %v want %v", c.prog, c.pc, gotErr, c.wantErr)
89                         }
90
91                         if c.wantErr != nil {
92                                 return
93                         }
94
95                         if !testutil.DeepEqual(got, c.want) {
96                                 t.Errorf("ParseOp(%x, %d) = %+v want %+v", c.prog, c.pc, got, c.want)
97                         }
98                 })
99         }
100 }
101
102 func TestParseProgram(t *testing.T) {
103         cases := []struct {
104                 prog    []byte
105                 want    []Instruction
106                 wantErr error
107         }{
108                 {
109                         prog: []byte{byte(OP_2), byte(OP_3), byte(OP_ADD), byte(OP_5), byte(OP_NUMEQUAL)},
110                         want: []Instruction{
111                                 {Op: OP_2, Data: []byte{0x02}, Len: 1},
112                                 {Op: OP_3, Data: []byte{0x03}, Len: 1},
113                                 {Op: OP_ADD, Len: 1},
114                                 {Op: OP_5, Data: []byte{0x05}, Len: 1},
115                                 {Op: OP_NUMEQUAL, Len: 1},
116                         },
117                 },
118                 {
119                         prog: []byte{255},
120                         want: []Instruction{
121                                 {Op: 255, Len: 1},
122                         },
123                 },
124         }
125
126         for _, c := range cases {
127                 got, gotErr := ParseProgram(c.prog)
128
129                 if errors.Root(gotErr) != c.wantErr {
130                         t.Errorf("ParseProgram(%x) error = %v want %v", c.prog, gotErr, c.wantErr)
131                 }
132
133                 if c.wantErr != nil {
134                         continue
135                 }
136
137                 if !testutil.DeepEqual(got, c.want) {
138                         t.Errorf("ParseProgram(%x) = %+v want %+v", c.prog, got, c.want)
139                 }
140         }
141 }
142
143 func TestIsPushData(t *testing.T) {
144         cases := []struct {
145                 want    Instruction
146                 wantErr error
147         }{
148                 {
149                         want: Instruction{Op: OP_16, Data: []byte{16}, Len: 1},
150                 },
151                 {
152                         want: Instruction{Op: OP_DATA_32, Data: []byte{16}, Len: 1},
153                 },
154                 {
155                         want: Instruction{Op: OP_FALSE, Data: []byte{}, Len: 1},
156                 },
157                 {
158                         want: Instruction{Op: OP_TRUE, Data: []byte{1}, Len: 1},
159                 },
160                 {
161                         want:    Instruction{Op: OP_JUMP, Data: []byte{0x00000000}, Len: 1},
162                         wantErr: ErrShortProgram,
163                 },
164                 {
165                         want:    Instruction{Op: OP_ADD, Data: []byte{0x12, 0x56}, Len: 2},
166                         wantErr: ErrShortProgram,
167                 },
168         }
169
170         for _, c := range cases {
171                 if c.want.IsPushdata() {
172                         t.Logf("check success")
173                 } else if c.wantErr != nil {
174                         t.Logf("check err success")
175                 } else {
176                         t.Errorf("check false: %v -- %v", reflect.ValueOf(ops[OP_1].fn), reflect.ValueOf(ops[c.want.Op].fn))
177                 }
178         }
179 }