github.com/ethereum/go-ethereum@v1.16.1/tests/state_test_util.go (about) 1 // Copyright 2015 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 17 package tests 18 19 import ( 20 "encoding/hex" 21 "encoding/json" 22 "errors" 23 "fmt" 24 "math/big" 25 "strconv" 26 "strings" 27 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/common/hexutil" 30 "github.com/ethereum/go-ethereum/common/math" 31 "github.com/ethereum/go-ethereum/consensus" 32 "github.com/ethereum/go-ethereum/consensus/misc/eip4844" 33 "github.com/ethereum/go-ethereum/core" 34 "github.com/ethereum/go-ethereum/core/rawdb" 35 "github.com/ethereum/go-ethereum/core/state" 36 "github.com/ethereum/go-ethereum/core/state/snapshot" 37 "github.com/ethereum/go-ethereum/core/tracing" 38 "github.com/ethereum/go-ethereum/core/types" 39 "github.com/ethereum/go-ethereum/core/vm" 40 "github.com/ethereum/go-ethereum/crypto" 41 "github.com/ethereum/go-ethereum/ethdb" 42 "github.com/ethereum/go-ethereum/params" 43 "github.com/ethereum/go-ethereum/rlp" 44 "github.com/ethereum/go-ethereum/triedb" 45 "github.com/ethereum/go-ethereum/triedb/hashdb" 46 "github.com/ethereum/go-ethereum/triedb/pathdb" 47 "github.com/holiman/uint256" 48 "golang.org/x/crypto/sha3" 49 ) 50 51 // StateTest checks transaction processing without block context. 52 // See https://github.com/ethereum/EIPs/issues/176 for the test format specification. 53 type StateTest struct { 54 json stJSON 55 } 56 57 // StateSubtest selects a specific configuration of a General State Test. 58 type StateSubtest struct { 59 Fork string 60 Index int 61 } 62 63 func (t *StateTest) UnmarshalJSON(in []byte) error { 64 return json.Unmarshal(in, &t.json) 65 } 66 67 type stJSON struct { 68 Env stEnv `json:"env"` 69 Pre types.GenesisAlloc `json:"pre"` 70 Tx stTransaction `json:"transaction"` 71 Out hexutil.Bytes `json:"out"` 72 Post map[string][]stPostState `json:"post"` 73 } 74 75 type stPostState struct { 76 Root common.UnprefixedHash `json:"hash"` 77 Logs common.UnprefixedHash `json:"logs"` 78 TxBytes hexutil.Bytes `json:"txbytes"` 79 ExpectException string `json:"expectException"` 80 Indexes struct { 81 Data int `json:"data"` 82 Gas int `json:"gas"` 83 Value int `json:"value"` 84 } 85 } 86 87 //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go 88 89 type stEnv struct { 90 Coinbase common.Address `json:"currentCoinbase" gencodec:"required"` 91 Difficulty *big.Int `json:"currentDifficulty" gencodec:"optional"` 92 Random *big.Int `json:"currentRandom" gencodec:"optional"` 93 GasLimit uint64 `json:"currentGasLimit" gencodec:"required"` 94 Number uint64 `json:"currentNumber" gencodec:"required"` 95 Timestamp uint64 `json:"currentTimestamp" gencodec:"required"` 96 BaseFee *big.Int `json:"currentBaseFee" gencodec:"optional"` 97 ExcessBlobGas *uint64 `json:"currentExcessBlobGas" gencodec:"optional"` 98 } 99 100 type stEnvMarshaling struct { 101 Coinbase common.UnprefixedAddress 102 Difficulty *math.HexOrDecimal256 103 Random *math.HexOrDecimal256 104 GasLimit math.HexOrDecimal64 105 Number math.HexOrDecimal64 106 Timestamp math.HexOrDecimal64 107 BaseFee *math.HexOrDecimal256 108 ExcessBlobGas *math.HexOrDecimal64 109 } 110 111 //go:generate go run github.com/fjl/gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go 112 113 type stTransaction struct { 114 GasPrice *big.Int `json:"gasPrice"` 115 MaxFeePerGas *big.Int `json:"maxFeePerGas"` 116 MaxPriorityFeePerGas *big.Int `json:"maxPriorityFeePerGas"` 117 Nonce uint64 `json:"nonce"` 118 To string `json:"to"` 119 Data []string `json:"data"` 120 AccessLists []*types.AccessList `json:"accessLists,omitempty"` 121 GasLimit []uint64 `json:"gasLimit"` 122 Value []string `json:"value"` 123 PrivateKey []byte `json:"secretKey"` 124 Sender *common.Address `json:"sender"` 125 BlobVersionedHashes []common.Hash `json:"blobVersionedHashes,omitempty"` 126 BlobGasFeeCap *big.Int `json:"maxFeePerBlobGas,omitempty"` 127 AuthorizationList []*stAuthorization `json:"authorizationList,omitempty"` 128 } 129 130 type stTransactionMarshaling struct { 131 GasPrice *math.HexOrDecimal256 132 MaxFeePerGas *math.HexOrDecimal256 133 MaxPriorityFeePerGas *math.HexOrDecimal256 134 Nonce math.HexOrDecimal64 135 GasLimit []math.HexOrDecimal64 136 PrivateKey hexutil.Bytes 137 BlobGasFeeCap *math.HexOrDecimal256 138 } 139 140 //go:generate go run github.com/fjl/gencodec -type stAuthorization -field-override stAuthorizationMarshaling -out gen_stauthorization.go 141 142 // Authorization is an authorization from an account to deploy code at it's address. 143 type stAuthorization struct { 144 ChainID *big.Int `json:"chainId" gencodec:"required"` 145 Address common.Address `json:"address" gencodec:"required"` 146 Nonce uint64 `json:"nonce" gencodec:"required"` 147 V uint8 `json:"v" gencodec:"required"` 148 R *big.Int `json:"r" gencodec:"required"` 149 S *big.Int `json:"s" gencodec:"required"` 150 } 151 152 // field type overrides for gencodec 153 type stAuthorizationMarshaling struct { 154 ChainID *math.HexOrDecimal256 155 Nonce math.HexOrDecimal64 156 V math.HexOrDecimal64 157 R *math.HexOrDecimal256 158 S *math.HexOrDecimal256 159 } 160 161 // GetChainConfig takes a fork definition and returns a chain config. 162 // The fork definition can be 163 // - a plain forkname, e.g. `Byzantium`, 164 // - a fork basename, and a list of EIPs to enable; e.g. `Byzantium+1884+1283`. 165 func GetChainConfig(forkString string) (baseConfig *params.ChainConfig, eips []int, err error) { 166 var ( 167 splitForks = strings.Split(forkString, "+") 168 ok bool 169 baseName, eipsStrings = splitForks[0], splitForks[1:] 170 ) 171 if baseConfig, ok = Forks[baseName]; !ok { 172 return nil, nil, UnsupportedForkError{baseName} 173 } 174 for _, eip := range eipsStrings { 175 if eipNum, err := strconv.Atoi(eip); err != nil { 176 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 177 } else { 178 if !vm.ValidEip(eipNum) { 179 return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum) 180 } 181 eips = append(eips, eipNum) 182 } 183 } 184 return baseConfig, eips, nil 185 } 186 187 // Subtests returns all valid subtests of the test. 188 func (t *StateTest) Subtests() []StateSubtest { 189 var sub []StateSubtest 190 for fork, pss := range t.json.Post { 191 for i := range pss { 192 sub = append(sub, StateSubtest{fork, i}) 193 } 194 } 195 return sub 196 } 197 198 // checkError checks if the error returned by the state transition matches any expected error. 199 // A failing expectation returns a wrapped version of the original error, if any, 200 // or a new error detailing the failing expectation. 201 // This function does not return or modify the original error, it only evaluates and returns expectations for the error. 202 func (t *StateTest) checkError(subtest StateSubtest, err error) error { 203 expectedError := t.json.Post[subtest.Fork][subtest.Index].ExpectException 204 if err == nil && expectedError == "" { 205 return nil 206 } 207 if err == nil && expectedError != "" { 208 return fmt.Errorf("expected error %q, got no error", expectedError) 209 } 210 if err != nil && expectedError == "" { 211 return fmt.Errorf("unexpected error: %w", err) 212 } 213 if err != nil && expectedError != "" { 214 // Ignore expected errors (TODO MariusVanDerWijden check error string) 215 return nil 216 } 217 return nil 218 } 219 220 // Run executes a specific subtest and verifies the post-state and logs 221 func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string, postCheck func(err error, st *StateTestState)) (result error) { 222 st, root, _, err := t.RunNoVerify(subtest, vmconfig, snapshotter, scheme) 223 // Invoke the callback at the end of function for further analysis. 224 defer func() { 225 postCheck(result, &st) 226 st.Close() 227 }() 228 229 checkedErr := t.checkError(subtest, err) 230 if checkedErr != nil { 231 return checkedErr 232 } 233 // The error has been checked; if it was unexpected, it's already returned. 234 if err != nil { 235 // Here, an error exists but it was expected. 236 // We do not check the post state or logs. 237 return nil 238 } 239 post := t.json.Post[subtest.Fork][subtest.Index] 240 // N.B: We need to do this in a two-step process, because the first Commit takes care 241 // of self-destructs, and we need to touch the coinbase _after_ it has potentially self-destructed. 242 if root != common.Hash(post.Root) { 243 return fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root) 244 } 245 if logs := rlpHash(st.StateDB.Logs()); logs != common.Hash(post.Logs) { 246 return fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs) 247 } 248 st.StateDB, _ = state.New(root, st.StateDB.Database()) 249 return nil 250 } 251 252 // RunNoVerify runs a specific subtest and returns the statedb and post-state root. 253 // Remember to call state.Close after verifying the test result! 254 func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool, scheme string) (st StateTestState, root common.Hash, gasUsed uint64, err error) { 255 config, eips, err := GetChainConfig(subtest.Fork) 256 if err != nil { 257 return st, common.Hash{}, 0, UnsupportedForkError{subtest.Fork} 258 } 259 vmconfig.ExtraEips = eips 260 261 block := t.genesis(config).ToBlock() 262 st = MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter, scheme) 263 264 var baseFee *big.Int 265 if config.IsLondon(new(big.Int)) { 266 baseFee = t.json.Env.BaseFee 267 if baseFee == nil { 268 // Retesteth uses `0x10` for genesis baseFee. Therefore, it defaults to 269 // parent - 2 : 0xa as the basefee for 'this' context. 270 baseFee = big.NewInt(0x0a) 271 } 272 } 273 post := t.json.Post[subtest.Fork][subtest.Index] 274 msg, err := t.json.Tx.toMessage(post, baseFee) 275 if err != nil { 276 return st, common.Hash{}, 0, err 277 } 278 279 // Blob transactions may be present after the Cancun fork. 280 // In production, 281 // - the header is verified against the max in eip4844.go:VerifyEIP4844Header 282 // - the block body is verified against the header in block_validator.go:ValidateBody 283 // Here, we just do this shortcut smaller fix, since state tests do not 284 // utilize those codepaths. 285 if config.IsCancun(new(big.Int), block.Time()) { 286 if len(msg.BlobHashes) > eip4844.MaxBlobsPerBlock(config, block.Time()) { 287 return st, common.Hash{}, 0, errors.New("blob gas exceeds maximum") 288 } 289 } 290 291 // Try to recover tx with current signer 292 if len(post.TxBytes) != 0 { 293 var ttx types.Transaction 294 err := ttx.UnmarshalBinary(post.TxBytes) 295 if err != nil { 296 return st, common.Hash{}, 0, err 297 } 298 if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil { 299 return st, common.Hash{}, 0, err 300 } 301 } 302 303 // Prepare the EVM. 304 context := core.NewEVMBlockContext(block.Header(), &dummyChain{config: config}, &t.json.Env.Coinbase) 305 context.GetHash = vmTestBlockHash 306 context.BaseFee = baseFee 307 context.Random = nil 308 if t.json.Env.Difficulty != nil { 309 context.Difficulty = new(big.Int).Set(t.json.Env.Difficulty) 310 } 311 if config.IsLondon(new(big.Int)) && t.json.Env.Random != nil { 312 rnd := common.BigToHash(t.json.Env.Random) 313 context.Random = &rnd 314 context.Difficulty = big.NewInt(0) 315 } 316 if config.IsCancun(new(big.Int), block.Time()) && t.json.Env.ExcessBlobGas != nil { 317 header := &types.Header{ 318 Time: block.Time(), 319 ExcessBlobGas: t.json.Env.ExcessBlobGas, 320 } 321 context.BlobBaseFee = eip4844.CalcBlobFee(config, header) 322 } 323 324 evm := vm.NewEVM(context, st.StateDB, config, vmconfig) 325 326 if tracer := vmconfig.Tracer; tracer != nil && tracer.OnTxStart != nil { 327 tracer.OnTxStart(evm.GetVMContext(), nil, msg.From) 328 } 329 // Execute the message. 330 snapshot := st.StateDB.Snapshot() 331 gaspool := new(core.GasPool) 332 gaspool.AddGas(block.GasLimit()) 333 vmRet, err := core.ApplyMessage(evm, msg, gaspool) 334 if err != nil { 335 st.StateDB.RevertToSnapshot(snapshot) 336 if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { 337 evm.Config.Tracer.OnTxEnd(nil, err) 338 } 339 return st, common.Hash{}, 0, err 340 } 341 // Add 0-value mining reward. This only makes a difference in the cases 342 // where 343 // - the coinbase self-destructed, or 344 // - there are only 'bad' transactions, which aren't executed. In those cases, 345 // the coinbase gets no txfee, so isn't created, and thus needs to be touched 346 st.StateDB.AddBalance(block.Coinbase(), new(uint256.Int), tracing.BalanceChangeUnspecified) 347 348 // Commit state mutations into database. 349 root, _ = st.StateDB.Commit(block.NumberU64(), config.IsEIP158(block.Number()), config.IsCancun(block.Number(), block.Time())) 350 if tracer := evm.Config.Tracer; tracer != nil && tracer.OnTxEnd != nil { 351 receipt := &types.Receipt{GasUsed: vmRet.UsedGas} 352 tracer.OnTxEnd(receipt, nil) 353 } 354 return st, root, vmRet.UsedGas, nil 355 } 356 357 func (t *StateTest) gasLimit(subtest StateSubtest) uint64 { 358 return t.json.Tx.GasLimit[t.json.Post[subtest.Fork][subtest.Index].Indexes.Gas] 359 } 360 361 func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis { 362 genesis := &core.Genesis{ 363 Config: config, 364 Coinbase: t.json.Env.Coinbase, 365 Difficulty: t.json.Env.Difficulty, 366 GasLimit: t.json.Env.GasLimit, 367 Number: t.json.Env.Number, 368 Timestamp: t.json.Env.Timestamp, 369 Alloc: t.json.Pre, 370 } 371 if t.json.Env.Random != nil { 372 // Post-Merge 373 genesis.Mixhash = common.BigToHash(t.json.Env.Random) 374 genesis.Difficulty = big.NewInt(0) 375 } 376 return genesis 377 } 378 379 func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Message, error) { 380 var from common.Address 381 // If 'sender' field is present, use that 382 if tx.Sender != nil { 383 from = *tx.Sender 384 } else if len(tx.PrivateKey) > 0 { 385 // Derive sender from private key if needed. 386 key, err := crypto.ToECDSA(tx.PrivateKey) 387 if err != nil { 388 return nil, fmt.Errorf("invalid private key: %v", err) 389 } 390 from = crypto.PubkeyToAddress(key.PublicKey) 391 } 392 // Parse recipient if present. 393 var to *common.Address 394 if tx.To != "" { 395 to = new(common.Address) 396 if err := to.UnmarshalText([]byte(tx.To)); err != nil { 397 return nil, fmt.Errorf("invalid to address: %v", err) 398 } 399 } 400 401 // Get values specific to this post state. 402 if ps.Indexes.Data > len(tx.Data) { 403 return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data) 404 } 405 if ps.Indexes.Value > len(tx.Value) { 406 return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value) 407 } 408 if ps.Indexes.Gas > len(tx.GasLimit) { 409 return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas) 410 } 411 dataHex := tx.Data[ps.Indexes.Data] 412 valueHex := tx.Value[ps.Indexes.Value] 413 gasLimit := tx.GasLimit[ps.Indexes.Gas] 414 // Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203 415 value := new(big.Int) 416 if valueHex != "0x" { 417 v, ok := math.ParseBig256(valueHex) 418 if !ok { 419 return nil, fmt.Errorf("invalid tx value %q", valueHex) 420 } 421 value = v 422 } 423 data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x")) 424 if err != nil { 425 return nil, fmt.Errorf("invalid tx data %q", dataHex) 426 } 427 var accessList types.AccessList 428 if tx.AccessLists != nil && tx.AccessLists[ps.Indexes.Data] != nil { 429 accessList = *tx.AccessLists[ps.Indexes.Data] 430 } 431 // If baseFee provided, set gasPrice to effectiveGasPrice. 432 gasPrice := tx.GasPrice 433 if baseFee != nil { 434 if tx.MaxFeePerGas == nil { 435 tx.MaxFeePerGas = gasPrice 436 } 437 if tx.MaxFeePerGas == nil { 438 tx.MaxFeePerGas = new(big.Int) 439 } 440 if tx.MaxPriorityFeePerGas == nil { 441 tx.MaxPriorityFeePerGas = tx.MaxFeePerGas 442 } 443 gasPrice = new(big.Int).Add(tx.MaxPriorityFeePerGas, baseFee) 444 if gasPrice.Cmp(tx.MaxFeePerGas) > 0 { 445 gasPrice = tx.MaxFeePerGas 446 } 447 } 448 if gasPrice == nil { 449 return nil, errors.New("no gas price provided") 450 } 451 var authList []types.SetCodeAuthorization 452 if tx.AuthorizationList != nil { 453 authList = make([]types.SetCodeAuthorization, len(tx.AuthorizationList)) 454 for i, auth := range tx.AuthorizationList { 455 authList[i] = types.SetCodeAuthorization{ 456 ChainID: *uint256.MustFromBig(auth.ChainID), 457 Address: auth.Address, 458 Nonce: auth.Nonce, 459 V: auth.V, 460 R: *uint256.MustFromBig(auth.R), 461 S: *uint256.MustFromBig(auth.S), 462 } 463 } 464 } 465 466 msg := &core.Message{ 467 From: from, 468 To: to, 469 Nonce: tx.Nonce, 470 Value: value, 471 GasLimit: gasLimit, 472 GasPrice: gasPrice, 473 GasFeeCap: tx.MaxFeePerGas, 474 GasTipCap: tx.MaxPriorityFeePerGas, 475 Data: data, 476 AccessList: accessList, 477 BlobHashes: tx.BlobVersionedHashes, 478 BlobGasFeeCap: tx.BlobGasFeeCap, 479 SetCodeAuthorizations: authList, 480 } 481 return msg, nil 482 } 483 484 func rlpHash(x interface{}) (h common.Hash) { 485 hw := sha3.NewLegacyKeccak256() 486 rlp.Encode(hw, x) 487 hw.Sum(h[:0]) 488 return h 489 } 490 491 func vmTestBlockHash(n uint64) common.Hash { 492 return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String()))) 493 } 494 495 // StateTestState groups all the state database objects together for use in tests. 496 type StateTestState struct { 497 StateDB *state.StateDB 498 TrieDB *triedb.Database 499 Snapshots *snapshot.Tree 500 } 501 502 // MakePreState creates a state containing the given allocation. 503 func MakePreState(db ethdb.Database, accounts types.GenesisAlloc, snapshotter bool, scheme string) StateTestState { 504 tconf := &triedb.Config{Preimages: true} 505 if scheme == rawdb.HashScheme { 506 tconf.HashDB = hashdb.Defaults 507 } else { 508 tconf.PathDB = pathdb.Defaults 509 } 510 triedb := triedb.NewDatabase(db, tconf) 511 sdb := state.NewDatabase(triedb, nil) 512 statedb, _ := state.New(types.EmptyRootHash, sdb) 513 for addr, a := range accounts { 514 statedb.SetCode(addr, a.Code) 515 statedb.SetNonce(addr, a.Nonce, tracing.NonceChangeUnspecified) 516 statedb.SetBalance(addr, uint256.MustFromBig(a.Balance), tracing.BalanceChangeUnspecified) 517 for k, v := range a.Storage { 518 statedb.SetState(addr, k, v) 519 } 520 } 521 // Commit and re-open to start with a clean state. 522 root, _ := statedb.Commit(0, false, false) 523 524 // If snapshot is requested, initialize the snapshotter and use it in state. 525 var snaps *snapshot.Tree 526 if snapshotter { 527 snapconfig := snapshot.Config{ 528 CacheSize: 1, 529 Recovery: false, 530 NoBuild: false, 531 AsyncBuild: false, 532 } 533 snaps, _ = snapshot.New(snapconfig, db, triedb, root) 534 } 535 sdb = state.NewDatabase(triedb, snaps) 536 statedb, _ = state.New(root, sdb) 537 return StateTestState{statedb, triedb, snaps} 538 } 539 540 // Close should be called when the state is no longer needed, ie. after running the test. 541 func (st *StateTestState) Close() { 542 if st.TrieDB != nil { 543 st.TrieDB.Close() 544 st.TrieDB = nil 545 } 546 if st.Snapshots != nil { 547 // Need to call Disable here to quit the snapshot generator goroutine. 548 st.Snapshots.Disable() 549 st.Snapshots.Release() 550 st.Snapshots = nil 551 } 552 } 553 554 // dummyChain implements the core.ChainContext interface. 555 type dummyChain struct { 556 config *params.ChainConfig 557 } 558 559 func (d *dummyChain) Engine() consensus.Engine { return nil } 560 func (d *dummyChain) GetHeader(h common.Hash, n uint64) *types.Header { return nil } 561 func (d *dummyChain) Config() *params.ChainConfig { return d.config }