github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/tests/vm_test_util.go (about) 1 // Copyright 2015 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/ethereumproject/go-ethereum/common" 28 "github.com/ethereumproject/go-ethereum/core/state" 29 "github.com/ethereumproject/go-ethereum/core/vm" 30 "github.com/ethereumproject/go-ethereum/ethdb" 31 "github.com/ethereumproject/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 env := make(map[string]string) 71 env["currentCoinbase"] = test.Env.CurrentCoinbase 72 env["currentDifficulty"] = test.Env.CurrentDifficulty 73 env["currentGasLimit"] = test.Env.CurrentGasLimit 74 env["currentNumber"] = test.Env.CurrentNumber 75 env["previousHash"] = test.Env.PreviousHash 76 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 77 env["currentTimestamp"] = strconv.Itoa(int(n)) 78 } else { 79 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 80 } 81 82 b.ResetTimer() 83 for i := 0; i < b.N; i++ { 84 benchVmTest(test, env, b) 85 } 86 87 return nil 88 } 89 90 func benchVmTest(test VmTest, env map[string]string, b *testing.B) { 91 b.StopTimer() 92 db, _ := ethdb.NewMemDatabase() 93 statedb := makePreState(db, test.Pre) 94 b.StartTimer() 95 96 RunVm(statedb, env, test.Exec) 97 } 98 99 func RunVmTest(p string, skipTests []string) error { 100 tests := make(map[string]VmTest) 101 err := readJsonFile(p, &tests) 102 if err != nil { 103 return err 104 } 105 106 if err := runVmTests(tests, skipTests); err != nil { 107 return err 108 } 109 110 return nil 111 } 112 113 func runVmTests(tests map[string]VmTest, skipTests []string) error { 114 skipTest := make(map[string]bool, len(skipTests)) 115 for _, name := range skipTests { 116 skipTest[name] = true 117 } 118 119 for name, test := range tests { 120 if skipTest[name] { 121 glog.Infoln("Skipping VM test", name) 122 return nil 123 } 124 125 if err := runVmTest(test); err != nil { 126 return fmt.Errorf("%s %s", name, err.Error()) 127 } 128 129 glog.Infoln("VM test passed: ", name) 130 //fmt.Println(string(statedb.Dump())) 131 } 132 return nil 133 } 134 135 func runVmTest(test VmTest) error { 136 db, _ := ethdb.NewMemDatabase() 137 statedb := makePreState(db, test.Pre) 138 139 // XXX Yeah, yeah... 140 env := make(map[string]string) 141 env["currentCoinbase"] = test.Env.CurrentCoinbase 142 env["currentDifficulty"] = test.Env.CurrentDifficulty 143 env["currentGasLimit"] = test.Env.CurrentGasLimit 144 env["currentNumber"] = test.Env.CurrentNumber 145 env["previousHash"] = test.Env.PreviousHash 146 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 147 env["currentTimestamp"] = strconv.Itoa(int(n)) 148 } else { 149 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 150 } 151 152 ret, logs, gas, err := RunVm(statedb, env, test.Exec) 153 154 // Compare expected and actual return 155 rexp := common.FromHex(test.Out) 156 if bytes.Compare(rexp, ret) != 0 { 157 return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret) 158 } 159 160 // Check gas usage 161 if test.Gas == "" && err == nil { 162 return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successfull") 163 } else { 164 want, ok := new(big.Int).SetString(test.Gas, 0) 165 if test.Gas == "" { 166 want = new(big.Int) 167 } else if !ok { 168 return fmt.Errorf("malformed test gas %q", test.Gas) 169 } 170 if want.Cmp(gas) != 0 { 171 return fmt.Errorf("gas failed. Expected %v, got %v\n", want, gas) 172 } 173 } 174 175 // check post state 176 for addr, account := range test.Post { 177 obj := statedb.GetAccount(common.HexToAddress(addr)) 178 if obj == nil { 179 continue 180 } 181 for addr, value := range account.Storage { 182 v := statedb.GetState(obj.Address(), common.HexToHash(addr)) 183 vexp := common.HexToHash(value) 184 if v != vexp { 185 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()) 186 } 187 } 188 } 189 190 // check logs 191 if len(test.Logs) > 0 { 192 lerr := checkLogs(test.Logs, logs) 193 if lerr != nil { 194 return lerr 195 } 196 } 197 198 return nil 199 } 200 201 func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs, *big.Int, error) { 202 var ( 203 to = common.HexToAddress(exec["address"]) 204 from = common.HexToAddress(exec["caller"]) 205 data = common.FromHex(exec["data"]) 206 gas, _ = new(big.Int).SetString(exec["gas"], 0) 207 price, _ = new(big.Int).SetString(exec["gasPrice"], 0) 208 value, _ = new(big.Int).SetString(exec["value"], 0) 209 ) 210 if gas == nil || price == nil || value == nil { 211 panic("malformed gas, price or value") 212 } 213 // Reset the pre-compiled contracts for VM tests. 214 vm.Precompiled = make(map[string]*vm.PrecompiledAccount) 215 216 caller := state.GetOrNewStateObject(from) 217 218 vmenv := NewEnvFromMap(RuleSet{ 219 HomesteadBlock: big.NewInt(1150000), 220 HomesteadGasRepriceBlock: big.NewInt(2500000), 221 DiehardBlock: big.NewInt(3000000), 222 ExplosionBlock: big.NewInt(5000000), 223 }, state, env, exec) 224 vmenv.vmTest = true 225 vmenv.skipTransfer = true 226 vmenv.initial = true 227 ret, err := vmenv.Call(caller, to, data, gas, price, value) 228 229 return ret, vmenv.state.Logs(), vmenv.Gas, err 230 }