github.1485827954.workers.dev/ethereum/go-ethereum@v1.14.3/miner/payload_building_test.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>
    16  
    17  package miner
    18  
    19  import (
    20  	"math/big"
    21  	"reflect"
    22  	"testing"
    23  	"time"
    24  
    25  	"github.com/ethereum/go-ethereum/accounts"
    26  	"github.com/ethereum/go-ethereum/beacon/engine"
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/consensus"
    29  	"github.com/ethereum/go-ethereum/consensus/clique"
    30  	"github.com/ethereum/go-ethereum/consensus/ethash"
    31  	"github.com/ethereum/go-ethereum/core"
    32  	"github.com/ethereum/go-ethereum/core/rawdb"
    33  	"github.com/ethereum/go-ethereum/core/txpool"
    34  	"github.com/ethereum/go-ethereum/core/txpool/legacypool"
    35  	"github.com/ethereum/go-ethereum/core/types"
    36  	"github.com/ethereum/go-ethereum/core/vm"
    37  	"github.com/ethereum/go-ethereum/crypto"
    38  	"github.com/ethereum/go-ethereum/ethdb"
    39  	"github.com/ethereum/go-ethereum/params"
    40  )
    41  
    42  var (
    43  	// Test chain configurations
    44  	testTxPoolConfig  legacypool.Config
    45  	ethashChainConfig *params.ChainConfig
    46  	cliqueChainConfig *params.ChainConfig
    47  
    48  	// Test accounts
    49  	testBankKey, _  = crypto.GenerateKey()
    50  	testBankAddress = crypto.PubkeyToAddress(testBankKey.PublicKey)
    51  	testBankFunds   = big.NewInt(1000000000000000000)
    52  
    53  	testUserKey, _  = crypto.GenerateKey()
    54  	testUserAddress = crypto.PubkeyToAddress(testUserKey.PublicKey)
    55  
    56  	// Test transactions
    57  	pendingTxs []*types.Transaction
    58  	newTxs     []*types.Transaction
    59  
    60  	testConfig = Config{
    61  		PendingFeeRecipient: testBankAddress,
    62  		Recommit:            time.Second,
    63  		GasCeil:             params.GenesisGasLimit,
    64  	}
    65  )
    66  
    67  func init() {
    68  	testTxPoolConfig = legacypool.DefaultConfig
    69  	testTxPoolConfig.Journal = ""
    70  	ethashChainConfig = new(params.ChainConfig)
    71  	*ethashChainConfig = *params.TestChainConfig
    72  	cliqueChainConfig = new(params.ChainConfig)
    73  	*cliqueChainConfig = *params.TestChainConfig
    74  	cliqueChainConfig.Clique = &params.CliqueConfig{
    75  		Period: 10,
    76  		Epoch:  30000,
    77  	}
    78  
    79  	signer := types.LatestSigner(params.TestChainConfig)
    80  	tx1 := types.MustSignNewTx(testBankKey, signer, &types.AccessListTx{
    81  		ChainID:  params.TestChainConfig.ChainID,
    82  		Nonce:    0,
    83  		To:       &testUserAddress,
    84  		Value:    big.NewInt(1000),
    85  		Gas:      params.TxGas,
    86  		GasPrice: big.NewInt(params.InitialBaseFee),
    87  	})
    88  	pendingTxs = append(pendingTxs, tx1)
    89  
    90  	tx2 := types.MustSignNewTx(testBankKey, signer, &types.LegacyTx{
    91  		Nonce:    1,
    92  		To:       &testUserAddress,
    93  		Value:    big.NewInt(1000),
    94  		Gas:      params.TxGas,
    95  		GasPrice: big.NewInt(params.InitialBaseFee),
    96  	})
    97  	newTxs = append(newTxs, tx2)
    98  }
    99  
   100  // testWorkerBackend implements worker.Backend interfaces and wraps all information needed during the testing.
   101  type testWorkerBackend struct {
   102  	db      ethdb.Database
   103  	txPool  *txpool.TxPool
   104  	chain   *core.BlockChain
   105  	genesis *core.Genesis
   106  }
   107  
   108  func newTestWorkerBackend(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, n int) *testWorkerBackend {
   109  	var gspec = &core.Genesis{
   110  		Config: chainConfig,
   111  		Alloc:  types.GenesisAlloc{testBankAddress: {Balance: testBankFunds}},
   112  	}
   113  	switch e := engine.(type) {
   114  	case *clique.Clique:
   115  		gspec.ExtraData = make([]byte, 32+common.AddressLength+crypto.SignatureLength)
   116  		copy(gspec.ExtraData[32:32+common.AddressLength], testBankAddress.Bytes())
   117  		e.Authorize(testBankAddress, func(account accounts.Account, s string, data []byte) ([]byte, error) {
   118  			return crypto.Sign(crypto.Keccak256(data), testBankKey)
   119  		})
   120  	case *ethash.Ethash:
   121  	default:
   122  		t.Fatalf("unexpected consensus engine type: %T", engine)
   123  	}
   124  	chain, err := core.NewBlockChain(db, &core.CacheConfig{TrieDirtyDisabled: true}, gspec, nil, engine, vm.Config{}, nil, nil)
   125  	if err != nil {
   126  		t.Fatalf("core.NewBlockChain failed: %v", err)
   127  	}
   128  	pool := legacypool.New(testTxPoolConfig, chain)
   129  	txpool, _ := txpool.New(testTxPoolConfig.PriceLimit, chain, []txpool.SubPool{pool})
   130  
   131  	return &testWorkerBackend{
   132  		db:      db,
   133  		chain:   chain,
   134  		txPool:  txpool,
   135  		genesis: gspec,
   136  	}
   137  }
   138  
   139  func (b *testWorkerBackend) BlockChain() *core.BlockChain { return b.chain }
   140  func (b *testWorkerBackend) TxPool() *txpool.TxPool       { return b.txPool }
   141  
   142  func newTestWorker(t *testing.T, chainConfig *params.ChainConfig, engine consensus.Engine, db ethdb.Database, blocks int) (*Miner, *testWorkerBackend) {
   143  	backend := newTestWorkerBackend(t, chainConfig, engine, db, blocks)
   144  	backend.txPool.Add(pendingTxs, true, false)
   145  	w := New(backend, testConfig, engine)
   146  	return w, backend
   147  }
   148  
   149  func TestBuildPayload(t *testing.T) {
   150  	var (
   151  		db        = rawdb.NewMemoryDatabase()
   152  		recipient = common.HexToAddress("0xdeadbeef")
   153  	)
   154  	w, b := newTestWorker(t, params.TestChainConfig, ethash.NewFaker(), db, 0)
   155  
   156  	timestamp := uint64(time.Now().Unix())
   157  	args := &BuildPayloadArgs{
   158  		Parent:       b.chain.CurrentBlock().Hash(),
   159  		Timestamp:    timestamp,
   160  		Random:       common.Hash{},
   161  		FeeRecipient: recipient,
   162  	}
   163  	payload, err := w.buildPayload(args)
   164  	if err != nil {
   165  		t.Fatalf("Failed to build payload %v", err)
   166  	}
   167  	verify := func(outer *engine.ExecutionPayloadEnvelope, txs int) {
   168  		payload := outer.ExecutionPayload
   169  		if payload.ParentHash != b.chain.CurrentBlock().Hash() {
   170  			t.Fatal("Unexpected parent hash")
   171  		}
   172  		if payload.Random != (common.Hash{}) {
   173  			t.Fatal("Unexpected random value")
   174  		}
   175  		if payload.Timestamp != timestamp {
   176  			t.Fatal("Unexpected timestamp")
   177  		}
   178  		if payload.FeeRecipient != recipient {
   179  			t.Fatal("Unexpected fee recipient")
   180  		}
   181  		if len(payload.Transactions) != txs {
   182  			t.Fatal("Unexpected transaction set")
   183  		}
   184  	}
   185  	empty := payload.ResolveEmpty()
   186  	verify(empty, 0)
   187  
   188  	full := payload.ResolveFull()
   189  	verify(full, len(pendingTxs))
   190  
   191  	// Ensure resolve can be called multiple times and the
   192  	// result should be unchanged
   193  	dataOne := payload.Resolve()
   194  	dataTwo := payload.Resolve()
   195  	if !reflect.DeepEqual(dataOne, dataTwo) {
   196  		t.Fatal("Unexpected payload data")
   197  	}
   198  }
   199  
   200  func TestPayloadId(t *testing.T) {
   201  	t.Parallel()
   202  	ids := make(map[string]int)
   203  	for i, tt := range []*BuildPayloadArgs{
   204  		{
   205  			Parent:       common.Hash{1},
   206  			Timestamp:    1,
   207  			Random:       common.Hash{0x1},
   208  			FeeRecipient: common.Address{0x1},
   209  		},
   210  		// Different parent
   211  		{
   212  			Parent:       common.Hash{2},
   213  			Timestamp:    1,
   214  			Random:       common.Hash{0x1},
   215  			FeeRecipient: common.Address{0x1},
   216  		},
   217  		// Different timestamp
   218  		{
   219  			Parent:       common.Hash{2},
   220  			Timestamp:    2,
   221  			Random:       common.Hash{0x1},
   222  			FeeRecipient: common.Address{0x1},
   223  		},
   224  		// Different Random
   225  		{
   226  			Parent:       common.Hash{2},
   227  			Timestamp:    2,
   228  			Random:       common.Hash{0x2},
   229  			FeeRecipient: common.Address{0x1},
   230  		},
   231  		// Different fee-recipient
   232  		{
   233  			Parent:       common.Hash{2},
   234  			Timestamp:    2,
   235  			Random:       common.Hash{0x2},
   236  			FeeRecipient: common.Address{0x2},
   237  		},
   238  		// Different withdrawals (non-empty)
   239  		{
   240  			Parent:       common.Hash{2},
   241  			Timestamp:    2,
   242  			Random:       common.Hash{0x2},
   243  			FeeRecipient: common.Address{0x2},
   244  			Withdrawals: []*types.Withdrawal{
   245  				{
   246  					Index:     0,
   247  					Validator: 0,
   248  					Address:   common.Address{},
   249  					Amount:    0,
   250  				},
   251  			},
   252  		},
   253  		// Different withdrawals (non-empty)
   254  		{
   255  			Parent:       common.Hash{2},
   256  			Timestamp:    2,
   257  			Random:       common.Hash{0x2},
   258  			FeeRecipient: common.Address{0x2},
   259  			Withdrawals: []*types.Withdrawal{
   260  				{
   261  					Index:     2,
   262  					Validator: 0,
   263  					Address:   common.Address{},
   264  					Amount:    0,
   265  				},
   266  			},
   267  		},
   268  	} {
   269  		id := tt.Id().String()
   270  		if prev, exists := ids[id]; exists {
   271  			t.Errorf("ID collision, case %d and case %d: id %v", prev, i, id)
   272  		}
   273  		ids[id] = i
   274  	}
   275  }