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