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  }