github.com/klaytn/klaytn@v1.12.1/tests/state_test_util.go (about) 1 // Modifications Copyright 2018 The klaytn Authors 2 // Copyright 2015 The go-ethereum Authors 3 // This file is part of the go-ethereum library. 4 // 5 // The go-ethereum library is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU Lesser General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // The go-ethereum library is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU Lesser General Public License for more details. 14 // 15 // You should have received a copy of the GNU Lesser General Public License 16 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 17 // 18 // This file is derived from tests/state_test_util.go (2018/06/04). 19 // Modified and improved for the klaytn development. 20 21 package tests 22 23 import ( 24 "encoding/hex" 25 "encoding/json" 26 "fmt" 27 "math/big" 28 "strconv" 29 "strings" 30 31 "github.com/klaytn/klaytn/blockchain" 32 "github.com/klaytn/klaytn/blockchain/state" 33 "github.com/klaytn/klaytn/blockchain/types" 34 "github.com/klaytn/klaytn/blockchain/vm" 35 "github.com/klaytn/klaytn/common" 36 "github.com/klaytn/klaytn/common/hexutil" 37 "github.com/klaytn/klaytn/common/math" 38 "github.com/klaytn/klaytn/crypto" 39 "github.com/klaytn/klaytn/crypto/sha3" 40 "github.com/klaytn/klaytn/params" 41 "github.com/klaytn/klaytn/rlp" 42 "github.com/klaytn/klaytn/storage/database" 43 ) 44 45 // StateTest checks transaction processing without block context. 46 // See https://github.com/ethereum/EIPs/issues/176 for the test format specification. 47 type StateTest struct { 48 json stJSON 49 } 50 51 // StateSubtest selects a specific configuration of a General State Test. 52 type StateSubtest struct { 53 Fork string 54 Index int 55 } 56 57 func (t *StateTest) UnmarshalJSON(in []byte) error { 58 return json.Unmarshal(in, &t.json) 59 } 60 61 type stJSON struct { 62 Env stEnv `json:"env"` 63 Pre blockchain.GenesisAlloc `json:"pre"` 64 Tx stTransaction `json:"transaction"` 65 Out hexutil.Bytes `json:"out"` 66 Post map[string][]stPostState `json:"post"` 67 } 68 69 type stPostState struct { 70 Root common.UnprefixedHash `json:"hash"` 71 Logs common.UnprefixedHash `json:"logs"` 72 Indexes struct { 73 Data int `json:"data"` 74 Gas int `json:"gas"` 75 Value int `json:"value"` 76 } 77 } 78 79 //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go 80 81 type stEnv struct { 82 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 83 BlockScore *big.Int `json:"currentDifficulty" gencodec:"required"` 84 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 85 Number uint64 `json:"currentNumber" gencodec:"required"` 86 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 87 } 88 89 type stEnvMarshaling struct { 90 Coinbase common.UnprefixedAddress 91 BlockScore *math.HexOrDecimal256 92 GasLimit math.HexOrDecimal64 93 Number math.HexOrDecimal64 94 Timestamp math.HexOrDecimal64 95 } 96 97 //go:generate gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go 98 99 type stTransaction struct { 100 GasPrice *big.Int `json:"gasPrice"` 101 Nonce uint64 `json:"nonce"` 102 To string `json:"to"` 103 Data []string `json:"data"` 104 GasLimit []uint64 `json:"gasLimit"` 105 Value []string `json:"value"` 106 PrivateKey []byte `json:"secretKey"` 107 } 108 109 type stTransactionMarshaling struct { 110 GasPrice *math.HexOrDecimal256 111 Nonce math.HexOrDecimal64 112 GasLimit []math.HexOrDecimal64 113 PrivateKey hexutil.Bytes 114 } 115 116 // getVMConfig takes a fork definition and returns a chain config. 117 // The fork definition can be 118 // - a plain forkname, e.g. `Byzantium`, 119 // - a fork basename, and a list of EIPs to enable; e.g. `Byzantium+1884+1283`. 120 func getVMConfig(forkString string) (baseConfig *params.ChainConfig, eips []int, err error) { 121 var ( 122 splitForks = strings.Split(forkString, "+") 123 ok bool 124 baseName, eipsStrings = splitForks[0], splitForks[1:] 125 ) 126 if baseConfig, ok = Forks[baseName]; !ok { 127 return nil, nil, UnsupportedForkError{baseName} 128 } 129 for _, eip := range eipsStrings { 130 if eipNum, err := strconv.Atoi(eip); err != nil { 131 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 132 } else { 133 eips = append(eips, eipNum) 134 } 135 } 136 return baseConfig, eips, nil 137 } 138 139 // Subtests returns all valid subtests of the test. 140 func (t *StateTest) Subtests() []StateSubtest { 141 var sub []StateSubtest 142 for fork, pss := range t.json.Post { 143 for i := range pss { 144 sub = append(sub, StateSubtest{fork, i}) 145 } 146 } 147 return sub 148 } 149 150 // Run executes a specific subtest. 151 func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config) (*state.StateDB, error) { 152 config, eips, err := getVMConfig(subtest.Fork) 153 if err != nil { 154 return nil, UnsupportedForkError{subtest.Fork} 155 } 156 vmconfig.ExtraEips = eips 157 blockchain.InitDeriveSha(config) 158 block := t.genesis(config).ToBlock(common.Hash{}, nil) 159 memDBManager := database.NewMemoryDBManager() 160 statedb := MakePreState(memDBManager, t.json.Pre) 161 162 post := t.json.Post[subtest.Fork][subtest.Index] 163 msg, err := t.json.Tx.toMessage(post, config.Rules(block.Number())) 164 if err != nil { 165 return nil, err 166 } 167 txContext := blockchain.NewEVMTxContext(msg, block.Header()) 168 blockContext := blockchain.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase) 169 blockContext.GetHash = vmTestBlockHash 170 evm := vm.NewEVM(blockContext, txContext, statedb, config, &vmconfig) 171 172 snapshot := statedb.Snapshot() 173 if _, err = blockchain.ApplyMessage(evm, msg); err != nil { 174 statedb.RevertToSnapshot(snapshot) 175 } 176 if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) { 177 return statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) 178 } 179 180 root, _ := statedb.Commit(true) 181 // Add 0-value mining reward. This only makes a difference in the cases 182 // where 183 // - the coinbase self-destructed, or 184 // - there are only 'bad' transactions, which aren't executed. In those cases, 185 // the coinbase gets no txfee, so isn't created, and thus needs to be touched 186 statedb.AddBalance(block.Rewardbase(), new(big.Int)) 187 // And _now_ get the state root 188 root = statedb.IntermediateRoot(true) 189 190 if root != common.Hash(post.Root) { 191 return statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) 192 } 193 return statedb, nil 194 } 195 196 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 197 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 198 } 199 200 func MakePreState(db database.DBManager, accounts blockchain.GenesisAlloc) *state.StateDB { 201 sdb := state.NewDatabase(db) 202 statedb, _ := state.New(common.Hash{}, sdb, nil, nil) 203 for addr, a := range accounts { 204 if len(a.Code) != 0 { 205 statedb.SetCode(addr, a.Code) 206 } 207 for k, v := range a.Storage { 208 statedb.SetState(addr, k, v) 209 } 210 statedb.SetNonce(addr, a.Nonce) 211 statedb.SetBalance(addr, a.Balance) 212 } 213 // Commit and re-open to start with a clean state. 214 root, _ := statedb.Commit(false) 215 statedb, _ = state.New(root, sdb, nil, nil) 216 return statedb 217 } 218 219 func (t *StateTest) genesis(config *params.ChainConfig) *blockchain.Genesis { 220 return &blockchain.Genesis{ 221 Config: config, 222 BlockScore: t.json.Env.BlockScore, 223 Number: t.json.Env.Number, 224 Timestamp: t.json.Env.Timestamp, 225 Alloc: t.json.Pre, 226 } 227 } 228 229 func (tx *stTransaction) toMessage(ps stPostState, r params.Rules) (blockchain.Message, error) { 230 // Derive sender from private key if present. 231 var from common.Address 232 if len(tx.PrivateKey) > 0 { 233 key, err := crypto.ToECDSA(tx.PrivateKey) 234 if err != nil { 235 return nil, fmt.Errorf("invalid private key: %v", err) 236 } 237 from = crypto.PubkeyToAddress(key.PublicKey) 238 } 239 // Parse recipient if present. 240 var to *common.Address 241 if tx.To != "" { 242 to = new(common.Address) 243 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 244 return nil, fmt.Errorf("invalid to address: %v", err) 245 } 246 } 247 248 // Get values specific to this post state. 249 if ps.Indexes.Data > len(tx.Data) { 250 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 251 } 252 if ps.Indexes.Value > len(tx.Value) { 253 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 254 } 255 if ps.Indexes.Gas > len(tx.GasLimit) { 256 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 257 } 258 dataHex := tx.Data[ps.Indexes.Data] 259 valueHex := tx.Value[ps.Indexes.Value] 260 gasLimit := tx.GasLimit[ps.Indexes.Gas] 261 // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203 262 value := new(big.Int) 263 if valueHex != "0x" { 264 v, ok := math.ParseBig256(valueHex) 265 if !ok { 266 return nil, fmt.Errorf("invalid tx value %q", valueHex) 267 } 268 value = v 269 } 270 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 271 if err != nil { 272 return nil, fmt.Errorf("invalid tx data %q", dataHex) 273 } 274 275 intrinsicGas, err := types.IntrinsicGas(data, nil, to == nil, r) 276 if err != nil { 277 return nil, err 278 } 279 280 msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, tx.GasPrice, data, true, intrinsicGas, nil) 281 return msg, nil 282 } 283 284 func rlpHash(x interface{}) (h common.Hash) { 285 hw := sha3.NewKeccak256() 286 rlp.Encode(hw, x) 287 hw.Sum(h[:0]) 288 return h 289 }