gitlab.com/flarenetwork/coreth@v0.1.1/tests/state_test_util.go (about) 1 // (c) 2019-2020, Ava Labs, Inc. 2 // 3 // This file is a derived work, based on the go-ethereum library whose original 4 // notices appear below. 5 // 6 // It is distributed under a license compatible with the licensing terms of the 7 // original code from which it is derived. 8 // 9 // Much love to the original authors for their work. 10 // ********** 11 // Copyright 2015 The go-ethereum Authors 12 // This file is part of the go-ethereum library. 13 // 14 // The go-ethereum library is free software: you can redistribute it and/or modify 15 // it under the terms of the GNU Lesser General Public License as published by 16 // the Free Software Foundation, either version 3 of the License, or 17 // (at your option) any later version. 18 // 19 // The go-ethereum library is distributed in the hope that it will be useful, 20 // but WITHOUT ANY WARRANTY; without even the implied warranty of 21 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 // GNU Lesser General Public License for more details. 23 // 24 // You should have received a copy of the GNU Lesser General Public License 25 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 26 27 package tests 28 29 import ( 30 "encoding/hex" 31 "encoding/json" 32 "fmt" 33 "math/big" 34 "strconv" 35 "strings" 36 37 "github.com/ethereum/go-ethereum/common" 38 "github.com/ethereum/go-ethereum/common/hexutil" 39 "github.com/ethereum/go-ethereum/common/math" 40 "github.com/ethereum/go-ethereum/crypto" 41 "github.com/ethereum/go-ethereum/ethdb" 42 "gitlab.com/flarenetwork/coreth/core" 43 "gitlab.com/flarenetwork/coreth/core/state" 44 "gitlab.com/flarenetwork/coreth/core/state/snapshot" 45 "gitlab.com/flarenetwork/coreth/core/types" 46 "gitlab.com/flarenetwork/coreth/core/vm" 47 "gitlab.com/flarenetwork/coreth/params" 48 ) 49 50 // StateTest checks transaction processing without block context. 51 // See https://github.com/ethereum/EIPs/issues/176 for the test format specification. 52 type StateTest struct { 53 json stJSON 54 } 55 56 // StateSubtest selects a specific configuration of a General State Test. 57 type StateSubtest struct { 58 Fork string 59 Index int 60 } 61 62 func (t *StateTest) UnmarshalJSON(in []byte) error { 63 return json.Unmarshal(in, &t.json) 64 } 65 66 type stJSON struct { 67 Env stEnv `json:"env"` 68 Pre core.GenesisAlloc `json:"pre"` 69 Tx stTransaction `json:"transaction"` 70 Out hexutil.Bytes `json:"out"` 71 Post map[string][]stPostState `json:"post"` 72 } 73 74 type stPostState struct { 75 Root common.UnprefixedHash `json:"hash"` 76 Logs common.UnprefixedHash `json:"logs"` 77 TxBytes hexutil.Bytes `json:"txbytes"` 78 ExpectException string `json:"expectException"` 79 Indexes struct { 80 Data int `json:"data"` 81 Gas int `json:"gas"` 82 Value int `json:"value"` 83 } 84 } 85 86 //go:generate gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go 87 88 type stEnv struct { 89 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 90 Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"` 91 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 92 Number uint64 `json:"currentNumber" gencodec:"required"` 93 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 94 BaseFee *big.Int `json:"currentBaseFee" gencodec:"optional"` 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 MaxFeePerGas *big.Int `json:"maxFeePerGas"` 102 MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas"` 103 Nonce uint64 `json:"nonce"` 104 To string `json:"to"` 105 Data []string `json:"data"` 106 AccessLists []*types.AccessList `json:"accessLists,omitempty"` 107 GasLimit []uint64 `json:"gasLimit"` 108 Value []string `json:"value"` 109 PrivateKey []byte `json:"secretKey"` 110 } 111 112 // GetChainConfig takes a fork definition and returns a chain config. 113 // The fork definition can be 114 // - a plain forkname, e.g. `Byzantium`, 115 // - a fork basename, and a list of EIPs to enable; e.g. `Byzantium+1884+1283`. 116 func GetChainConfig(forkString string) (baseConfig *params.ChainConfig, eips []int, err error) { 117 var ( 118 splitForks = strings.Split(forkString, "+") 119 ok bool 120 baseName, eipsStrings = splitForks[0], splitForks[1:] 121 ) 122 if baseConfig, ok = Forks[baseName]; !ok { 123 return nil, nil, UnsupportedForkError{baseName} 124 } 125 for _, eip := range eipsStrings { 126 if eipNum, err := strconv.Atoi(eip); err != nil { 127 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 128 } else { 129 if !vm.ValidEip(eipNum) { 130 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 131 } 132 eips = append(eips, eipNum) 133 } 134 } 135 return baseConfig, eips, nil 136 } 137 138 // Subtests returns all valid subtests of the test. 139 func (t *StateTest) Subtests() []StateSubtest { 140 var sub []StateSubtest 141 for fork, pss := range t.json.Post { 142 for i := range pss { 143 sub = append(sub, StateSubtest{fork, i}) 144 } 145 } 146 return sub 147 } 148 149 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 150 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 151 } 152 153 func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) { 154 sdb := state.NewDatabase(db) 155 statedb, _ := state.New(common.Hash{}, sdb, nil) 156 for addr, a := range accounts { 157 statedb.SetCode(addr, a.Code) 158 statedb.SetNonce(addr, a.Nonce) 159 statedb.SetBalance(addr, a.Balance) 160 for k, v := range a.Storage { 161 statedb.SetState(addr, k, v) 162 } 163 } 164 // Commit and re-open to start with a clean state. 165 root, _ := statedb.Commit(false) 166 167 var snaps *snapshot.Tree 168 if snapshotter { 169 snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, common.Hash{}, root, false, true, false) 170 } 171 statedb, _ = state.New(root, sdb, snaps) 172 return snaps, statedb 173 } 174 175 func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { 176 return &core.Genesis{ 177 Config: config, 178 Coinbase: t.json.Env.Coinbase, 179 Difficulty: t.json.Env.Difficulty, 180 GasLimit: t.json.Env.GasLimit, 181 Number: t.json.Env.Number, 182 Timestamp: t.json.Env.Timestamp, 183 Alloc: t.json.Pre, 184 } 185 } 186 187 func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Message, error) { 188 // Derive sender from private key if present. 189 var from common.Address 190 if len(tx.PrivateKey) > 0 { 191 key, err := crypto.ToECDSA(tx.PrivateKey) 192 if err != nil { 193 return nil, fmt.Errorf("invalid private key: %v", err) 194 } 195 from = crypto.PubkeyToAddress(key.PublicKey) 196 } 197 // Parse recipient if present. 198 var to *common.Address 199 if tx.To != "" { 200 to = new(common.Address) 201 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 202 return nil, fmt.Errorf("invalid to address: %v", err) 203 } 204 } 205 206 // Get values specific to this post state. 207 if ps.Indexes.Data > len(tx.Data) { 208 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 209 } 210 if ps.Indexes.Value > len(tx.Value) { 211 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 212 } 213 if ps.Indexes.Gas > len(tx.GasLimit) { 214 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 215 } 216 dataHex := tx.Data[ps.Indexes.Data] 217 valueHex := tx.Value[ps.Indexes.Value] 218 gasLimit := tx.GasLimit[ps.Indexes.Gas] 219 // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203 220 value := new(big.Int) 221 if valueHex != "0x" { 222 v, ok := math.ParseBig256(valueHex) 223 if !ok { 224 return nil, fmt.Errorf("invalid tx value %q", valueHex) 225 } 226 value = v 227 } 228 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 229 if err != nil { 230 return nil, fmt.Errorf("invalid tx data %q", dataHex) 231 } 232 var accessList types.AccessList 233 if tx.AccessLists != nil && tx.AccessLists[ps.Indexes.Data] != nil { 234 accessList = *tx.AccessLists[ps.Indexes.Data] 235 } 236 // If baseFee provided, set gasPrice to effectiveGasPrice. 237 gasPrice := tx.GasPrice 238 if baseFee != nil { 239 if tx.MaxFeePerGas == nil { 240 tx.MaxFeePerGas = gasPrice 241 } 242 if tx.MaxFeePerGas == nil { 243 tx.MaxFeePerGas = new(big.Int) 244 } 245 if tx.MaxPriorityFeePerGas == nil { 246 tx.MaxPriorityFeePerGas = tx.MaxFeePerGas 247 } 248 gasPrice = math.BigMin(new(big.Int).Add(tx.MaxPriorityFeePerGas, baseFee), 249 tx.MaxFeePerGas) 250 } 251 if gasPrice == nil { 252 return nil, fmt.Errorf("no gas price provided") 253 } 254 255 msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice, 256 tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false) 257 return msg, nil 258 }