github.com/ylsGit/go-ethereum@v1.6.5/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/ethereum/go-ethereum/common" 28 "github.com/ethereum/go-ethereum/common/math" 29 "github.com/ethereum/go-ethereum/core/state" 30 "github.com/ethereum/go-ethereum/core/types" 31 "github.com/ethereum/go-ethereum/core/vm" 32 "github.com/ethereum/go-ethereum/ethdb" 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/ethereum/go-ethereum/params" 35 ) 36 37 func RunVmTestWithReader(r io.Reader, skipTests []string) error { 38 tests := make(map[string]VmTest) 39 err := readJson(r, &tests) 40 if err != nil { 41 return err 42 } 43 44 if err != nil { 45 return err 46 } 47 48 if err := runVmTests(tests, skipTests); err != nil { 49 return err 50 } 51 52 return nil 53 } 54 55 type bconf struct { 56 name string 57 precomp bool 58 jit bool 59 } 60 61 func BenchVmTest(p string, conf bconf, b *testing.B) error { 62 tests := make(map[string]VmTest) 63 err := readJsonFile(p, &tests) 64 if err != nil { 65 return err 66 } 67 68 test, ok := tests[conf.name] 69 if !ok { 70 return fmt.Errorf("test not found: %s", conf.name) 71 } 72 73 env := make(map[string]string) 74 env["currentCoinbase"] = test.Env.CurrentCoinbase 75 env["currentDifficulty"] = test.Env.CurrentDifficulty 76 env["currentGasLimit"] = test.Env.CurrentGasLimit 77 env["currentNumber"] = test.Env.CurrentNumber 78 env["previousHash"] = test.Env.PreviousHash 79 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 80 env["currentTimestamp"] = strconv.Itoa(int(n)) 81 } else { 82 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 83 } 84 85 /* 86 if conf.precomp { 87 program := vm.NewProgram(test.code) 88 err := vm.AttachProgram(program) 89 if err != nil { 90 return err 91 } 92 } 93 */ 94 95 b.ResetTimer() 96 for i := 0; i < b.N; i++ { 97 benchVmTest(test, env, b) 98 } 99 100 return nil 101 } 102 103 func benchVmTest(test VmTest, env map[string]string, b *testing.B) { 104 b.StopTimer() 105 db, _ := ethdb.NewMemDatabase() 106 statedb := makePreState(db, test.Pre) 107 b.StartTimer() 108 109 RunVm(statedb, env, test.Exec) 110 } 111 112 func RunVmTest(p string, skipTests []string) error { 113 tests := make(map[string]VmTest) 114 err := readJsonFile(p, &tests) 115 if err != nil { 116 return err 117 } 118 119 if err := runVmTests(tests, skipTests); err != nil { 120 return err 121 } 122 123 return nil 124 } 125 126 func runVmTests(tests map[string]VmTest, skipTests []string) error { 127 skipTest := make(map[string]bool, len(skipTests)) 128 for _, name := range skipTests { 129 skipTest[name] = true 130 } 131 132 for name, test := range tests { 133 if skipTest[name] /*|| name != "exp0"*/ { 134 log.Info(fmt.Sprint("Skipping VM test", name)) 135 continue 136 } 137 138 if err := runVmTest(test); err != nil { 139 return fmt.Errorf("%s %s", name, err.Error()) 140 } 141 142 log.Info(fmt.Sprint("VM test passed: ", name)) 143 //fmt.Println(string(statedb.Dump())) 144 } 145 return nil 146 } 147 148 func runVmTest(test VmTest) error { 149 db, _ := ethdb.NewMemDatabase() 150 statedb := makePreState(db, test.Pre) 151 152 // XXX Yeah, yeah... 153 env := make(map[string]string) 154 env["currentCoinbase"] = test.Env.CurrentCoinbase 155 env["currentDifficulty"] = test.Env.CurrentDifficulty 156 env["currentGasLimit"] = test.Env.CurrentGasLimit 157 env["currentNumber"] = test.Env.CurrentNumber 158 env["previousHash"] = test.Env.PreviousHash 159 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 160 env["currentTimestamp"] = strconv.Itoa(int(n)) 161 } else { 162 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 163 } 164 165 var ( 166 ret []byte 167 gas *big.Int 168 err error 169 logs []*types.Log 170 ) 171 172 ret, logs, gas, err = RunVm(statedb, env, test.Exec) 173 174 // Compare expected and actual return 175 rexp := common.FromHex(test.Out) 176 if !bytes.Equal(rexp, ret) { 177 return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret) 178 } 179 180 // Check gas usage 181 if len(test.Gas) == 0 && err == nil { 182 return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successful") 183 } else { 184 gexp := math.MustParseBig256(test.Gas) 185 if gexp.Cmp(gas) != 0 { 186 return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas) 187 } 188 } 189 190 // check post state 191 for address, account := range test.Post { 192 accountAddr := common.HexToAddress(address) 193 if !statedb.Exist(accountAddr) { 194 continue 195 } 196 for addr, value := range account.Storage { 197 v := statedb.GetState(accountAddr, common.HexToHash(addr)) 198 vexp := common.HexToHash(value) 199 if v != vexp { 200 return fmt.Errorf("(%x: %s) storage failed. Expected %x, got %x (%v %v)\n", addr[:4], addr, vexp, v, vexp.Big(), v.Big()) 201 } 202 } 203 } 204 205 // check logs 206 if len(test.Logs) > 0 { 207 lerr := checkLogs(test.Logs, logs) 208 if lerr != nil { 209 return lerr 210 } 211 } 212 213 return nil 214 } 215 216 func RunVm(statedb *state.StateDB, env, exec map[string]string) ([]byte, []*types.Log, *big.Int, error) { 217 chainConfig := ¶ms.ChainConfig{ 218 HomesteadBlock: params.MainNetHomesteadBlock, 219 DAOForkBlock: params.MainNetDAOForkBlock, 220 DAOForkSupport: true, 221 } 222 var ( 223 to = common.HexToAddress(exec["address"]) 224 from = common.HexToAddress(exec["caller"]) 225 data = common.FromHex(exec["data"]) 226 gas = math.MustParseBig256(exec["gas"]) 227 value = math.MustParseBig256(exec["value"]) 228 ) 229 caller := statedb.GetOrNewStateObject(from) 230 vm.PrecompiledContracts = make(map[common.Address]vm.PrecompiledContract) 231 232 environment, _ := NewEVMEnvironment(true, chainConfig, statedb, env, exec) 233 ret, g, err := environment.Call(caller, to, data, gas.Uint64(), value) 234 return ret, statedb.Logs(), new(big.Int).SetUint64(g), err 235 }