state_test_util.go 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281
  1. // Copyright 2017 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. "encoding/hex"
  20. "encoding/json"
  21. "fmt"
  22. "math/big"
  23. "reflect"
  24. "strings"
  25. "github.com/ethereum/go-ethereum/common"
  26. "github.com/ethereum/go-ethereum/common/hexutil"
  27. "github.com/ethereum/go-ethereum/common/math"
  28. "github.com/ethereum/go-ethereum/core"
  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/crypto"
  33. "github.com/ethereum/go-ethereum/ethdb"
  34. "github.com/ethereum/go-ethereum/params"
  35. )
  36. // StateTest checks transaction processing without block context.
  37. // See https://github.com/ethereum/EIPs/issues/176 for the test format specification.
  38. type StateTest struct {
  39. json stJSON
  40. }
  41. // StateSubtest selects a specific configuration of a General State Test.
  42. type StateSubtest struct {
  43. Fork string
  44. Index int
  45. }
  46. func (t *StateTest) UnmarshalJSON(in []byte) error {
  47. return json.Unmarshal(in, &t.json)
  48. }
  49. type stJSON struct {
  50. Env stEnv `json:"env"`
  51. Pre core.GenesisAlloc `json:"pre"`
  52. Tx stTransaction `json:"transaction"`
  53. Out hexutil.Bytes `json:"out"`
  54. Post map[string][]stPostState `json:"post"`
  55. }
  56. type stPostState struct {
  57. Root common.UnprefixedHash `json:"hash"`
  58. Logs *[]stLog `json:"logs"`
  59. Indexes struct {
  60. Data int `json:"data"`
  61. Gas int `json:"gas"`
  62. Value int `json:"value"`
  63. }
  64. }
  65. //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
  66. type stEnv struct {
  67. Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
  68. Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"`
  69. GasLimit *big.Int `json:"currentGasLimit" gencodec:"required"`
  70. Number uint64 `json:"currentNumber" gencodec:"required"`
  71. Timestamp uint64 `json:"currentTimestamp" gencodec:"required"`
  72. }
  73. type stEnvMarshaling struct {
  74. Coinbase common.UnprefixedAddress
  75. Difficulty *math.HexOrDecimal256
  76. GasLimit *math.HexOrDecimal256
  77. Number math.HexOrDecimal64
  78. Timestamp math.HexOrDecimal64
  79. }
  80. //go:generate gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go
  81. type stTransaction struct {
  82. GasPrice *big.Int `json:"gasPrice"`
  83. Nonce uint64 `json:"nonce"`
  84. To string `json:"to"`
  85. Data []string `json:"data"`
  86. GasLimit []uint64 `json:"gasLimit"`
  87. Value []string `json:"value"`
  88. PrivateKey []byte `json:"secretKey"`
  89. }
  90. type stTransactionMarshaling struct {
  91. GasPrice *math.HexOrDecimal256
  92. Nonce math.HexOrDecimal64
  93. GasLimit []math.HexOrDecimal64
  94. PrivateKey hexutil.Bytes
  95. }
  96. //go:generate gencodec -type stLog -field-override stLogMarshaling -out gen_stlog.go
  97. type stLog struct {
  98. Address common.Address `json:"address"`
  99. Data []byte `json:"data"`
  100. Topics []common.Hash `json:"topics"`
  101. Bloom string `json:"bloom"`
  102. }
  103. type stLogMarshaling struct {
  104. Address common.UnprefixedAddress
  105. Data hexutil.Bytes
  106. Topics []common.UnprefixedHash
  107. }
  108. // Subtests returns all valid subtests of the test.
  109. func (t *StateTest) Subtests() []StateSubtest {
  110. var sub []StateSubtest
  111. for fork, pss := range t.json.Post {
  112. for i, _ := range pss {
  113. sub = append(sub, StateSubtest{fork, i})
  114. }
  115. }
  116. return sub
  117. }
  118. // Run executes a specific subtest.
  119. func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) error {
  120. config, ok := Forks[subtest.Fork]
  121. if !ok {
  122. return UnsupportedForkError{subtest.Fork}
  123. }
  124. block, _ := t.genesis(config).ToBlock()
  125. db, _ := ethdb.NewMemDatabase()
  126. statedb := makePreState(db, t.json.Pre)
  127. post := t.json.Post[subtest.Fork][subtest.Index]
  128. msg, err := t.json.Tx.toMessage(post)
  129. if err != nil {
  130. return err
  131. }
  132. context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase)
  133. context.GetHash = vmTestBlockHash
  134. evm := vm.NewEVM(context, statedb, config, vmconfig)
  135. gaspool := new(core.GasPool)
  136. gaspool.AddGas(block.GasLimit())
  137. snapshot := statedb.Snapshot()
  138. if _, _, _, err := core.ApplyMessage(evm, msg, gaspool); err != nil {
  139. statedb.RevertToSnapshot(snapshot)
  140. }
  141. if post.Logs != nil {
  142. if err := checkLogs(statedb.Logs(), *post.Logs); err != nil {
  143. return err
  144. }
  145. }
  146. root, _ := statedb.CommitTo(db, config.IsEIP158(block.Number()))
  147. if root != common.Hash(post.Root) {
  148. return fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root)
  149. }
  150. return nil
  151. }
  152. func (t *StateTest) gasLimit(subtest StateSubtest) uint64 {
  153. return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas]
  154. }
  155. func makePreState(db ethdb.Database, accounts core.GenesisAlloc) *state.StateDB {
  156. sdb := state.NewDatabase(db)
  157. statedb, _ := state.New(common.Hash{}, sdb)
  158. for addr, a := range accounts {
  159. statedb.SetCode(addr, a.Code)
  160. statedb.SetNonce(addr, a.Nonce)
  161. statedb.SetBalance(addr, a.Balance)
  162. for k, v := range a.Storage {
  163. statedb.SetState(addr, k, v)
  164. }
  165. }
  166. // Commit and re-open to start with a clean state.
  167. root, _ := statedb.CommitTo(db, false)
  168. statedb, _ = state.New(root, sdb)
  169. return statedb
  170. }
  171. func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis {
  172. return &core.Genesis{
  173. Config: config,
  174. Coinbase: t.json.Env.Coinbase,
  175. Difficulty: t.json.Env.Difficulty,
  176. GasLimit: t.json.Env.GasLimit.Uint64(),
  177. Number: t.json.Env.Number,
  178. Timestamp: t.json.Env.Timestamp,
  179. Alloc: t.json.Pre,
  180. }
  181. }
  182. func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) {
  183. // Derive sender from private key if present.
  184. var from common.Address
  185. if len(tx.PrivateKey) > 0 {
  186. key, err := crypto.ToECDSA(tx.PrivateKey)
  187. if err != nil {
  188. return nil, fmt.Errorf("invalid private key: %v", err)
  189. }
  190. from = crypto.PubkeyToAddress(key.PublicKey)
  191. }
  192. // Parse recipient if present.
  193. var to *common.Address
  194. if tx.To != "" {
  195. to = new(common.Address)
  196. if err := to.UnmarshalText([]byte(tx.To)); err != nil {
  197. return nil, fmt.Errorf("invalid to address: %v", err)
  198. }
  199. }
  200. // Get values specific to this post state.
  201. if ps.Indexes.Data > len(tx.Data) {
  202. return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data)
  203. }
  204. if ps.Indexes.Value > len(tx.Value) {
  205. return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value)
  206. }
  207. if ps.Indexes.Gas > len(tx.GasLimit) {
  208. return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas)
  209. }
  210. dataHex := tx.Data[ps.Indexes.Data]
  211. valueHex := tx.Value[ps.Indexes.Value]
  212. gasLimit := tx.GasLimit[ps.Indexes.Gas]
  213. // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203
  214. value := new(big.Int)
  215. if valueHex != "0x" {
  216. v, ok := math.ParseBig256(valueHex)
  217. if !ok {
  218. return nil, fmt.Errorf("invalid tx value %q", valueHex)
  219. }
  220. value = v
  221. }
  222. data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x"))
  223. if err != nil {
  224. return nil, fmt.Errorf("invalid tx data %q", dataHex)
  225. }
  226. msg := types.NewMessage(from, to, tx.Nonce, value, new(big.Int).SetUint64(gasLimit), tx.GasPrice, data, true)
  227. return msg, nil
  228. }
  229. func checkLogs(have []*types.Log, want []stLog) error {
  230. if len(have) != len(want) {
  231. return fmt.Errorf("logs length mismatch: got %d, want %d", len(have), len(want))
  232. }
  233. for i := range have {
  234. if have[i].Address != want[i].Address {
  235. return fmt.Errorf("log address %d: got %x, want %x", i, have[i].Address, want[i].Address)
  236. }
  237. if !bytes.Equal(have[i].Data, want[i].Data) {
  238. return fmt.Errorf("log data %d: got %x, want %x", i, have[i].Data, want[i].Data)
  239. }
  240. if !reflect.DeepEqual(have[i].Topics, want[i].Topics) {
  241. return fmt.Errorf("log topics %d:\ngot %x\nwant %x", i, have[i].Topics, want[i].Topics)
  242. }
  243. genBloom := math.PaddedBigBytes(types.LogsBloom([]*types.Log{have[i]}), 256)
  244. var wantBloom types.Bloom
  245. if err := hexutil.UnmarshalFixedUnprefixedText("Bloom", []byte(want[i].Bloom), wantBloom[:]); err != nil {
  246. return fmt.Errorf("test log %d has invalid bloom: %v", i, err)
  247. }
  248. if !bytes.Equal(genBloom, wantBloom[:]) {
  249. return fmt.Errorf("bloom mismatch")
  250. }
  251. }
  252. return nil
  253. }