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  }