github.com/jeffallen/go-ethereum@v1.1.4-0.20150910155051-571d3236c49c/tests/state_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 "encoding/hex" 22 "fmt" 23 "io" 24 "math/big" 25 "strconv" 26 "testing" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/core" 30 "github.com/ethereum/go-ethereum/core/state" 31 "github.com/ethereum/go-ethereum/core/vm" 32 "github.com/ethereum/go-ethereum/crypto" 33 "github.com/ethereum/go-ethereum/ethdb" 34 "github.com/ethereum/go-ethereum/logger/glog" 35 ) 36 37 func RunStateTestWithReader(r io.Reader, skipTests []string) error { 38 tests := make(map[string]VmTest) 39 if err := readJson(r, &tests); err != nil { 40 return err 41 } 42 43 if err := runStateTests(tests, skipTests); err != nil { 44 return err 45 } 46 47 return nil 48 } 49 50 func RunStateTest(p string, skipTests []string) error { 51 tests := make(map[string]VmTest) 52 if err := readJsonFile(p, &tests); err != nil { 53 return err 54 } 55 56 if err := runStateTests(tests, skipTests); err != nil { 57 return err 58 } 59 60 return nil 61 62 } 63 64 func BenchStateTest(p string, conf bconf, b *testing.B) error { 65 tests := make(map[string]VmTest) 66 if err := readJsonFile(p, &tests); err != nil { 67 return err 68 } 69 test, ok := tests[conf.name] 70 if !ok { 71 return fmt.Errorf("test not found: %s", conf.name) 72 } 73 74 pJit := vm.EnableJit 75 vm.EnableJit = conf.jit 76 pForceJit := vm.ForceJit 77 vm.ForceJit = conf.precomp 78 79 // XXX Yeah, yeah... 80 env := make(map[string]string) 81 env["currentCoinbase"] = test.Env.CurrentCoinbase 82 env["currentDifficulty"] = test.Env.CurrentDifficulty 83 env["currentGasLimit"] = test.Env.CurrentGasLimit 84 env["currentNumber"] = test.Env.CurrentNumber 85 env["previousHash"] = test.Env.PreviousHash 86 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 87 env["currentTimestamp"] = strconv.Itoa(int(n)) 88 } else { 89 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 90 } 91 92 b.ResetTimer() 93 for i := 0; i < b.N; i++ { 94 benchStateTest(test, env, b) 95 } 96 97 vm.EnableJit = pJit 98 vm.ForceJit = pForceJit 99 100 return nil 101 } 102 103 func benchStateTest(test VmTest, env map[string]string, b *testing.B) { 104 b.StopTimer() 105 db, _ := ethdb.NewMemDatabase() 106 statedb := state.New(common.Hash{}, db) 107 for addr, account := range test.Pre { 108 obj := StateObjectFromAccount(db, addr, account) 109 statedb.SetStateObject(obj) 110 for a, v := range account.Storage { 111 obj.SetState(common.HexToHash(a), common.HexToHash(v)) 112 } 113 } 114 b.StartTimer() 115 116 RunState(statedb, env, test.Exec) 117 } 118 119 func runStateTests(tests map[string]VmTest, skipTests []string) error { 120 skipTest := make(map[string]bool, len(skipTests)) 121 for _, name := range skipTests { 122 skipTest[name] = true 123 } 124 125 for name, test := range tests { 126 if skipTest[name] { 127 glog.Infoln("Skipping state test", name) 128 return nil 129 } 130 131 if err := runStateTest(test); err != nil { 132 return fmt.Errorf("%s: %s\n", name, err.Error()) 133 } 134 135 glog.Infoln("State test passed: ", name) 136 //fmt.Println(string(statedb.Dump())) 137 } 138 return nil 139 140 } 141 142 func runStateTest(test VmTest) error { 143 db, _ := ethdb.NewMemDatabase() 144 statedb := state.New(common.Hash{}, db) 145 for addr, account := range test.Pre { 146 obj := StateObjectFromAccount(db, addr, account) 147 statedb.SetStateObject(obj) 148 for a, v := range account.Storage { 149 obj.SetState(common.HexToHash(a), common.HexToHash(v)) 150 } 151 } 152 153 // XXX Yeah, yeah... 154 env := make(map[string]string) 155 env["currentCoinbase"] = test.Env.CurrentCoinbase 156 env["currentDifficulty"] = test.Env.CurrentDifficulty 157 env["currentGasLimit"] = test.Env.CurrentGasLimit 158 env["currentNumber"] = test.Env.CurrentNumber 159 env["previousHash"] = test.Env.PreviousHash 160 if n, ok := test.Env.CurrentTimestamp.(float64); ok { 161 env["currentTimestamp"] = strconv.Itoa(int(n)) 162 } else { 163 env["currentTimestamp"] = test.Env.CurrentTimestamp.(string) 164 } 165 166 var ( 167 ret []byte 168 // gas *big.Int 169 // err error 170 logs state.Logs 171 ) 172 173 ret, logs, _, _ = RunState(statedb, env, test.Transaction) 174 175 // // Compare expected and actual return 176 rexp := common.FromHex(test.Out) 177 if bytes.Compare(rexp, ret) != 0 { 178 return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret) 179 } 180 181 // check post state 182 for addr, account := range test.Post { 183 obj := statedb.GetStateObject(common.HexToAddress(addr)) 184 if obj == nil { 185 continue 186 } 187 188 if obj.Balance().Cmp(common.Big(account.Balance)) != 0 { 189 return fmt.Errorf("(%x) balance failed. Expected %v, got %v => %v\n", obj.Address().Bytes()[:4], account.Balance, obj.Balance(), new(big.Int).Sub(common.Big(account.Balance), obj.Balance())) 190 } 191 192 if obj.Nonce() != common.String2Big(account.Nonce).Uint64() { 193 return fmt.Errorf("(%x) nonce failed. Expected %v, got %v\n", obj.Address().Bytes()[:4], account.Nonce, obj.Nonce()) 194 } 195 196 for addr, value := range account.Storage { 197 v := obj.GetState(common.HexToHash(addr)) 198 vexp := common.HexToHash(value) 199 200 if v != vexp { 201 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()) 202 } 203 } 204 } 205 206 statedb.Sync() 207 if common.HexToHash(test.PostStateRoot) != statedb.Root() { 208 return fmt.Errorf("Post state root error. Expected %s, got %x", test.PostStateRoot, statedb.Root()) 209 } 210 211 // check logs 212 if len(test.Logs) > 0 { 213 if err := checkLogs(test.Logs, logs); err != nil { 214 return err 215 } 216 } 217 218 return nil 219 } 220 221 func RunState(statedb *state.StateDB, env, tx map[string]string) ([]byte, state.Logs, *big.Int, error) { 222 var ( 223 data = common.FromHex(tx["data"]) 224 gas = common.Big(tx["gasLimit"]) 225 price = common.Big(tx["gasPrice"]) 226 value = common.Big(tx["value"]) 227 nonce = common.Big(tx["nonce"]).Uint64() 228 caddr = common.HexToAddress(env["currentCoinbase"]) 229 ) 230 231 var to *common.Address 232 if len(tx["to"]) > 2 { 233 t := common.HexToAddress(tx["to"]) 234 to = &t 235 } 236 // Set pre compiled contracts 237 vm.Precompiled = vm.PrecompiledContracts() 238 239 snapshot := statedb.Copy() 240 coinbase := statedb.GetOrNewStateObject(caddr) 241 coinbase.SetGasLimit(common.Big(env["currentGasLimit"])) 242 243 key, _ := hex.DecodeString(tx["secretKey"]) 244 addr := crypto.PubkeyToAddress(crypto.ToECDSA(key).PublicKey) 245 message := NewMessage(addr, to, data, value, gas, price, nonce) 246 vmenv := NewEnvFromMap(statedb, env, tx) 247 vmenv.origin = addr 248 ret, _, err := core.ApplyMessage(vmenv, message, coinbase) 249 if core.IsNonceErr(err) || core.IsInvalidTxErr(err) || state.IsGasLimitErr(err) { 250 statedb.Set(snapshot) 251 } 252 statedb.SyncObjects() 253 254 return ret, vmenv.state.Logs(), vmenv.Gas, err 255 }