github.com/MetalBlockchain/subnet-evm@v0.4.9/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/MetalBlockchain/subnet-evm/core" 38 "github.com/MetalBlockchain/subnet-evm/core/state" 39 "github.com/MetalBlockchain/subnet-evm/core/state/snapshot" 40 "github.com/MetalBlockchain/subnet-evm/core/types" 41 "github.com/MetalBlockchain/subnet-evm/core/vm" 42 "github.com/MetalBlockchain/subnet-evm/ethdb" 43 "github.com/MetalBlockchain/subnet-evm/params" 44 "github.com/ethereum/go-ethereum/common" 45 "github.com/ethereum/go-ethereum/common/hexutil" 46 "github.com/ethereum/go-ethereum/common/math" 47 "github.com/ethereum/go-ethereum/crypto" 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 go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go 87 type stEnv struct { 88 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 89 Difficulty *big.Int `json:"currentDifficulty" gencodec:"required"` 90 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 91 Number uint64 `json:"currentNumber" gencodec:"required"` 92 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 93 BaseFee *big.Int `json:"currentBaseFee" gencodec:"optional"` 94 } 95 96 //go:generate go run github.com/fjl/gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go 97 type stTransaction struct { 98 GasPrice *big.Int `json:"gasPrice"` 99 MaxFeePerGas *big.Int `json:"maxFeePerGas"` 100 MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas"` 101 Nonce uint64 `json:"nonce"` 102 To string `json:"to"` 103 Data []string `json:"data"` 104 AccessLists []*types.AccessList `json:"accessLists,omitempty"` 105 GasLimit []uint64 `json:"gasLimit"` 106 Value []string `json:"value"` 107 PrivateKey []byte `json:"secretKey"` 108 } 109 110 // GetChainConfig takes a fork definition and returns a chain config. 111 // The fork definition can be 112 // - a plain forkname, e.g. `Byzantium`, 113 // - a fork basename, and a list of EIPs to enable; e.g. `Byzantium+1884+1283`. 114 func GetChainConfig(forkString string) (baseConfig *params.ChainConfig, eips []int, err error) { 115 var ( 116 splitForks = strings.Split(forkString, "+") 117 ok bool 118 baseName, eipsStrings = splitForks[0], splitForks[1:] 119 ) 120 if baseConfig, ok = Forks[baseName]; !ok { 121 return nil, nil, UnsupportedForkError{baseName} 122 } 123 for _, eip := range eipsStrings { 124 if eipNum, err := strconv.Atoi(eip); err != nil { 125 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 126 } else { 127 if !vm.ValidEip(eipNum) { 128 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 129 } 130 eips = append(eips, eipNum) 131 } 132 } 133 return baseConfig, eips, nil 134 } 135 136 // Subtests returns all valid subtests of the test. 137 func (t *StateTest) Subtests() []StateSubtest { 138 var sub []StateSubtest 139 for fork, pss := range t.json.Post { 140 for i := range pss { 141 sub = append(sub, StateSubtest{fork, i}) 142 } 143 } 144 return sub 145 } 146 147 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 148 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 149 } 150 151 func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) { 152 sdb := state.NewDatabase(db) 153 statedb, _ := state.New(common.Hash{}, sdb, nil) 154 for addr, a := range accounts { 155 statedb.SetCode(addr, a.Code) 156 statedb.SetNonce(addr, a.Nonce) 157 statedb.SetBalance(addr, a.Balance) 158 for k, v := range a.Storage { 159 statedb.SetState(addr, k, v) 160 } 161 } 162 // Commit and re-open to start with a clean state. 163 root, _ := statedb.Commit(false, false) 164 165 var snaps *snapshot.Tree 166 if snapshotter { 167 snaps, _ = snapshot.New(db, sdb.TrieDB(), 1, common.Hash{}, root, false, true, false) 168 } 169 statedb, _ = state.New(root, sdb, snaps) 170 return snaps, statedb 171 } 172 173 func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { 174 return &core.Genesis{ 175 Config: config, 176 Coinbase: t.json.Env.Coinbase, 177 Difficulty: t.json.Env.Difficulty, 178 GasLimit: t.json.Env.GasLimit, 179 Number: t.json.Env.Number, 180 Timestamp: t.json.Env.Timestamp, 181 Alloc: t.json.Pre, 182 } 183 } 184 185 func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (core.Message, error) { 186 // Derive sender from private key if present. 187 var from common.Address 188 if len(tx.PrivateKey) > 0 { 189 key, err := crypto.ToECDSA(tx.PrivateKey) 190 if err != nil { 191 return nil, fmt.Errorf("invalid private key: %v", err) 192 } 193 from = crypto.PubkeyToAddress(key.PublicKey) 194 } 195 // Parse recipient if present. 196 var to *common.Address 197 if tx.To != "" { 198 to = new(common.Address) 199 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 200 return nil, fmt.Errorf("invalid to address: %v", err) 201 } 202 } 203 204 // Get values specific to this post state. 205 if ps.Indexes.Data > len(tx.Data) { 206 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 207 } 208 if ps.Indexes.Value > len(tx.Value) { 209 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 210 } 211 if ps.Indexes.Gas > len(tx.GasLimit) { 212 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 213 } 214 dataHex := tx.Data[ps.Indexes.Data] 215 valueHex := tx.Value[ps.Indexes.Value] 216 gasLimit := tx.GasLimit[ps.Indexes.Gas] 217 // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203 218 value := new(big.Int) 219 if valueHex != "0x" { 220 v, ok := math.ParseBig256(valueHex) 221 if !ok { 222 return nil, fmt.Errorf("invalid tx value %q", valueHex) 223 } 224 value = v 225 } 226 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 227 if err != nil { 228 return nil, fmt.Errorf("invalid tx data %q", dataHex) 229 } 230 var accessList types.AccessList 231 if tx.AccessLists != nil && tx.AccessLists[ps.Indexes.Data] != nil { 232 accessList = *tx.AccessLists[ps.Indexes.Data] 233 } 234 // If baseFee provided, set gasPrice to effectiveGasPrice. 235 gasPrice := tx.GasPrice 236 if baseFee != nil { 237 if tx.MaxFeePerGas == nil { 238 tx.MaxFeePerGas = gasPrice 239 } 240 if tx.MaxFeePerGas == nil { 241 tx.MaxFeePerGas = new(big.Int) 242 } 243 if tx.MaxPriorityFeePerGas == nil { 244 tx.MaxPriorityFeePerGas = tx.MaxFeePerGas 245 } 246 gasPrice = math.BigMin(new(big.Int).Add(tx.MaxPriorityFeePerGas, baseFee), 247 tx.MaxFeePerGas) 248 } 249 if gasPrice == nil { 250 return nil, fmt.Errorf("no gas price provided") 251 } 252 253 msg := types.NewMessage(from, to, tx.Nonce, value, gasLimit, gasPrice, 254 tx.MaxFeePerGas, tx.MaxPriorityFeePerGas, data, accessList, false) 255 return msg, nil 256 }