vm_test_util.go 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251
  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. package tests
  17. import (
  18. "bytes"
  19. "fmt"
  20. "io"
  21. "math/big"
  22. "strconv"
  23. "testing"
  24. "github.com/ethereum/go-ethereum/common"
  25. "github.com/ethereum/go-ethereum/core/state"
  26. "github.com/ethereum/go-ethereum/core/vm"
  27. "github.com/ethereum/go-ethereum/ethdb"
  28. "github.com/ethereum/go-ethereum/logger/glog"
  29. "github.com/ethereum/go-ethereum/params"
  30. )
  31. func RunVmTestWithReader(r io.Reader, skipTests []string) error {
  32. tests := make(map[string]VmTest)
  33. err := readJson(r, &tests)
  34. if err != nil {
  35. return err
  36. }
  37. if err != nil {
  38. return err
  39. }
  40. if err := runVmTests(tests, skipTests); err != nil {
  41. return err
  42. }
  43. return nil
  44. }
  45. type bconf struct {
  46. name string
  47. precomp bool
  48. jit bool
  49. }
  50. func BenchVmTest(p string, conf bconf, b *testing.B) error {
  51. tests := make(map[string]VmTest)
  52. err := readJsonFile(p, &tests)
  53. if err != nil {
  54. return err
  55. }
  56. test, ok := tests[conf.name]
  57. if !ok {
  58. return fmt.Errorf("test not found: %s", conf.name)
  59. }
  60. env := make(map[string]string)
  61. env["currentCoinbase"] = test.Env.CurrentCoinbase
  62. env["currentDifficulty"] = test.Env.CurrentDifficulty
  63. env["currentGasLimit"] = test.Env.CurrentGasLimit
  64. env["currentNumber"] = test.Env.CurrentNumber
  65. env["previousHash"] = test.Env.PreviousHash
  66. if n, ok := test.Env.CurrentTimestamp.(float64); ok {
  67. env["currentTimestamp"] = strconv.Itoa(int(n))
  68. } else {
  69. env["currentTimestamp"] = test.Env.CurrentTimestamp.(string)
  70. }
  71. /*
  72. if conf.precomp {
  73. program := vm.NewProgram(test.code)
  74. err := vm.AttachProgram(program)
  75. if err != nil {
  76. return err
  77. }
  78. }
  79. */
  80. b.ResetTimer()
  81. for i := 0; i < b.N; i++ {
  82. benchVmTest(test, env, b)
  83. }
  84. return nil
  85. }
  86. func benchVmTest(test VmTest, env map[string]string, b *testing.B) {
  87. b.StopTimer()
  88. db, _ := ethdb.NewMemDatabase()
  89. statedb, _ := state.New(common.Hash{}, db)
  90. for addr, account := range test.Pre {
  91. obj := StateObjectFromAccount(db, addr, account)
  92. statedb.SetStateObject(obj)
  93. for a, v := range account.Storage {
  94. obj.SetState(common.HexToHash(a), common.HexToHash(v))
  95. }
  96. }
  97. b.StartTimer()
  98. RunVm(statedb, env, test.Exec)
  99. }
  100. func RunVmTest(p string, skipTests []string) error {
  101. tests := make(map[string]VmTest)
  102. err := readJsonFile(p, &tests)
  103. if err != nil {
  104. return err
  105. }
  106. if err := runVmTests(tests, skipTests); err != nil {
  107. return err
  108. }
  109. return nil
  110. }
  111. func runVmTests(tests map[string]VmTest, skipTests []string) error {
  112. skipTest := make(map[string]bool, len(skipTests))
  113. for _, name := range skipTests {
  114. skipTest[name] = true
  115. }
  116. for name, test := range tests {
  117. if skipTest[name] {
  118. glog.Infoln("Skipping VM test", name)
  119. return nil
  120. }
  121. if err := runVmTest(test); err != nil {
  122. return fmt.Errorf("%s %s", name, err.Error())
  123. }
  124. glog.Infoln("VM test passed: ", name)
  125. //fmt.Println(string(statedb.Dump()))
  126. }
  127. return nil
  128. }
  129. func runVmTest(test VmTest) error {
  130. db, _ := ethdb.NewMemDatabase()
  131. statedb, _ := state.New(common.Hash{}, db)
  132. for addr, account := range test.Pre {
  133. obj := StateObjectFromAccount(db, addr, account)
  134. statedb.SetStateObject(obj)
  135. for a, v := range account.Storage {
  136. obj.SetState(common.HexToHash(a), common.HexToHash(v))
  137. }
  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. var (
  152. ret []byte
  153. gas *big.Int
  154. err error
  155. logs vm.Logs
  156. )
  157. ret, logs, gas, err = RunVm(statedb, env, test.Exec)
  158. // Compare expected and actual return
  159. rexp := common.FromHex(test.Out)
  160. if bytes.Compare(rexp, ret) != 0 {
  161. return fmt.Errorf("return failed. Expected %x, got %x\n", rexp, ret)
  162. }
  163. // Check gas usage
  164. if len(test.Gas) == 0 && err == nil {
  165. return fmt.Errorf("gas unspecified, indicating an error. VM returned (incorrectly) successfull")
  166. } else {
  167. gexp := common.Big(test.Gas)
  168. if gexp.Cmp(gas) != 0 {
  169. return fmt.Errorf("gas failed. Expected %v, got %v\n", gexp, gas)
  170. }
  171. }
  172. // check post state
  173. for addr, account := range test.Post {
  174. obj := statedb.GetStateObject(common.HexToAddress(addr))
  175. if obj == nil {
  176. continue
  177. }
  178. for addr, value := range account.Storage {
  179. v := obj.GetState(common.HexToHash(addr))
  180. vexp := common.HexToHash(value)
  181. if v != vexp {
  182. 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())
  183. }
  184. }
  185. }
  186. // check logs
  187. if len(test.Logs) > 0 {
  188. lerr := checkLogs(test.Logs, logs)
  189. if lerr != nil {
  190. return lerr
  191. }
  192. }
  193. return nil
  194. }
  195. func RunVm(state *state.StateDB, env, exec map[string]string) ([]byte, vm.Logs, *big.Int, error) {
  196. var (
  197. to = common.HexToAddress(exec["address"])
  198. from = common.HexToAddress(exec["caller"])
  199. data = common.FromHex(exec["data"])
  200. gas = common.Big(exec["gas"])
  201. price = common.Big(exec["gasPrice"])
  202. value = common.Big(exec["value"])
  203. )
  204. // Reset the pre-compiled contracts for VM tests.
  205. vm.Precompiled = make(map[string]*vm.PrecompiledAccount)
  206. caller := state.GetOrNewStateObject(from)
  207. vmenv := NewEnvFromMap(RuleSet{params.MainNetHomesteadBlock}, state, env, exec)
  208. vmenv.vmTest = true
  209. vmenv.skipTransfer = true
  210. vmenv.initial = true
  211. ret, err := vmenv.Call(caller, to, data, gas, price, value)
  212. return ret, vmenv.state.Logs(), vmenv.Gas, err
  213. }