github.com/MetalBlockchain/subnet-evm@v0.6.3/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  	"errors"
    33  	"fmt"
    34  	"math/big"
    35  	"strconv"
    36  	"strings"
    37  
    38  	"github.com/MetalBlockchain/subnet-evm/core"
    39  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    40  	"github.com/MetalBlockchain/subnet-evm/core/state"
    41  	"github.com/MetalBlockchain/subnet-evm/core/state/snapshot"
    42  	"github.com/MetalBlockchain/subnet-evm/core/types"
    43  	"github.com/MetalBlockchain/subnet-evm/core/vm"
    44  	"github.com/MetalBlockchain/subnet-evm/params"
    45  	"github.com/MetalBlockchain/subnet-evm/trie"
    46  	"github.com/ethereum/go-ethereum/common"
    47  	"github.com/ethereum/go-ethereum/common/hexutil"
    48  	"github.com/ethereum/go-ethereum/common/math"
    49  	"github.com/ethereum/go-ethereum/crypto"
    50  	"github.com/ethereum/go-ethereum/ethdb"
    51  	"github.com/ethereum/go-ethereum/rlp"
    52  	"golang.org/x/crypto/sha3"
    53  )
    54  
    55  // StateTest checks transaction processing without block context.
    56  // See https://github.com/ethereum/EIPs/issues/176 for the test format specification.
    57  type StateTest struct {
    58  	json stJSON
    59  }
    60  
    61  // StateSubtest selects a specific configuration of a General State Test.
    62  type StateSubtest struct {
    63  	Fork  string
    64  	Index int
    65  }
    66  
    67  func (t *StateTest) UnmarshalJSON(in []byte) error {
    68  	return json.Unmarshal(in, &t.json)
    69  }
    70  
    71  type stJSON struct {
    72  	Env  stEnv                    `json:"env"`
    73  	Pre  core.GenesisAlloc        `json:"pre"`
    74  	Tx   stTransaction            `json:"transaction"`
    75  	Out  hexutil.Bytes            `json:"out"`
    76  	Post map[string][]stPostState `json:"post"`
    77  }
    78  
    79  type stPostState struct {
    80  	Root            common.UnprefixedHash `json:"hash"`
    81  	Logs            common.UnprefixedHash `json:"logs"`
    82  	TxBytes         hexutil.Bytes         `json:"txbytes"`
    83  	ExpectException string                `json:"expectException"`
    84  	Indexes         struct {
    85  		Data  int `json:"data"`
    86  		Gas   int `json:"gas"`
    87  		Value int `json:"value"`
    88  	}
    89  }
    90  
    91  //go:generate go run github.com/fjl/gencodec -type stEnv -field-override stEnvMarshaling -out gen_stenv.go
    92  type stEnv struct {
    93  	Coinbase   common.Address `json:"currentCoinbase"   gencodec:"required"`
    94  	Difficulty *big.Int       `json:"currentDifficulty" gencodec:"required"`
    95  	Random     *big.Int       `json:"currentRandom"     gencodec:"optional"`
    96  	GasLimit   uint64         `json:"currentGasLimit"   gencodec:"required"`
    97  	Number     uint64         `json:"currentNumber"     gencodec:"required"`
    98  	Timestamp  uint64         `json:"currentTimestamp"  gencodec:"required"`
    99  	BaseFee    *big.Int       `json:"currentBaseFee"  gencodec:"optional"`
   100  }
   101  
   102  //go:generate go run github.com/fjl/gencodec -type stTransaction -field-override stTransactionMarshaling -out gen_sttransaction.go
   103  type stTransaction struct {
   104  	GasPrice             *big.Int            `json:"gasPrice"`
   105  	MaxFeePerGas         *big.Int            `json:"maxFeePerGas"`
   106  	MaxPriorityFeePerGas *big.Int            `json:"maxPriorityFeePerGas"`
   107  	Nonce                uint64              `json:"nonce"`
   108  	To                   string              `json:"to"`
   109  	Data                 []string            `json:"data"`
   110  	AccessLists          []*types.AccessList `json:"accessLists,omitempty"`
   111  	GasLimit             []uint64            `json:"gasLimit"`
   112  	Value                []string            `json:"value"`
   113  	PrivateKey           []byte              `json:"secretKey"`
   114  	BlobVersionedHashes  []common.Hash       `json:"blobVersionedHashes,omitempty"`
   115  	BlobGasFeeCap        *big.Int            `json:"maxFeePerBlobGas,omitempty"`
   116  }
   117  
   118  // nolint: unused
   119  type stTransactionMarshaling struct {
   120  	GasPrice             *math.HexOrDecimal256
   121  	MaxFeePerGas         *math.HexOrDecimal256
   122  	MaxPriorityFeePerGas *math.HexOrDecimal256
   123  	Nonce                math.HexOrDecimal64
   124  	GasLimit             []math.HexOrDecimal64
   125  	PrivateKey           hexutil.Bytes
   126  	BlobGasFeeCap        *math.HexOrDecimal256
   127  }
   128  
   129  // GetChainConfig takes a fork definition and returns a chain config.
   130  // The fork definition can be
   131  // - a plain forkname, e.g. `Byzantium`,
   132  // - a fork basename, and a list of EIPs to enable; e.g. `Byzantium+1884+1283`.
   133  func GetChainConfig(forkString string) (baseConfig *params.ChainConfig, eips []int, err error) {
   134  	var (
   135  		splitForks            = strings.Split(forkString, "+")
   136  		ok                    bool
   137  		baseName, eipsStrings = splitForks[0], splitForks[1:]
   138  	)
   139  
   140  	// NOTE: this is added to support mapping geth fork names to
   141  	// subnet-evm fork names.
   142  	forkAliases := map[string]string{
   143  		"Berlin":       "Pre-SubnetEVM",
   144  		"London":       "SubnetEVM",
   145  		"ArrowGlacier": "SubnetEVM",
   146  		"GrayGlacier":  "SubnetEVM",
   147  		"Merge":        "SubnetEVM",
   148  	}
   149  	if alias, ok := forkAliases[baseName]; ok {
   150  		baseName = alias
   151  	}
   152  
   153  	if baseConfig, ok = Forks[baseName]; !ok {
   154  		return nil, nil, UnsupportedForkError{baseName}
   155  	}
   156  	for _, eip := range eipsStrings {
   157  		if eipNum, err := strconv.Atoi(eip); err != nil {
   158  			return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum)
   159  		} else {
   160  			if !vm.ValidEip(eipNum) {
   161  				return nil, nil, fmt.Errorf("syntax error, invalid eip number %v", eipNum)
   162  			}
   163  			eips = append(eips, eipNum)
   164  		}
   165  	}
   166  	return baseConfig, eips, nil
   167  }
   168  
   169  // Subtests returns all valid subtests of the test.
   170  func (t *StateTest) Subtests() []StateSubtest {
   171  	var sub []StateSubtest
   172  	for fork, pss := range t.json.Post {
   173  		for i := range pss {
   174  			sub = append(sub, StateSubtest{fork, i})
   175  		}
   176  	}
   177  	return sub
   178  }
   179  
   180  // checkError checks if the error returned by the state transition matches any expected error.
   181  // A failing expectation returns a wrapped version of the original error, if any,
   182  // or a new error detailing the failing expectation.
   183  // This function does not return or modify the original error, it only evaluates and returns expectations for the error.
   184  func (t *StateTest) checkError(subtest StateSubtest, err error) error {
   185  	expectedError := t.json.Post[subtest.Fork][subtest.Index].ExpectException
   186  	if err == nil && expectedError == "" {
   187  		return nil
   188  	}
   189  	if err == nil && expectedError != "" {
   190  		return fmt.Errorf("expected error %q, got no error", expectedError)
   191  	}
   192  	if err != nil && expectedError == "" {
   193  		return fmt.Errorf("unexpected error: %w", err)
   194  	}
   195  	if err != nil && expectedError != "" {
   196  		// Ignore expected errors (TODO MariusVanDerWijden check error string)
   197  		return nil
   198  	}
   199  	return nil
   200  }
   201  
   202  // Run executes a specific subtest and verifies the post-state and logs
   203  func (t *StateTest) Run(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, error) {
   204  	snaps, statedb, root, err := t.RunNoVerify(subtest, vmconfig, snapshotter)
   205  	if checkedErr := t.checkError(subtest, err); checkedErr != nil {
   206  		return snaps, statedb, checkedErr
   207  	}
   208  	// The error has been checked; if it was unexpected, it's already returned.
   209  	if err != nil {
   210  		// Here, an error exists but it was expected.
   211  		// We do not check the post state or logs.
   212  		return snaps, statedb, nil
   213  	}
   214  	post := t.json.Post[subtest.Fork][subtest.Index]
   215  	// N.B: We need to do this in a two-step process, because the first Commit takes care
   216  	// of self-destructs, and we need to touch the coinbase _after_ it has potentially self-destructed.
   217  	if root != common.Hash(post.Root) {
   218  		return snaps, statedb, fmt.Errorf("post state root mismatch: got %x, want %x", root, post.Root)
   219  	}
   220  	if logs := rlpHash(statedb.Logs()); logs != common.Hash(post.Logs) {
   221  		return snaps, statedb, fmt.Errorf("post state logs hash mismatch: got %x, want %x", logs, post.Logs)
   222  	}
   223  	// Re-init the post-state instance for further operation
   224  	statedb, err = state.New(root, statedb.Database(), snaps)
   225  	if err != nil {
   226  		return nil, nil, err
   227  	}
   228  	return snaps, statedb, nil
   229  }
   230  
   231  // RunNoVerify runs a specific subtest and returns the statedb and post-state root
   232  func (t *StateTest) RunNoVerify(subtest StateSubtest, vmconfig vm.Config, snapshotter bool) (*snapshot.Tree, *state.StateDB, common.Hash, error) {
   233  	config, eips, err := GetChainConfig(subtest.Fork)
   234  	if err != nil {
   235  		return nil, nil, common.Hash{}, UnsupportedForkError{subtest.Fork}
   236  	}
   237  	vmconfig.ExtraEips = eips
   238  	block := t.genesis(config).ToBlock()
   239  	snaps, statedb := MakePreState(rawdb.NewMemoryDatabase(), t.json.Pre, snapshotter)
   240  
   241  	var baseFee *big.Int
   242  	if config.IsSubnetEVM(0) {
   243  		baseFee = t.json.Env.BaseFee
   244  		if baseFee == nil {
   245  			// Retesteth uses `0x10` for genesis baseFee. Therefore, it defaults to
   246  			// parent - 2 : 0xa as the basefee for 'this' context.
   247  			baseFee = big.NewInt(0x0a)
   248  		}
   249  	}
   250  	post := t.json.Post[subtest.Fork][subtest.Index]
   251  	msg, err := t.json.Tx.toMessage(post, baseFee)
   252  	if err != nil {
   253  		return nil, nil, common.Hash{}, err
   254  	}
   255  
   256  	// Try to recover tx with current signer
   257  	if len(post.TxBytes) != 0 {
   258  		var ttx types.Transaction
   259  		err := ttx.UnmarshalBinary(post.TxBytes)
   260  		if err != nil {
   261  			return nil, nil, common.Hash{}, err
   262  		}
   263  
   264  		if _, err := types.Sender(types.LatestSigner(config), &ttx); err != nil {
   265  			return nil, nil, common.Hash{}, err
   266  		}
   267  	}
   268  
   269  	// Prepare the EVM.
   270  	txContext := core.NewEVMTxContext(msg)
   271  	context := core.NewEVMBlockContext(block.Header(), nil, &t.json.Env.Coinbase)
   272  	context.GetHash = vmTestBlockHash
   273  	context.BaseFee = baseFee
   274  	if config.IsSubnetEVM(0) && t.json.Env.Random != nil {
   275  		context.Difficulty = big.NewInt(0)
   276  	}
   277  	evm := vm.NewEVM(context, txContext, statedb, config, vmconfig)
   278  	// Execute the message.
   279  	snapshot := statedb.Snapshot()
   280  	gaspool := new(core.GasPool)
   281  	gaspool.AddGas(block.GasLimit())
   282  	_, err = core.ApplyMessage(evm, msg, gaspool)
   283  	if err != nil {
   284  		statedb.RevertToSnapshot(snapshot)
   285  	}
   286  	// Add 0-value mining reward. This only makes a difference in the cases
   287  	// where
   288  	// - the coinbase self-destructed, or
   289  	// - there are only 'bad' transactions, which aren't executed. In those cases,
   290  	//   the coinbase gets no txfee, so isn't created, and thus needs to be touched
   291  	statedb.AddBalance(block.Coinbase(), new(big.Int))
   292  	// Commit block
   293  	root, _ := statedb.Commit(block.NumberU64(), config.IsEIP158(block.Number()), false)
   294  	return snaps, statedb, root, err
   295  }
   296  
   297  func MakePreState(db ethdb.Database, accounts core.GenesisAlloc, snapshotter bool) (*snapshot.Tree, *state.StateDB) {
   298  	sdb := state.NewDatabaseWithConfig(db, &trie.Config{Preimages: true})
   299  	statedb, _ := state.New(types.EmptyRootHash, sdb, nil)
   300  	for addr, a := range accounts {
   301  		statedb.SetCode(addr, a.Code)
   302  		statedb.SetNonce(addr, a.Nonce)
   303  		statedb.SetBalance(addr, a.Balance)
   304  		for k, v := range a.Storage {
   305  			statedb.SetState(addr, k, v)
   306  		}
   307  	}
   308  	// Commit and re-open to start with a clean state.
   309  	root, _ := statedb.Commit(0, false, false)
   310  
   311  	var snaps *snapshot.Tree
   312  	if snapshotter {
   313  		snapconfig := snapshot.Config{
   314  			CacheSize:  1,
   315  			NoBuild:    false,
   316  			AsyncBuild: false,
   317  			SkipVerify: true,
   318  		}
   319  		snaps, _ = snapshot.New(snapconfig, db, sdb.TrieDB(), common.Hash{}, root)
   320  	}
   321  	statedb, _ = state.New(root, sdb, snaps)
   322  	return snaps, statedb
   323  }
   324  
   325  func (t *StateTest) genesis(config *params.ChainConfig) *core.Genesis {
   326  	genesis := &core.Genesis{
   327  		Config:     config,
   328  		Coinbase:   t.json.Env.Coinbase,
   329  		Difficulty: t.json.Env.Difficulty,
   330  		GasLimit:   t.json.Env.GasLimit,
   331  		Number:     t.json.Env.Number,
   332  		Timestamp:  t.json.Env.Timestamp,
   333  		Alloc:      t.json.Pre,
   334  	}
   335  	if t.json.Env.Random != nil {
   336  		// Post-Merge
   337  		genesis.Mixhash = common.BigToHash(t.json.Env.Random)
   338  		genesis.Difficulty = big.NewInt(0)
   339  	}
   340  	return genesis
   341  }
   342  
   343  func (tx *stTransaction) toMessage(ps stPostState, baseFee *big.Int) (*core.Message, error) {
   344  	// Derive sender from private key if present.
   345  	var from common.Address
   346  	if len(tx.PrivateKey) > 0 {
   347  		key, err := crypto.ToECDSA(tx.PrivateKey)
   348  		if err != nil {
   349  			return nil, fmt.Errorf("invalid private key: %v", err)
   350  		}
   351  		from = crypto.PubkeyToAddress(key.PublicKey)
   352  	}
   353  	// Parse recipient if present.
   354  	var to *common.Address
   355  	if tx.To != "" {
   356  		to = new(common.Address)
   357  		if err := to.UnmarshalText([]byte(tx.To)); err != nil {
   358  			return nil, fmt.Errorf("invalid to address: %v", err)
   359  		}
   360  	}
   361  
   362  	// Get values specific to this post state.
   363  	if ps.Indexes.Data > len(tx.Data) {
   364  		return nil, fmt.Errorf("tx data index %d out of bounds", ps.Indexes.Data)
   365  	}
   366  	if ps.Indexes.Value > len(tx.Value) {
   367  		return nil, fmt.Errorf("tx value index %d out of bounds", ps.Indexes.Value)
   368  	}
   369  	if ps.Indexes.Gas > len(tx.GasLimit) {
   370  		return nil, fmt.Errorf("tx gas limit index %d out of bounds", ps.Indexes.Gas)
   371  	}
   372  	dataHex := tx.Data[ps.Indexes.Data]
   373  	valueHex := tx.Value[ps.Indexes.Value]
   374  	gasLimit := tx.GasLimit[ps.Indexes.Gas]
   375  	// Value, Data hex encoding is messy: https://github.com/ethereum/tests/issues/203
   376  	value := new(big.Int)
   377  	if valueHex != "0x" {
   378  		v, ok := math.ParseBig256(valueHex)
   379  		if !ok {
   380  			return nil, fmt.Errorf("invalid tx value %q", valueHex)
   381  		}
   382  		value = v
   383  	}
   384  	data, err := hex.DecodeString(strings.TrimPrefix(dataHex, "0x"))
   385  	if err != nil {
   386  		return nil, fmt.Errorf("invalid tx data %q", dataHex)
   387  	}
   388  	var accessList types.AccessList
   389  	if tx.AccessLists != nil && tx.AccessLists[ps.Indexes.Data] != nil {
   390  		accessList = *tx.AccessLists[ps.Indexes.Data]
   391  	}
   392  	// If baseFee provided, set gasPrice to effectiveGasPrice.
   393  	gasPrice := tx.GasPrice
   394  	if baseFee != nil {
   395  		if tx.MaxFeePerGas == nil {
   396  			tx.MaxFeePerGas = gasPrice
   397  		}
   398  		if tx.MaxFeePerGas == nil {
   399  			tx.MaxFeePerGas = new(big.Int)
   400  		}
   401  		if tx.MaxPriorityFeePerGas == nil {
   402  			tx.MaxPriorityFeePerGas = tx.MaxFeePerGas
   403  		}
   404  		gasPrice = math.BigMin(new(big.Int).Add(tx.MaxPriorityFeePerGas, baseFee),
   405  			tx.MaxFeePerGas)
   406  	}
   407  	if gasPrice == nil {
   408  		return nil, errors.New("no gas price provided")
   409  	}
   410  
   411  	msg := &core.Message{
   412  		From:          from,
   413  		To:            to,
   414  		Nonce:         tx.Nonce,
   415  		Value:         value,
   416  		GasLimit:      gasLimit,
   417  		GasPrice:      gasPrice,
   418  		GasFeeCap:     tx.MaxFeePerGas,
   419  		GasTipCap:     tx.MaxPriorityFeePerGas,
   420  		Data:          data,
   421  		AccessList:    accessList,
   422  		BlobHashes:    tx.BlobVersionedHashes,
   423  		BlobGasFeeCap: tx.BlobGasFeeCap,
   424  	}
   425  	return msg, nil
   426  }
   427  
   428  func rlpHash(x interface{}) (h common.Hash) {
   429  	hw := sha3.NewLegacyKeccak256()
   430  	rlp.Encode(hw, x)
   431  	hw.Sum(h[:0])
   432  	return h
   433  }
   434  
   435  func vmTestBlockHash(n uint64) common.Hash {
   436  	return common.BytesToHash(crypto.Keccak256([]byte(big.NewInt(int64(n)).String())))
   437  }