github.com/Bytom/bytom@v1.1.2-0.20210127130405-ae40204c0b09/protocol/vm/introspection_test.go (about) 1 package vm 2 3 import ( 4 "testing" 5 6 "github.com/davecgh/go-spew/spew" 7 8 "github.com/bytom/bytom/errors" 9 "github.com/bytom/bytom/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 }