github.com/bytom/bytom@v1.1.2-0.20221014091027-bbcba3df6075/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 altStack: [][]byte{[]byte("statedata")}, 110 context: &Context{ 111 CheckOutput: func(uint64, uint64, []byte, uint64, []byte, [][]byte, bool) (bool, error) { 112 return false, nil 113 }, 114 }, 115 }, 116 wantVM: &virtualMachine{ 117 runLimit: 50062, 118 deferredCost: -78, 119 dataStack: [][]byte{{}}, 120 altStack: [][]byte{[]byte("statedata")}, 121 }, 122 }, { 123 op: OP_CHECKOUTPUT, 124 startVM: &virtualMachine{ 125 dataStack: [][]byte{ 126 {5}, 127 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"), 128 {7}, 129 append([]byte{2}, make([]byte, 31)...), 130 {1}, 131 []byte("controlprog"), 132 }, 133 altStack: [][]byte{[]byte("statedata")}, 134 context: &Context{ 135 CheckOutput: func(uint64, uint64, []byte, uint64, []byte, [][]byte, bool) (bool, error) { 136 return false, ErrBadValue 137 }, 138 }, 139 }, 140 wantErr: ErrBadValue, 141 }, { 142 op: OP_CHECKOUTPUT, 143 startVM: &virtualMachine{ 144 runLimit: 0, 145 dataStack: [][]byte{ 146 {4}, 147 mustDecodeHex("1f2a05f881ed9fa0c9068a84823677409f863891a2196eb55dbfbb677a566374"), 148 {7}, 149 append([]byte{2}, make([]byte, 31)...), 150 {1}, 151 []byte("controlprog"), 152 }, 153 altStack: [][]byte{[]byte("statedata")}, 154 context: &Context{}, 155 }, 156 wantErr: ErrRunLimitExceeded, 157 }, { 158 op: OP_ASSET, 159 startVM: &virtualMachine{ 160 context: &Context{AssetID: &assetID}, 161 }, 162 wantVM: &virtualMachine{ 163 runLimit: 49959, 164 deferredCost: 40, 165 dataStack: [][]byte{assetID}, 166 }, 167 }, { 168 op: OP_AMOUNT, 169 startVM: &virtualMachine{ 170 context: &Context{Amount: uint64ptr(5)}, 171 }, 172 wantVM: &virtualMachine{ 173 runLimit: 49990, 174 deferredCost: 9, 175 dataStack: [][]byte{{5}}, 176 }, 177 }, { 178 op: OP_PROGRAM, 179 startVM: &virtualMachine{ 180 program: []byte("spendprog"), 181 context: &Context{Code: []byte("spendprog")}, 182 }, 183 wantVM: &virtualMachine{ 184 runLimit: 49982, 185 deferredCost: 17, 186 dataStack: [][]byte{[]byte("spendprog")}, 187 }, 188 }, { 189 op: OP_PROGRAM, 190 startVM: &virtualMachine{ 191 program: []byte("issueprog"), 192 runLimit: 50000, 193 context: &Context{Code: []byte("issueprog")}, 194 }, 195 wantVM: &virtualMachine{ 196 runLimit: 49982, 197 deferredCost: 17, 198 dataStack: [][]byte{[]byte("issueprog")}, 199 }, 200 }, { 201 op: OP_INDEX, 202 startVM: &virtualMachine{ 203 context: &Context{DestPos: new(uint64)}, 204 }, 205 wantVM: &virtualMachine{ 206 runLimit: 49991, 207 deferredCost: 8, 208 dataStack: [][]byte{[]byte{}}, 209 }, 210 }, { 211 op: OP_ENTRYID, 212 startVM: &virtualMachine{ 213 context: &Context{EntryID: entryID}, 214 }, 215 wantVM: &virtualMachine{ 216 runLimit: 49959, 217 deferredCost: 40, 218 dataStack: [][]byte{entryID}, 219 }, 220 }} 221 222 txops := []Op{ 223 OP_CHECKOUTPUT, OP_ASSET, OP_AMOUNT, OP_PROGRAM, 224 OP_INDEX, OP_OUTPUTID, 225 } 226 227 for _, op := range txops { 228 cases = append(cases, testStruct{ 229 op: op, 230 startVM: &virtualMachine{ 231 runLimit: 0, 232 context: &Context{}, 233 }, 234 wantErr: ErrRunLimitExceeded, 235 }) 236 } 237 238 for i, c := range cases { 239 t.Logf("case %d", i) 240 prog := []byte{byte(c.op)} 241 vm := c.startVM 242 if c.wantErr != ErrRunLimitExceeded { 243 vm.runLimit = 50000 244 } 245 vm.program = prog 246 err := vm.run() 247 switch errors.Root(err) { 248 case c.wantErr: 249 // ok 250 case nil: 251 t.Errorf("case %d, op %s: got no error, want %v", i, ops[c.op].name, c.wantErr) 252 default: 253 t.Errorf("case %d, op %s: got err = %v want %v", i, ops[c.op].name, err, c.wantErr) 254 } 255 if c.wantErr != nil { 256 continue 257 } 258 gotVM := vm 259 260 c.wantVM.program = prog 261 c.wantVM.pc = 1 262 c.wantVM.nextPC = 1 263 c.wantVM.context = gotVM.context 264 265 if !testutil.DeepEqual(gotVM, c.wantVM) { 266 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)) 267 } 268 } 269 } 270 271 func uint64ptr(n uint64) *uint64 { return &n }