github.com/sberex/go-sberex@v1.8.2-0.20181113200658-ed96ac38f7d7/tests/state_test_util.go (about) 1 // This file is part of the go-sberex library. The go-sberex library is 2 // free software: you can redistribute it and/or modify it under the terms 3 // of the GNU Lesser General Public License as published by the Free 4 // Software Foundation, either version 3 of the License, or (at your option) 5 // any later version. 6 // 7 // The go-sberex library is distributed in the hope that it will be useful, 8 // but WITHOUT ANY WARRANTY; without even the implied warranty of 9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser 10 // General Public License <http://www.gnu.org/licenses/> for more details. 11 12 package tests 13 14 import ( 15 "encoding/hex" 16 "encoding/json" 17 "fmt" 18 "math/big" 19 "strings" 20 21 "github.com/Sberex/go-sberex/common" 22 "github.com/Sberex/go-sberex/common/hexutil" 23 "github.com/Sberex/go-sberex/common/math" 24 "github.com/Sberex/go-sberex/core" 25 "github.com/Sberex/go-sberex/core/state" 26 "github.com/Sberex/go-sberex/core/types" 27 "github.com/Sberex/go-sberex/core/vm" 28 "github.com/Sberex/go-sberex/crypto" 29 "github.com/Sberex/go-sberex/crypto/sha3" 30 "github.com/Sberex/go-sberex/ethdb" 31 "github.com/Sberex/go-sberex/params" 32 "github.com/Sberex/go-sberex/rlp" 33 ) 34 35 // StateTest checks transaction processing without block context. 36 type StateTest struct { 37 json stJSON 38 } 39 40 // StateSubtest selects a specific configuration of a General State Test. 41 type StateSubtest struct { 42 Fork string 43 Index int 44 } 45 46 func (t *StateTest) UnmarshalJSON(in []byte) error { 47 return json.Unmarshal(in, &t.json) 48 } 49 50 type stJSON struct { 51 Env stEnv `json:"env"` 52 Pre core.GenesisAlloc `json:"pre"` 53 Tx stTransaction `json:"transaction"` 54 Out hexutil.Bytes `json:"out"` 55 Post map[string][]stPostState `json:"post"` 56 } 57 58 type stPostState struct { 59 Root common.UnprefixedHash `json:"hash"` 60 Logs common.UnprefixedHash `json:"logs"` 61 Indexes struct { 62 Data int `json:"data"` 63 Gas int `json:"gas"` 64 Value int `json:"value"` 65 } 66 } 67 68 //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go 69 70 type stEnv struct { 71 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 72 Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"` 73 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 74 Number uint64 `json:"currentNumber" gencodec:"required"` 75 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 76 } 77 78 type stEnvMarshaling struct { 79 Coinbase common.UnprefixedAddress 80 Difficulty *math.HexOrDecimal256 81 GasLimit math.HexOrDecimal64 82 Number math.HexOrDecimal64 83 Timestamp math.HexOrDecimal64 84 } 85 86 //go:generate gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go 87 88 type stTransaction struct { 89 GasPrice *big.Int `json:"gasPrice"` 90 Nonce uint64 `json:"nonce"` 91 To string `json:"to"` 92 Data []string `json:"data"` 93 GasLimit []uint64 `json:"gasLimit"` 94 Value []string `json:"value"` 95 PrivateKey []byte `json:"secretKey"` 96 } 97 98 type stTransactionMarshaling struct { 99 GasPrice *math.HexOrDecimal256 100 Nonce math.HexOrDecimal64 101 GasLimit []math.HexOrDecimal64 102 PrivateKey hexutil.Bytes 103 } 104 105 // Subtests returns all valid subtests of the test. 106 func (t *StateTest) Subtests() []StateSubtest { 107 var sub []StateSubtest 108 for fork, pss := range t.json.Post { 109 for i := range pss { 110 sub = append(sub, StateSubtest{fork, i}) 111 } 112 } 113 return sub 114 } 115 116 // Run executes a specific subtest. 117 func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateDB, error) { 118 config, ok := Forks[subtest.Fork] 119 if !ok { 120 return nil, UnsupportedForkError{subtest.Fork} 121 } 122 block := t.genesis(config).ToBlock(nil) 123 db, _ := ethdb.NewMemDatabase() 124 statedb := MakePreState(db, t.json.Pre) 125 126 post := t.json.Post[subtest.Fork][subtest.Index] 127 msg, err := t.json.Tx.toMessage(post) 128 if err != nil { 129 return nil, err 130 } 131 context := core.NewEVMContext(msg, block.Header(), nil, &t.json.Env.Coinbase) 132 context.GetHash = vmTestBlockHash 133 evm := vm.NewEVM(context, statedb, config, vmconfig) 134 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 logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { 142 return statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) 143 } 144 root, _ := statedb.Commit(config.IsEIP158(block.Number())) 145 if root != common.Hash(post.Root) { 146 return statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) 147 } 148 return statedb, nil 149 } 150 151 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 152 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 153 } 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.Commit(false) 168 statedb, _ = state.New(root, sdb) 169 return statedb 170 } 171 172 func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { 173 return &core.Genesis{ 174 Config: config, 175 Coinbase: t.json.Env.Coinbase, 176 Difficulty: t.json.Env.Difficulty, 177 GasLimit: t.json.Env.GasLimit, 178 Number: t.json.Env.Number, 179 Timestamp: t.json.Env.Timestamp, 180 Alloc: t.json.Pre, 181 } 182 } 183 184 func (tx *stTransaction) toMessage(ps stPostState) (core.Message, error) { 185 // Derive sender from private key if present. 186 var from common.Address 187 if len(tx.PrivateKey) > 0 { 188 key, err := crypto.ToECDSA(tx.PrivateKey) 189 if err != nil { 190 return nil, fmt.Errorf("invalid private key: %v", err) 191 } 192 from = crypto.PubkeyToAddress(key.PublicKey) 193 } 194 // Parse recipient if present. 195 var to *common.Address 196 if tx.To != "" { 197 to = new(common.Address) 198 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 199 return nil, fmt.Errorf("invalid to address: %v", err) 200 } 201 } 202 203 // Get values specific to this post state. 204 if ps.Indexes.Data > len(tx.Data) { 205 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 206 } 207 if ps.Indexes.Value > len(tx.Value) { 208 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 209 } 210 if ps.Indexes.Gas > len(tx.GasLimit) { 211 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 212 } 213 dataHex := tx.Data[ps.Indexes.Data] 214 valueHex := tx.Value[ps.Indexes.Value] 215 gasLimit := tx.GasLimit[ps.Indexes.Gas] 216 // Value, Data hex encoding is messy: https://github.com/Sberex/tests/issues/203 217 value := new(big.Int) 218 if valueHex != "0x" { 219 v, ok := math.ParseBig256(valueHex) 220 if !ok { 221 return nil, fmt.Errorf("invalid tx value %q", valueHex) 222 } 223 value = v 224 } 225 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 226 if err != nil { 227 return nil, fmt.Errorf("invalid tx data %q", dataHex) 228 } 229 230 msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true) 231 return msg, nil 232 } 233 234 func rlpHash(x interface{}) (h common.Hash) { 235 hw := sha3.NewKeccak256() 236 rlp.Encode(hw, x) 237 hw.Sum(h[:0]) 238 return h 239 }