OSDN Git Service

Merge pull request #41 from Bytom/dev
[bytom/vapor.git] / protocol / vm / introspection_test.go
1 package vm
2
3 import (
4         "testing"
5
6         "github.com/davecgh/go-spew/spew"
7
8         "github.com/vapor/errors"
9         "github.com/vapor/testutil"
10 )
11
12 func TestOutputIDAndNonceOp(t *testing.T) {
13         // arbitrary
14         outputID := mustDecodeHex("0a60f9b12950c84c221012a808ef7782823b7e16b71fe2ba01811cda96a217df")
15
16         prog := []byte{uint8(OP_OUTPUTID)}
17         vm := &virtualMachine{
18                 runLimit: 50000,
19                 program:  prog,
20                 context:  &Context{SpentOutputID: &outputID},
21         }
22         err := vm.step()
23         if err != nil {
24                 t.Fatal(err)
25         }
26         gotVM := vm
27
28         expectedStack := [][]byte{outputID}
29         if !testutil.DeepEqual(gotVM.dataStack, expectedStack) {
30                 t.Errorf("expected stack %v, got %v; vm is:\n%s", expectedStack, gotVM.dataStack, spew.Sdump(vm))
31         }
32
33         prog = []byte{uint8(OP_OUTPUTID)}
34         vm = &virtualMachine{
35                 runLimit: 50000,
36                 program:  prog,
37                 context:  &Context{SpentOutputID: nil},
38         }
39         err = vm.step()
40         if err != ErrContext {
41                 t.Errorf("expected ErrContext, got %v", err)
42         }
43 }
44
45 func TestBlockHeight(t *testing.T) {
46         var blockHeight uint64 = 6666
47
48         prog, err := Assemble("BLOCKHEIGHT 6666 NUMEQUAL")
49         if err != nil {
50                 t.Fatal(err)
51         }
52         vm := &virtualMachine{
53                 runLimit: 50000,
54                 program:  prog,
55                 context:  &Context{BlockHeight: &blockHeight},
56         }
57         err = vm.run()
58         if err != nil {
59                 t.Errorf("got error %s, expected none", err)
60         }
61         if vm.falseResult() {
62                 t.Error("result is false, want success")
63         }
64
65         prog, err = Assemble("BLOCKHEIGHT 7777 NUMEQUAL")
66         if err != nil {
67                 t.Fatal(err)
68         }
69         vm = &virtualMachine{
70                 runLimit: 50000,
71                 program:  prog,
72                 context:  &Context{BlockHeight: &blockHeight},
73         }
74         err = vm.run()
75         if err == nil && vm.falseResult() {
76                 err = ErrFalseVMResult
77         }
78         switch err {
79         case nil:
80                 t.Error("got ok result, expected failure")
81         case ErrFalseVMResult:
82                 // ok
83         default:
84                 t.Errorf("got error %s, expected ErrFalseVMResult", err)
85         }
86 }
87
88 func TestIntrospectionOps(t *testing.T) {
89         // arbitrary
90         entryID := mustDecodeHex("2e68d78cdeaa98944c12512cf9c719eb4881e9afb61e4b766df5f369aee6392c")
91         assetID := mustDecodeHex("0100000000000000000000000000000000000000000000000000000000000000")
92
93         type testStruct struct {
94                 op      Op
95                 startVM *virtualMachine
96                 wantErr error
97                 wantVM  *virtualMachine
98         }
99         cases := []testStruct{{
100                 op: OP_CHECKOUTPUT,
101                 startVM: &virtualMachine{
102                         dataStack: [][]byte{
103                                 {0},
104                                 {1},
105                                 append([]byte{9}, make([]byte, 31)...),
106                                 {1},
107                                 []byte("missingprog"),
108                         },
109                         context: &Context{
110                                 CheckOutput: func(uint64, uint64, []byte, uint64, []byte, bool) (bool, error) {
111                                         return false, nil
112                                 },
113                         },
114                 },
115                 wantVM: &virtualMachine{
116                         runLimit:     50062,
117                         deferredCost: -78,
118                         dataStack:    [][]byte{{}},
119                 },
120         }, {
121                 op: OP_CHECKOUTPUT,
122                 startVM: &virtualMachine{
123                         dataStack: [][]byte{
124                                 {4},
125                                 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
126                                 {7},
127                                 append([]byte{2}, make([]byte, 31)...),
128                                 Int64Bytes(-1),
129                                 []byte("controlprog"),
130                         },
131                         context: &Context{},
132                 },
133                 wantErr: ErrBadValue,
134         }, {
135                 op: OP_CHECKOUTPUT,
136                 startVM: &virtualMachine{
137                         dataStack: [][]byte{
138                                 {4},
139                                 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
140                                 Int64Bytes(-1),
141                                 append([]byte{2}, make([]byte, 31)...),
142                                 {1},
143                                 []byte("controlprog"),
144                         },
145                         context: &Context{},
146                 },
147                 wantErr: ErrBadValue,
148         }, {
149                 op: OP_CHECKOUTPUT,
150                 startVM: &virtualMachine{
151                         dataStack: [][]byte{
152                                 Int64Bytes(-1),
153                                 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
154                                 {7},
155                                 append([]byte{2}, make([]byte, 31)...),
156                                 {1},
157                                 []byte("controlprog"),
158                         },
159                         context: &Context{},
160                 },
161                 wantErr: ErrBadValue,
162         }, {
163                 op: OP_CHECKOUTPUT,
164                 startVM: &virtualMachine{
165                         dataStack: [][]byte{
166                                 {5},
167                                 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
168                                 {7},
169                                 append([]byte{2}, make([]byte, 31)...),
170                                 {1},
171                                 []byte("controlprog"),
172                         },
173                         context: &Context{
174                                 CheckOutput: func(uint64, uint64, []byte, uint64, []byte, bool) (bool, error) {
175                                         return false, ErrBadValue
176                                 },
177                         },
178                 },
179                 wantErr: ErrBadValue,
180         }, {
181                 op: OP_CHECKOUTPUT,
182                 startVM: &virtualMachine{
183                         runLimit: 0,
184                         dataStack: [][]byte{
185                                 {4},
186                                 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"),
187                                 {7},
188                                 append([]byte{2}, make([]byte, 31)...),
189                                 {1},
190                                 []byte("controlprog"),
191                         },
192                         context: &Context{},
193                 },
194                 wantErr: ErrRunLimitExceeded,
195         }, {
196                 op: OP_ASSET,
197                 startVM: &virtualMachine{
198                         context: &Context{AssetID: &assetID},
199                 },
200                 wantVM: &virtualMachine{
201                         runLimit:     49959,
202                         deferredCost: 40,
203                         dataStack:    [][]byte{assetID},
204                 },
205         }, {
206                 op: OP_AMOUNT,
207                 startVM: &virtualMachine{
208                         context: &Context{Amount: uint64ptr(5)},
209                 },
210                 wantVM: &virtualMachine{
211                         runLimit:     49990,
212                         deferredCost: 9,
213                         dataStack:    [][]byte{{5}},
214                 },
215         }, {
216                 op: OP_PROGRAM,
217                 startVM: &virtualMachine{
218                         program: []byte("spendprog"),
219                         context: &Context{Code: []byte("spendprog")},
220                 },
221                 wantVM: &virtualMachine{
222                         runLimit:     49982,
223                         deferredCost: 17,
224                         dataStack:    [][]byte{[]byte("spendprog")},
225                 },
226         }, {
227                 op: OP_PROGRAM,
228                 startVM: &virtualMachine{
229                         program:  []byte("issueprog"),
230                         runLimit: 50000,
231                         context:  &Context{Code: []byte("issueprog")},
232                 },
233                 wantVM: &virtualMachine{
234                         runLimit:     49982,
235                         deferredCost: 17,
236                         dataStack:    [][]byte{[]byte("issueprog")},
237                 },
238         }, {
239                 op: OP_INDEX,
240                 startVM: &virtualMachine{
241                         context: &Context{DestPos: new(uint64)},
242                 },
243                 wantVM: &virtualMachine{
244                         runLimit:     49991,
245                         deferredCost: 8,
246                         dataStack:    [][]byte{[]byte{}},
247                 },
248         }, {
249                 op: OP_ENTRYID,
250                 startVM: &virtualMachine{
251                         context: &Context{EntryID: entryID},
252                 },
253                 wantVM: &virtualMachine{
254                         runLimit:     49959,
255                         deferredCost: 40,
256                         dataStack:    [][]byte{entryID},
257                 },
258         }}
259
260         txops := []Op{
261                 OP_CHECKOUTPUT, OP_ASSET, OP_AMOUNT, OP_PROGRAM,
262                 OP_INDEX, OP_OUTPUTID,
263         }
264
265         for _, op := range txops {
266                 cases = append(cases, testStruct{
267                         op: op,
268                         startVM: &virtualMachine{
269                                 runLimit: 0,
270                                 context:  &Context{},
271                         },
272                         wantErr: ErrRunLimitExceeded,
273                 })
274         }
275
276         for i, c := range cases {
277                 t.Logf("case %d", i)
278                 prog := []byte{byte(c.op)}
279                 vm := c.startVM
280                 if c.wantErr != ErrRunLimitExceeded {
281                         vm.runLimit = 50000
282                 }
283                 vm.program = prog
284                 err := vm.run()
285                 switch errors.Root(err) {
286                 case c.wantErr:
287                         // ok
288                 case nil:
289                         t.Errorf("case %d, op %s: got no error, want %v", i, ops[c.op].name, c.wantErr)
290                 default:
291                         t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr)
292                 }
293                 if c.wantErr != nil {
294                         continue
295                 }
296                 gotVM := vm
297
298                 c.wantVM.program = prog
299                 c.wantVM.pc = 1
300                 c.wantVM.nextPC = 1
301                 c.wantVM.context = gotVM.context
302
303                 if !testutil.DeepEqual(gotVM, c.wantVM) {
304                         t.Errorf("case %d, op %s: unexpected vm result\n\tgot:  %+v\n\twant: %+v\nstartVM is:\n%s", i, ops[c.op].name, gotVM, c.wantVM, spew.Sdump(c.startVM))
305                 }
306         }
307 }
308
309 func uint64ptr(n uint64) *uint64 { return &n }