OSDN Git Service

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