github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/tests/vm_test_util.go (about) 1 // Copyright 2014 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package tests 18 19 import ( 20 "bytes" 21 "fmt" 22 "io" 23 "math/big" 24 "strconv" 25 "testing" 26 27 "github.com/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/core/state" 29 "github.com/ethereum/go-ethereum/core/vm" 30 "github.com/ethereum/go-ethereum/ethdb" 31 "github.com/ethereum/go-ethereum/logger/glog" 32 ) 33 34 func RunVmTestWithReader(r io.Reader, skipTests []string) error { 35 tests := make(map[string]VmTest) 36 err := readJson(r, &tests) 37 if err != nil { 38 return err 39 } 40 41 if err != nil { 42 return err 43 } 44 45 if err := runVmTests(tests, skipTests); err != nil { 46 return err 47 } 48 49 return nil 50 } 51 52 type bconf struct { 53 name string 54 precomp bool 55 jit bool 56 } 57 58 func BenchVmTest(p string, conf bconf, b *testing.B) error { 59 tests := make(map[string]VmTest) 60 err := readJsonFile(p, &tests) 61 if err != nil { 62 return err 63 } 64 65 test, ok := tests[conf.name] 66 if !ok { 67 return fmt.Errorf("test not found: %s", conf.name) 68 } 69 70 pJit := vm.EnableJit 71 vm.EnableJit = conf.jit 72 pForceJit := vm.ForceJit 73 vm.ForceJit = conf.precomp 74 75 env := make(map[string]string) 76 env["currentCoinbase"] = test.Env.CurrentCoinbase 77 env["currentDifficulty"] = test.Env.CurrentDifficulty 78 env["currentGasLimit"] = test.Env.CurrentGasLimit 79 env["currentNumber"] = test.Env.CurrentNumber 80 env["previousHash"] = test.Env.PreviousHash 81 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 82 env["currentTimestamp"] = strconv.Itoa(int(n)) 83 } else { 84 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 85 } 86 87 /* 88 if conf.precomp { 89 program := vm.NewProgram(test.code) 90 err := vm.AttachProgram(program) 91 if err != nil { 92 return err 93 } 94 } 95 */ 96 97 b.ResetTimer() 98 for i := 0; i < b.N; i++ { 99 benchVmTest(test, env, b) 100 } 101 102 vm.EnableJit = pJit 103 vm.ForceJit = pForceJit 104 105 return nil 106 } 107 108 func benchVmTest(test VmTest, env map[string]string, b *testing.B) { 109 b.StopTimer() 110 db, _ := ethdb.NewMemDatabase() 111 statedb := state.New(common.Hash{}, db) 112 for addr, account := range test.Pre { 113 obj := StateObjectFromAccount(db, addr, account) 114 statedb.SetStateObject(obj) 115 for a, v := range account.Storage { 116 obj.SetState(common.HexToHash(a), common.HexToHash(v)) 117 } 118 } 119 b.StartTimer() 120 121 RunVm(statedb, env, test.Exec) 122 } 123 124 func RunVmTest(p string, skipTests []string) error { 125 tests := make(map[string]VmTest) 126 err := readJsonFile(p, &tests) 127 if err != nil { 128 return err 129 } 130 131 if err := runVmTests(tests, skipTests); err != nil { 132 return err 133 } 134 135 return nil 136 } 137 138 func runVmTests(tests map[string]VmTest, skipTests []string) error { 139 skipTest := make(map[string]bool, len(skipTests)) 140 for _, name := range skipTests { 141 skipTest[name] = true 142 } 143 144 for name, test := range tests { 145 if skipTest[name] { 146 glog.Infoln("Skipping VM test", name) 147 return nil 148 } 149 150 if err := runVmTest(test); err != nil { 151 return fmt.Errorf("%s %s", name, err.Error()) 152 } 153 154 glog.Infoln("VM test passed: ", name) 155 //fmt.Println(string(statedb.Dump())) 156 } 157 return nil 158 } 159 160 func runVmTest(test VmTest) error { 161 db, _ := ethdb.NewMemDatabase() 162 statedb := state.New(common.Hash{}, db) 163 for addr, account := range test.Pre { 164 obj := StateObjectFromAccount(db, addr, account) 165 statedb.SetStateObject(obj) 166 for a, v := range account.Storage { 167 obj.SetState(common.HexToHash(a), common.HexToHash(v)) 168 } 169 } 170 171 // XXX Yeah, yeah... 172 env := make(map[string]string) 173 env["currentCoinbase"] = test.Env.CurrentCoinbase 174 env["currentDifficulty"] = test.Env.CurrentDifficulty 175 env["currentGasLimit"] = test.Env.CurrentGasLimit 176 env["currentNumber"] = test.Env.CurrentNumber 177 env["previousHash"] = test.Env.PreviousHash 178 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 179 env["currentTimestamp"] = strconv.Itoa(int(n)) 180 } else { 181 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 182 } 183 184 var ( 185 ret []byte 186 gas *big.Int 187 err error 188 logs state.Logs 189 ) 190 191 ret, logs, gas, err = RunVm(statedb, env, test.Exec) 192 193 // Compare expected and actual return 194 rexp := common.FromHex(test.Out) 195 if bytes.Compare(rexp, ret) != 0 { 196 return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret) 197 } 198 199 // Check gas usage 200 if len(test.Gas) == 0 && err == nil { 201 return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successfull") 202 } else { 203 gexp := common.Big(test.Gas) 204 if gexp.Cmp(gas) != 0 { 205 return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas) 206 } 207 } 208 209 // check post state 210 for addr, account := range test.Post { 211 obj := statedb.GetStateObject(common.HexToAddress(addr)) 212 if obj == nil { 213 continue 214 } 215 216 for addr, value := range account.Storage { 217 v := obj.GetState(common.HexToHash(addr)) 218 vexp := common.HexToHash(value) 219 220 if v != vexp { 221 return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", obj.Address().Bytes()[0:4], addr, vexp, v, vexp.Big(), v.Big()) 222 } 223 } 224 } 225 226 // check logs 227 if len(test.Logs) > 0 { 228 lerr := checkLogs(test.Logs, logs) 229 if lerr != nil { 230 return lerr 231 } 232 } 233 234 return nil 235 } 236 237 func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, state.Logs, *big.Int, error) { 238 var ( 239 to = common.HexToAddress(exec["address"]) 240 from = common.HexToAddress(exec["caller"]) 241 data = common.FromHex(exec["data"]) 242 gas = common.Big(exec["gas"]) 243 price = common.Big(exec["gasPrice"]) 244 value = common.Big(exec["value"]) 245 ) 246 // Reset the pre-compiled contracts for VM tests. 247 vm.Precompiled = make(map[string]*vm.PrecompiledAccount) 248 249 caller := state.GetOrNewStateObject(from) 250 251 vmenv := NewEnvFromMap(state, env, exec) 252 vmenv.vmTest = true 253 vmenv.skipTransfer = true 254 vmenv.initial = true 255 ret, err := vmenv.Call(caller, to, data, gas, price, value) 256 257 return ret, vmenv.state.Logs(), vmenv.Gas, err 258 }