github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/protocol/vm/stack_test.go (about) 1 package vm 2 3 import ( 4 "fmt" 5 "reflect" 6 "runtime" 7 "strings" 8 "testing" 9 10 "github.com/bytom/bytom/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, opNot}, 343 {1, op0NotEqual}, 344 {2, opAdd}, 345 {2, opSub}, 346 {2, opMul}, 347 {2, opDiv}, 348 {2, opMod}, 349 {2, opLshift}, 350 {2, opRshift}, 351 {2, opBoolAnd}, 352 {2, opBoolOr}, 353 {2, opNumEqual}, 354 {2, opNumEqualVerify}, 355 {2, opNumNotEqual}, 356 {2, opLessThan}, 357 {2, opGreaterThan}, 358 {2, opLessThanOrEqual}, 359 {2, opGreaterThanOrEqual}, 360 {2, opMin}, 361 {2, opMax}, 362 {3, opWithin}, 363 364 // splice 365 {2, opCat}, 366 {3, opSubstr}, 367 {2, opLeft}, 368 {2, opRight}, 369 {1, opSize}, 370 {2, opCatpushdata}, 371 372 // stack 373 {1, opToAltStack}, 374 {2, op2Drop}, 375 {2, op2Dup}, 376 {3, op3Dup}, 377 {4, op2Over}, 378 {6, op2Rot}, 379 {4, op2Swap}, 380 {1, opIfDup}, 381 {1, opDrop}, 382 {1, opDup}, 383 {2, opNip}, 384 {2, opOver}, 385 {2, opPick}, // TODO(kr): special; check data-dependent # of pops 386 {2, opRoll}, // TODO(kr): special; check data-dependent # of pops 387 {3, opRot}, 388 {2, opSwap}, 389 {2, opTuck}, 390 } 391 392 for _, test := range cases { 393 t.Run(funcName(test.op), func(t *testing.T) { 394 395 for i := 0; i < test.narg; i++ { 396 t.Run(fmt.Sprintf("%d args", i), func(t *testing.T) { 397 398 vm := &virtualMachine{ 399 runLimit: 50000, 400 dataStack: make([][]byte, i), 401 } 402 err := test.op(vm) 403 if err != ErrDataStackUnderflow { 404 t.Errorf("err = %v, want ErrStackUnderflow", err) 405 } 406 }) 407 } 408 }) 409 } 410 } 411 412 func funcName(f interface{}) string { 413 v := reflect.ValueOf(f) 414 if v.Kind() != reflect.Func { 415 return "" 416 } 417 s := runtime.FuncForPC(v.Pointer()).Name() 418 return s[strings.LastIndex(s, ".")+1:] 419 }