github.com/MetalBlockchain/subnet-evm@v0.4.9/core/state_processor_test.go (about)

     1  // (c) 2019-2021, 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 2020 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 core
    28  
    29  import (
    30  	"math/big"
    31  	"testing"
    32  
    33  	"github.com/MetalBlockchain/subnet-evm/consensus"
    34  	"github.com/MetalBlockchain/subnet-evm/consensus/dummy"
    35  	"github.com/MetalBlockchain/subnet-evm/core/rawdb"
    36  	"github.com/MetalBlockchain/subnet-evm/core/types"
    37  	"github.com/MetalBlockchain/subnet-evm/core/vm"
    38  	"github.com/MetalBlockchain/subnet-evm/params"
    39  	"github.com/MetalBlockchain/subnet-evm/precompile"
    40  	"github.com/MetalBlockchain/subnet-evm/trie"
    41  	"github.com/ethereum/go-ethereum/common"
    42  	"github.com/ethereum/go-ethereum/crypto"
    43  	"golang.org/x/crypto/sha3"
    44  )
    45  
    46  var (
    47  	config     = params.TestChainConfig
    48  	signer     = types.LatestSigner(config)
    49  	testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    50  )
    51  
    52  func makeTx(nonce uint64, to common.Address, amount *big.Int, gasLimit uint64, gasPrice *big.Int, data []byte) *types.Transaction {
    53  	tx, _ := types.SignTx(types.NewTransaction(nonce, to, amount, gasLimit, gasPrice, data), signer, testKey)
    54  	return tx
    55  }
    56  
    57  func mkDynamicTx(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
    58  	tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
    59  		Nonce:     nonce,
    60  		GasTipCap: gasTipCap,
    61  		GasFeeCap: gasFeeCap,
    62  		Gas:       gasLimit,
    63  		To:        &to,
    64  		Value:     big.NewInt(0),
    65  	}), signer, testKey)
    66  	return tx
    67  }
    68  
    69  // TestStateProcessorErrors tests the output from the 'core' errors
    70  // as defined in core/error.go. These errors are generated when the
    71  // blockchain imports bad blocks, meaning blocks which have valid headers but
    72  // contain invalid transactions
    73  func TestStateProcessorErrors(t *testing.T) {
    74  	config.FeeConfig.MinBaseFee = params.TestMaxBaseFee
    75  	{ // Tests against a 'recent' chain definition
    76  		var (
    77  			db    = rawdb.NewMemoryDatabase()
    78  			gspec = &Genesis{
    79  				Config: config,
    80  				Alloc: GenesisAlloc{
    81  					common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
    82  						Balance: big.NewInt(2000000000000000000), // 2 ether
    83  						Nonce:   0,
    84  					},
    85  				},
    86  				GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(),
    87  			}
    88  			genesis       = gspec.MustCommit(db)
    89  			blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{})
    90  		)
    91  		defer blockchain.Stop()
    92  		bigNumber := new(big.Int).SetBytes(common.FromHex("0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"))
    93  		tooBigNumber := new(big.Int).Set(bigNumber)
    94  		tooBigNumber.Add(tooBigNumber, common.Big1)
    95  		for i, tt := range []struct {
    96  			txs  []*types.Transaction
    97  			want string
    98  		}{
    99  			{ // ErrNonceTooLow
   100  				txs: []*types.Transaction{
   101  					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(225000000000), nil),
   102  					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(225000000000), nil),
   103  				},
   104  				want: "could not apply tx 1 [0x734d821c990099c6ae42d78072aadd3931c35328cf03ef4cf5b2a4ac9c398522]: nonce too low: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 0 state: 1",
   105  			},
   106  			{ // ErrNonceTooHigh
   107  				txs: []*types.Transaction{
   108  					makeTx(100, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(225000000000), nil),
   109  				},
   110  				want: "could not apply tx 0 [0x0df36254cfbef8ed6961b38fc68aecc777177166144c8a56bc8919e23a559bf4]: nonce too high: address 0x71562b71999873DB5b286dF957af199Ec94617F7, tx: 100 state: 0",
   111  			},
   112  			{ // ErrGasLimitReached
   113  				txs: []*types.Transaction{
   114  					makeTx(0, common.Address{}, big.NewInt(0), 8000001, big.NewInt(225000000000), nil),
   115  				},
   116  				want: "could not apply tx 0 [0xfbe38b817aaa760c2766b56c019fcdba506560a28fd41c69ae96bdaa4569e317]: gas limit reached",
   117  			},
   118  			{ // ErrInsufficientFundsForTransfer
   119  				txs: []*types.Transaction{
   120  					makeTx(0, common.Address{}, big.NewInt(2000000000000000000), params.TxGas, big.NewInt(225000000000), nil),
   121  				},
   122  				want: "could not apply tx 0 [0xae1601ef55b676ebb824ee7e16a0d14af725b7f9cf5ec79e21f14833c26b5b35]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 2004725000000000000",
   123  			},
   124  			{ // ErrInsufficientFunds
   125  				txs: []*types.Transaction{
   126  					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas, big.NewInt(900000000000000000), nil),
   127  				},
   128  				want: "could not apply tx 0 [0x4a69690c4b0cd85e64d0d9ea06302455b01e10a83db964d60281739752003440]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 18900000000000000000000",
   129  			},
   130  			// ErrGasUintOverflow
   131  			// One missing 'core' error is ErrGasUintOverflow: "gas uint64 overflow",
   132  			// In order to trigger that one, we'd have to allocate a _huge_ chunk of data, such that the
   133  			// multiplication len(data) +gas_per_byte overflows uint64. Not testable at the moment
   134  			{ // ErrIntrinsicGas
   135  				txs: []*types.Transaction{
   136  					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas-1000, big.NewInt(225000000000), nil),
   137  				},
   138  				want: "could not apply tx 0 [0x2fc3e3b5cc26917d413e26983fe189475f47d4f0757e32aaa5561fcb9c9dc432]: intrinsic gas too low: have 20000, want 21000",
   139  			},
   140  			{ // ErrGasLimitReached
   141  				txs: []*types.Transaction{
   142  					makeTx(0, common.Address{}, big.NewInt(0), params.TxGas*381, big.NewInt(225000000000), nil),
   143  				},
   144  				want: "could not apply tx 0 [0x9ee548e001369418ae53aaa11b5d823f081cc7fa9c9a7ee71a978ae17a2aece0]: gas limit reached",
   145  			},
   146  			{ // ErrFeeCapTooLow
   147  				txs: []*types.Transaction{
   148  					mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(0)),
   149  				},
   150  				want: "could not apply tx 0 [0xc4ab868fef0c82ae0387b742aee87907f2d0fc528fc6ea0a021459fb0fc4a4a8]: max fee per gas less than block base fee: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas: 0 baseFee: 225000000000",
   151  			},
   152  			{ // ErrTipVeryHigh
   153  				txs: []*types.Transaction{
   154  					mkDynamicTx(0, common.Address{}, params.TxGas, tooBigNumber, big.NewInt(1)),
   155  				},
   156  				want: "could not apply tx 0 [0x15b8391b9981f266b32f3ab7da564bbeb3d6c21628364ea9b32a21139f89f712]: max priority fee per gas higher than 2^256-1: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxPriorityFeePerGas bit length: 257",
   157  			},
   158  			{ // ErrFeeCapVeryHigh
   159  				txs: []*types.Transaction{
   160  					mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), tooBigNumber),
   161  				},
   162  				want: "could not apply tx 0 [0x48bc299b83fdb345c57478f239e89814bb3063eb4e4b49f3b6057a69255c16bd]: max fee per gas higher than 2^256-1: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxFeePerGas bit length: 257",
   163  			},
   164  			{ // ErrTipAboveFeeCap
   165  				txs: []*types.Transaction{
   166  					mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(2), big.NewInt(1)),
   167  				},
   168  				want: "could not apply tx 0 [0xf987a31ff0c71895780a7612f965a0c8b056deb54e020bb44fa478092f14c9b4]: max priority fee per gas higher than max fee per gas: address 0x71562b71999873DB5b286dF957af199Ec94617F7, maxPriorityFeePerGas: 2, maxFeePerGas: 1",
   169  			},
   170  			{ // ErrInsufficientFunds
   171  				// Available balance:           1000000000000000000
   172  				// Effective cost:                   18375000021000
   173  				// FeeCap * gas:                1050000000000000000
   174  				// This test is designed to have the effective cost be covered by the balance, but
   175  				// the extended requirement on FeeCap*gas < balance to fail
   176  				txs: []*types.Transaction{
   177  					mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(1), big.NewInt(100000000000000)),
   178  				},
   179  				want: "could not apply tx 0 [0x3388378ed60640e75d2edf728d5528a305f599997abc4f23ec46b351b6197499]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 2100000000000000000",
   180  			},
   181  			{ // Another ErrInsufficientFunds, this one to ensure that feecap/tip of max u256 is allowed
   182  				txs: []*types.Transaction{
   183  					mkDynamicTx(0, common.Address{}, params.TxGas, bigNumber, bigNumber),
   184  				},
   185  				want: "could not apply tx 0 [0xd82a0c2519acfeac9a948258c47e784acd20651d9d80f9a1c67b4137651c3a24]: insufficient funds for gas * price + value: address 0x71562b71999873DB5b286dF957af199Ec94617F7 have 2000000000000000000 want 2431633873983640103894990685182446064918669677978451844828609264166175722438635000",
   186  			},
   187  		} {
   188  			block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config)
   189  			_, err := blockchain.InsertChain(types.Blocks{block})
   190  			if err == nil {
   191  				t.Fatal("block imported without errors")
   192  			}
   193  			if have, want := err.Error(), tt.want; have != want {
   194  				t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
   195  			}
   196  		}
   197  	}
   198  
   199  	// ErrTxTypeNotSupported, For this, we need an older chain
   200  	{
   201  		var (
   202  			db    = rawdb.NewMemoryDatabase()
   203  			gspec = &Genesis{
   204  				Config: &params.ChainConfig{
   205  					ChainID:             big.NewInt(1),
   206  					FeeConfig:           params.DefaultFeeConfig,
   207  					HomesteadBlock:      big.NewInt(0),
   208  					EIP150Block:         big.NewInt(0),
   209  					EIP150Hash:          common.Hash{},
   210  					EIP155Block:         big.NewInt(0),
   211  					EIP158Block:         big.NewInt(0),
   212  					ByzantiumBlock:      big.NewInt(0),
   213  					ConstantinopleBlock: big.NewInt(0),
   214  					PetersburgBlock:     big.NewInt(0),
   215  					IstanbulBlock:       big.NewInt(0),
   216  					MuirGlacierBlock:    big.NewInt(0),
   217  				},
   218  				Alloc: GenesisAlloc{
   219  					common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
   220  						Balance: big.NewInt(1000000000000000000), // 1 ether
   221  						Nonce:   0,
   222  					},
   223  				},
   224  				GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(),
   225  			}
   226  			genesis       = gspec.MustCommit(db)
   227  			blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{})
   228  		)
   229  		defer blockchain.Stop()
   230  		for i, tt := range []struct {
   231  			txs  []*types.Transaction
   232  			want string
   233  		}{
   234  			{ // ErrTxTypeNotSupported
   235  				txs: []*types.Transaction{
   236  					mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)),
   237  				},
   238  				want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: transaction type not supported",
   239  			},
   240  		} {
   241  			block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config)
   242  			_, err := blockchain.InsertChain(types.Blocks{block})
   243  			if err == nil {
   244  				t.Fatal("block imported without errors")
   245  			}
   246  			if have, want := err.Error(), tt.want; have != want {
   247  				t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
   248  			}
   249  		}
   250  	}
   251  
   252  	// ErrSenderNoEOA, for this we need the sender to have contract code
   253  	{
   254  		var (
   255  			db    = rawdb.NewMemoryDatabase()
   256  			gspec = &Genesis{
   257  				Config: config,
   258  				Alloc: GenesisAlloc{
   259  					common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7"): GenesisAccount{
   260  						Balance: big.NewInt(1000000000000000000), // 1 ether
   261  						Nonce:   0,
   262  						Code:    common.FromHex("0xB0B0FACE"),
   263  					},
   264  				},
   265  				GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(),
   266  			}
   267  			genesis       = gspec.MustCommit(db)
   268  			blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{})
   269  		)
   270  		defer blockchain.Stop()
   271  		for i, tt := range []struct {
   272  			txs  []*types.Transaction
   273  			want string
   274  		}{
   275  			{ // ErrSenderNoEOA
   276  				txs: []*types.Transaction{
   277  					mkDynamicTx(0, common.Address{}, params.TxGas-1000, big.NewInt(0), big.NewInt(0)),
   278  				},
   279  				want: "could not apply tx 0 [0x88626ac0d53cb65308f2416103c62bb1f18b805573d4f96a3640bbbfff13c14f]: sender not an eoa: address 0x71562b71999873DB5b286dF957af199Ec94617F7, codehash: 0x9280914443471259d4570a8661015ae4a5b80186dbc619658fb494bebc3da3d1",
   280  			},
   281  		} {
   282  			block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config)
   283  			_, err := blockchain.InsertChain(types.Blocks{block})
   284  			if err == nil {
   285  				t.Fatal("block imported without errors")
   286  			}
   287  			if have, want := err.Error(), tt.want; have != want {
   288  				t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
   289  			}
   290  		}
   291  	}
   292  }
   293  
   294  // TestBadTxAllowListBlock tests the output generated when the
   295  // blockchain imports a bad block with a transaction from a
   296  // non-whitelisted TX Allow List address.
   297  func TestBadTxAllowListBlock(t *testing.T) {
   298  	var (
   299  		db       = rawdb.NewMemoryDatabase()
   300  		testAddr = common.HexToAddress("0x71562b71999873DB5b286dF957af199Ec94617F7")
   301  
   302  		config = &params.ChainConfig{
   303  			ChainID:             big.NewInt(1),
   304  			FeeConfig:           params.DefaultFeeConfig,
   305  			HomesteadBlock:      big.NewInt(0),
   306  			EIP150Block:         big.NewInt(0),
   307  			EIP150Hash:          common.Hash{},
   308  			EIP155Block:         big.NewInt(0),
   309  			EIP158Block:         big.NewInt(0),
   310  			ByzantiumBlock:      big.NewInt(0),
   311  			ConstantinopleBlock: big.NewInt(0),
   312  			PetersburgBlock:     big.NewInt(0),
   313  			IstanbulBlock:       big.NewInt(0),
   314  			MuirGlacierBlock:    big.NewInt(0),
   315  			NetworkUpgrades: params.NetworkUpgrades{
   316  				SubnetEVMTimestamp: big.NewInt(0),
   317  			},
   318  			PrecompileUpgrade: params.PrecompileUpgrade{
   319  				TxAllowListConfig: precompile.NewTxAllowListConfig(big.NewInt(0), nil, nil),
   320  			},
   321  		}
   322  		signer     = types.LatestSigner(config)
   323  		testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
   324  
   325  		gspec = &Genesis{
   326  			Config: config,
   327  			Alloc: GenesisAlloc{
   328  				testAddr: GenesisAccount{
   329  					Balance: big.NewInt(1000000000000000000), // 1 ether
   330  					Nonce:   0,
   331  				},
   332  			},
   333  
   334  			GasLimit: params.TestChainConfig.FeeConfig.GasLimit.Uint64(),
   335  		}
   336  		genesis       = gspec.MustCommit(db)
   337  		blockchain, _ = NewBlockChain(db, DefaultCacheConfig, gspec.Config, dummy.NewCoinbaseFaker(), vm.Config{}, common.Hash{})
   338  	)
   339  
   340  	mkDynamicTx := func(nonce uint64, to common.Address, gasLimit uint64, gasTipCap, gasFeeCap *big.Int) *types.Transaction {
   341  		tx, _ := types.SignTx(types.NewTx(&types.DynamicFeeTx{
   342  			Nonce:     nonce,
   343  			GasTipCap: gasTipCap,
   344  			GasFeeCap: gasFeeCap,
   345  			Gas:       gasLimit,
   346  			To:        &to,
   347  			Value:     big.NewInt(0),
   348  		}), signer, testKey)
   349  		return tx
   350  	}
   351  
   352  	defer blockchain.Stop()
   353  	for i, tt := range []struct {
   354  		txs  []*types.Transaction
   355  		want string
   356  	}{
   357  		{ // Nonwhitelisted address
   358  			txs: []*types.Transaction{
   359  				mkDynamicTx(0, common.Address{}, params.TxGas, big.NewInt(0), big.NewInt(225000000000)),
   360  			},
   361  			want: "could not apply tx 0 [0xc5725e8baac950b2925dd4fea446ccddead1cc0affdae18b31a7d910629d9225]: cannot issue transaction from non-allow listed address: 0x71562b71999873DB5b286dF957af199Ec94617F7",
   362  		},
   363  	} {
   364  		block := GenerateBadBlock(genesis, dummy.NewCoinbaseFaker(), tt.txs, gspec.Config)
   365  		_, err := blockchain.InsertChain(types.Blocks{block})
   366  		if err == nil {
   367  			t.Fatal("block imported without errors")
   368  		}
   369  		if have, want := err.Error(), tt.want; have != want {
   370  			t.Errorf("test %d:\nhave \"%v\"\nwant \"%v\"\n", i, have, want)
   371  		}
   372  	}
   373  }
   374  
   375  // GenerateBadBlock constructs a "block" which contains the transactions. The transactions are not expected to be
   376  // valid, and no proper post-state can be made. But from the perspective of the blockchain, the block is sufficiently
   377  // valid to be considered for import:
   378  // - valid pow (fake), ancestry, difficulty, gaslimit etc
   379  func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block {
   380  	header := &types.Header{
   381  		ParentHash: parent.Hash(),
   382  		Coinbase:   parent.Coinbase(),
   383  		Difficulty: engine.CalcDifficulty(&fakeChainReader{config}, parent.Time()+10, &types.Header{
   384  			Number:     parent.Number(),
   385  			Time:       parent.Time(),
   386  			Difficulty: parent.Difficulty(),
   387  			UncleHash:  parent.UncleHash(),
   388  		}),
   389  		GasLimit:  parent.GasLimit(),
   390  		Number:    new(big.Int).Add(parent.Number(), common.Big1),
   391  		Time:      parent.Time() + 10,
   392  		UncleHash: types.EmptyUncleHash,
   393  	}
   394  
   395  	if config.IsSubnetEVM(new(big.Int).SetUint64(header.Time)) {
   396  		header.Extra, header.BaseFee, _ = dummy.CalcBaseFee(config, config.FeeConfig, parent.Header(), header.Time)
   397  		header.BlockGasCost = big.NewInt(0)
   398  	}
   399  	var receipts []*types.Receipt
   400  	// The post-state result doesn't need to be correct (this is a bad block), but we do need something there
   401  	// Preferably something unique. So let's use a combo of blocknum + txhash
   402  	hasher := sha3.NewLegacyKeccak256()
   403  	hasher.Write(header.Number.Bytes())
   404  	var cumulativeGas uint64
   405  	for _, tx := range txs {
   406  		txh := tx.Hash()
   407  		hasher.Write(txh[:])
   408  		receipt := types.NewReceipt(nil, false, cumulativeGas+tx.Gas())
   409  		receipt.TxHash = tx.Hash()
   410  		receipt.GasUsed = tx.Gas()
   411  		receipts = append(receipts, receipt)
   412  		cumulativeGas += tx.Gas()
   413  	}
   414  	header.Root = common.BytesToHash(hasher.Sum(nil))
   415  	// Assemble and return the final block for sealing
   416  	return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil))
   417  }