github.com/carter-ya/go-ethereum@v0.0.0-20230628080049-d2309be3983b/eth/catalyst/api_test.go (about)

     1  // Copyright 2021 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 catalyst
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"math/big"
    23  	"sync"
    24  	"testing"
    25  	"time"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/consensus/ethash"
    30  	"github.com/ethereum/go-ethereum/core"
    31  	"github.com/ethereum/go-ethereum/core/beacon"
    32  	"github.com/ethereum/go-ethereum/core/types"
    33  	"github.com/ethereum/go-ethereum/crypto"
    34  	"github.com/ethereum/go-ethereum/eth"
    35  	"github.com/ethereum/go-ethereum/eth/downloader"
    36  	"github.com/ethereum/go-ethereum/eth/ethconfig"
    37  	"github.com/ethereum/go-ethereum/node"
    38  	"github.com/ethereum/go-ethereum/p2p"
    39  	"github.com/ethereum/go-ethereum/params"
    40  	"github.com/ethereum/go-ethereum/trie"
    41  )
    42  
    43  var (
    44  	// testKey is a private key to use for funding a tester account.
    45  	testKey, _ = crypto.HexToECDSA("b71c71a67e1177ad4e901695e1b4b9ee17ae16c6668d313eac2f96dbcda3f291")
    46  
    47  	// testAddr is the Ethereum address of the tester account.
    48  	testAddr = crypto.PubkeyToAddress(testKey.PublicKey)
    49  
    50  	testBalance = big.NewInt(2e18)
    51  )
    52  
    53  func generatePreMergeChain(n int) (*core.Genesis, []*types.Block) {
    54  	config := *params.AllEthashProtocolChanges
    55  	genesis := &core.Genesis{
    56  		Config:     &config,
    57  		Alloc:      core.GenesisAlloc{testAddr: {Balance: testBalance}},
    58  		ExtraData:  []byte("test genesis"),
    59  		Timestamp:  9000,
    60  		BaseFee:    big.NewInt(params.InitialBaseFee),
    61  		Difficulty: big.NewInt(0),
    62  	}
    63  	testNonce := uint64(0)
    64  	generate := func(i int, g *core.BlockGen) {
    65  		g.OffsetTime(5)
    66  		g.SetExtra([]byte("test"))
    67  		tx, _ := types.SignTx(types.NewTransaction(testNonce, common.HexToAddress("0x9a9070028361F7AAbeB3f2F2Dc07F82C4a98A02a"), big.NewInt(1), params.TxGas, big.NewInt(params.InitialBaseFee*2), nil), types.LatestSigner(&config), testKey)
    68  		g.AddTx(tx)
    69  		testNonce++
    70  	}
    71  	_, blocks, _ := core.GenerateChainWithGenesis(genesis, ethash.NewFaker(), n, generate)
    72  	totalDifficulty := big.NewInt(0)
    73  	for _, b := range blocks {
    74  		totalDifficulty.Add(totalDifficulty, b.Difficulty())
    75  	}
    76  	config.TerminalTotalDifficulty = totalDifficulty
    77  	return genesis, blocks
    78  }
    79  
    80  func TestEth2AssembleBlock(t *testing.T) {
    81  	genesis, blocks := generatePreMergeChain(10)
    82  	n, ethservice := startEthService(t, genesis, blocks)
    83  	defer n.Close()
    84  
    85  	api := NewConsensusAPI(ethservice)
    86  	signer := types.NewEIP155Signer(ethservice.BlockChain().Config().ChainID)
    87  	tx, err := types.SignTx(types.NewTransaction(uint64(10), blocks[9].Coinbase(), big.NewInt(1000), params.TxGas, big.NewInt(params.InitialBaseFee), nil), signer, testKey)
    88  	if err != nil {
    89  		t.Fatalf("error signing transaction, err=%v", err)
    90  	}
    91  	ethservice.TxPool().AddLocal(tx)
    92  	blockParams := beacon.PayloadAttributesV1{
    93  		Timestamp: blocks[9].Time() + 5,
    94  	}
    95  	execData, err := assembleBlock(api, blocks[9].Hash(), &blockParams)
    96  	if err != nil {
    97  		t.Fatalf("error producing block, err=%v", err)
    98  	}
    99  	if len(execData.Transactions) != 1 {
   100  		t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
   101  	}
   102  }
   103  
   104  func TestEth2AssembleBlockWithAnotherBlocksTxs(t *testing.T) {
   105  	genesis, blocks := generatePreMergeChain(10)
   106  	n, ethservice := startEthService(t, genesis, blocks[:9])
   107  	defer n.Close()
   108  
   109  	api := NewConsensusAPI(ethservice)
   110  
   111  	// Put the 10th block's tx in the pool and produce a new block
   112  	api.eth.TxPool().AddRemotesSync(blocks[9].Transactions())
   113  	blockParams := beacon.PayloadAttributesV1{
   114  		Timestamp: blocks[8].Time() + 5,
   115  	}
   116  	execData, err := assembleBlock(api, blocks[8].Hash(), &blockParams)
   117  	if err != nil {
   118  		t.Fatalf("error producing block, err=%v", err)
   119  	}
   120  	if len(execData.Transactions) != blocks[9].Transactions().Len() {
   121  		t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
   122  	}
   123  }
   124  
   125  func TestSetHeadBeforeTotalDifficulty(t *testing.T) {
   126  	genesis, blocks := generatePreMergeChain(10)
   127  	n, ethservice := startEthService(t, genesis, blocks)
   128  	defer n.Close()
   129  
   130  	api := NewConsensusAPI(ethservice)
   131  	fcState := beacon.ForkchoiceStateV1{
   132  		HeadBlockHash:      blocks[5].Hash(),
   133  		SafeBlockHash:      common.Hash{},
   134  		FinalizedBlockHash: common.Hash{},
   135  	}
   136  	if resp, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
   137  		t.Errorf("fork choice updated should not error: %v", err)
   138  	} else if resp.PayloadStatus.Status != beacon.INVALID_TERMINAL_BLOCK.Status {
   139  		t.Errorf("fork choice updated before total terminal difficulty should be INVALID")
   140  	}
   141  }
   142  
   143  func TestEth2PrepareAndGetPayload(t *testing.T) {
   144  	genesis, blocks := generatePreMergeChain(10)
   145  	// We need to properly set the terminal total difficulty
   146  	genesis.Config.TerminalTotalDifficulty.Sub(genesis.Config.TerminalTotalDifficulty, blocks[9].Difficulty())
   147  	n, ethservice := startEthService(t, genesis, blocks[:9])
   148  	defer n.Close()
   149  
   150  	api := NewConsensusAPI(ethservice)
   151  
   152  	// Put the 10th block's tx in the pool and produce a new block
   153  	ethservice.TxPool().AddLocals(blocks[9].Transactions())
   154  	blockParams := beacon.PayloadAttributesV1{
   155  		Timestamp: blocks[8].Time() + 5,
   156  	}
   157  	fcState := beacon.ForkchoiceStateV1{
   158  		HeadBlockHash:      blocks[8].Hash(),
   159  		SafeBlockHash:      common.Hash{},
   160  		FinalizedBlockHash: common.Hash{},
   161  	}
   162  	_, err := api.ForkchoiceUpdatedV1(fcState, &blockParams)
   163  	if err != nil {
   164  		t.Fatalf("error preparing payload, err=%v", err)
   165  	}
   166  	payloadID := computePayloadId(fcState.HeadBlockHash, &blockParams)
   167  	execData, err := api.GetPayloadV1(payloadID)
   168  	if err != nil {
   169  		t.Fatalf("error getting payload, err=%v", err)
   170  	}
   171  	if len(execData.Transactions) != blocks[9].Transactions().Len() {
   172  		t.Fatalf("invalid number of transactions %d != 1", len(execData.Transactions))
   173  	}
   174  	// Test invalid payloadID
   175  	var invPayload beacon.PayloadID
   176  	copy(invPayload[:], payloadID[:])
   177  	invPayload[0] = ^invPayload[0]
   178  	_, err = api.GetPayloadV1(invPayload)
   179  	if err == nil {
   180  		t.Fatal("expected error retrieving invalid payload")
   181  	}
   182  }
   183  
   184  func checkLogEvents(t *testing.T, logsCh <-chan []*types.Log, rmLogsCh <-chan core.RemovedLogsEvent, wantNew, wantRemoved int) {
   185  	t.Helper()
   186  
   187  	if len(logsCh) != wantNew {
   188  		t.Fatalf("wrong number of log events: got %d, want %d", len(logsCh), wantNew)
   189  	}
   190  	if len(rmLogsCh) != wantRemoved {
   191  		t.Fatalf("wrong number of removed log events: got %d, want %d", len(rmLogsCh), wantRemoved)
   192  	}
   193  	// Drain events.
   194  	for i := 0; i < len(logsCh); i++ {
   195  		<-logsCh
   196  	}
   197  	for i := 0; i < len(rmLogsCh); i++ {
   198  		<-rmLogsCh
   199  	}
   200  }
   201  
   202  func TestInvalidPayloadTimestamp(t *testing.T) {
   203  	genesis, preMergeBlocks := generatePreMergeChain(10)
   204  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   205  	defer n.Close()
   206  	var (
   207  		api    = NewConsensusAPI(ethservice)
   208  		parent = ethservice.BlockChain().CurrentBlock()
   209  	)
   210  	tests := []struct {
   211  		time      uint64
   212  		shouldErr bool
   213  	}{
   214  		{0, true},
   215  		{parent.Time(), true},
   216  		{parent.Time() - 1, true},
   217  
   218  		// TODO (MariusVanDerWijden) following tests are currently broken,
   219  		// fixed in upcoming merge-kiln-v2 pr
   220  		//{parent.Time() + 1, false},
   221  		//{uint64(time.Now().Unix()) + uint64(time.Minute), false},
   222  	}
   223  
   224  	for i, test := range tests {
   225  		t.Run(fmt.Sprintf("Timestamp test: %v", i), func(t *testing.T) {
   226  			params := beacon.PayloadAttributesV1{
   227  				Timestamp:             test.time,
   228  				Random:                crypto.Keccak256Hash([]byte{byte(123)}),
   229  				SuggestedFeeRecipient: parent.Coinbase(),
   230  			}
   231  			fcState := beacon.ForkchoiceStateV1{
   232  				HeadBlockHash:      parent.Hash(),
   233  				SafeBlockHash:      common.Hash{},
   234  				FinalizedBlockHash: common.Hash{},
   235  			}
   236  			_, err := api.ForkchoiceUpdatedV1(fcState, &params)
   237  			if test.shouldErr && err == nil {
   238  				t.Fatalf("expected error preparing payload with invalid timestamp, err=%v", err)
   239  			} else if !test.shouldErr && err != nil {
   240  				t.Fatalf("error preparing payload with valid timestamp, err=%v", err)
   241  			}
   242  		})
   243  	}
   244  }
   245  
   246  func TestEth2NewBlock(t *testing.T) {
   247  	genesis, preMergeBlocks := generatePreMergeChain(10)
   248  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   249  	defer n.Close()
   250  
   251  	var (
   252  		api    = NewConsensusAPI(ethservice)
   253  		parent = preMergeBlocks[len(preMergeBlocks)-1]
   254  
   255  		// This EVM code generates a log when the contract is created.
   256  		logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
   257  	)
   258  	// The event channels.
   259  	newLogCh := make(chan []*types.Log, 10)
   260  	rmLogsCh := make(chan core.RemovedLogsEvent, 10)
   261  	ethservice.BlockChain().SubscribeLogsEvent(newLogCh)
   262  	ethservice.BlockChain().SubscribeRemovedLogsEvent(rmLogsCh)
   263  
   264  	for i := 0; i < 10; i++ {
   265  		statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
   266  		nonce := statedb.GetNonce(testAddr)
   267  		tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
   268  		ethservice.TxPool().AddLocal(tx)
   269  
   270  		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
   271  			Timestamp: parent.Time() + 5,
   272  		})
   273  		if err != nil {
   274  			t.Fatalf("Failed to create the executable data %v", err)
   275  		}
   276  		block, err := beacon.ExecutableDataToBlock(*execData)
   277  		if err != nil {
   278  			t.Fatalf("Failed to convert executable data to block %v", err)
   279  		}
   280  		newResp, err := api.NewPayloadV1(*execData)
   281  		switch {
   282  		case err != nil:
   283  			t.Fatalf("Failed to insert block: %v", err)
   284  		case newResp.Status != "VALID":
   285  			t.Fatalf("Failed to insert block: %v", newResp.Status)
   286  		case ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1:
   287  			t.Fatalf("Chain head shouldn't be updated")
   288  		}
   289  		checkLogEvents(t, newLogCh, rmLogsCh, 0, 0)
   290  		fcState := beacon.ForkchoiceStateV1{
   291  			HeadBlockHash:      block.Hash(),
   292  			SafeBlockHash:      block.Hash(),
   293  			FinalizedBlockHash: block.Hash(),
   294  		}
   295  		if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
   296  			t.Fatalf("Failed to insert block: %v", err)
   297  		}
   298  		if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want {
   299  			t.Fatalf("Chain head should be updated, have %d want %d", have, want)
   300  		}
   301  		checkLogEvents(t, newLogCh, rmLogsCh, 1, 0)
   302  
   303  		parent = block
   304  	}
   305  
   306  	// Introduce fork chain
   307  	var (
   308  		head = ethservice.BlockChain().CurrentBlock().NumberU64()
   309  	)
   310  	parent = preMergeBlocks[len(preMergeBlocks)-1]
   311  	for i := 0; i < 10; i++ {
   312  		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
   313  			Timestamp: parent.Time() + 6,
   314  		})
   315  		if err != nil {
   316  			t.Fatalf("Failed to create the executable data %v", err)
   317  		}
   318  		block, err := beacon.ExecutableDataToBlock(*execData)
   319  		if err != nil {
   320  			t.Fatalf("Failed to convert executable data to block %v", err)
   321  		}
   322  		newResp, err := api.NewPayloadV1(*execData)
   323  		if err != nil || newResp.Status != "VALID" {
   324  			t.Fatalf("Failed to insert block: %v", err)
   325  		}
   326  		if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
   327  			t.Fatalf("Chain head shouldn't be updated")
   328  		}
   329  
   330  		fcState := beacon.ForkchoiceStateV1{
   331  			HeadBlockHash:      block.Hash(),
   332  			SafeBlockHash:      block.Hash(),
   333  			FinalizedBlockHash: block.Hash(),
   334  		}
   335  		if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
   336  			t.Fatalf("Failed to insert block: %v", err)
   337  		}
   338  		if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
   339  			t.Fatalf("Chain head should be updated")
   340  		}
   341  		parent, head = block, block.NumberU64()
   342  	}
   343  }
   344  
   345  func TestEth2DeepReorg(t *testing.T) {
   346  	// TODO (MariusVanDerWijden) TestEth2DeepReorg is currently broken, because it tries to reorg
   347  	// before the totalTerminalDifficulty threshold
   348  	/*
   349  		genesis, preMergeBlocks := generatePreMergeChain(core.TriesInMemory * 2)
   350  		n, ethservice := startEthService(t, genesis, preMergeBlocks)
   351  		defer n.Close()
   352  
   353  		var (
   354  			api    = NewConsensusAPI(ethservice, nil)
   355  			parent = preMergeBlocks[len(preMergeBlocks)-core.TriesInMemory-1]
   356  			head   = ethservice.BlockChain().CurrentBlock().NumberU64()
   357  		)
   358  		if ethservice.BlockChain().HasBlockAndState(parent.Hash(), parent.NumberU64()) {
   359  			t.Errorf("Block %d not pruned", parent.NumberU64())
   360  		}
   361  		for i := 0; i < 10; i++ {
   362  			execData, err := api.assembleBlock(AssembleBlockParams{
   363  				ParentHash: parent.Hash(),
   364  				Timestamp:  parent.Time() + 5,
   365  			})
   366  			if err != nil {
   367  				t.Fatalf("Failed to create the executable data %v", err)
   368  			}
   369  			block, err := ExecutableDataToBlock(ethservice.BlockChain().Config(), parent.Header(), *execData)
   370  			if err != nil {
   371  				t.Fatalf("Failed to convert executable data to block %v", err)
   372  			}
   373  			newResp, err := api.ExecutePayload(*execData)
   374  			if err != nil || newResp.Status != "VALID" {
   375  				t.Fatalf("Failed to insert block: %v", err)
   376  			}
   377  			if ethservice.BlockChain().CurrentBlock().NumberU64() != head {
   378  				t.Fatalf("Chain head shouldn't be updated")
   379  			}
   380  			if err := api.setHead(block.Hash()); err != nil {
   381  				t.Fatalf("Failed to set head: %v", err)
   382  			}
   383  			if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64() {
   384  				t.Fatalf("Chain head should be updated")
   385  			}
   386  			parent, head = block, block.NumberU64()
   387  		}
   388  	*/
   389  }
   390  
   391  // startEthService creates a full node instance for testing.
   392  func startEthService(t *testing.T, genesis *core.Genesis, blocks []*types.Block) (*node.Node, *eth.Ethereum) {
   393  	t.Helper()
   394  
   395  	n, err := node.New(&node.Config{
   396  		P2P: p2p.Config{
   397  			ListenAddr:  "0.0.0.0:0",
   398  			NoDiscovery: true,
   399  			MaxPeers:    25,
   400  		}})
   401  	if err != nil {
   402  		t.Fatal("can't create node:", err)
   403  	}
   404  
   405  	ethcfg := &ethconfig.Config{Genesis: genesis, Ethash: ethash.Config{PowMode: ethash.ModeFake}, SyncMode: downloader.FullSync, TrieTimeout: time.Minute, TrieDirtyCache: 256, TrieCleanCache: 256}
   406  	ethservice, err := eth.New(n, ethcfg)
   407  	if err != nil {
   408  		t.Fatal("can't create eth service:", err)
   409  	}
   410  	if err := n.Start(); err != nil {
   411  		t.Fatal("can't start node:", err)
   412  	}
   413  	if _, err := ethservice.BlockChain().InsertChain(blocks); err != nil {
   414  		n.Close()
   415  		t.Fatal("can't import test blocks:", err)
   416  	}
   417  
   418  	ethservice.SetEtherbase(testAddr)
   419  	ethservice.SetSynced()
   420  	return n, ethservice
   421  }
   422  
   423  func TestFullAPI(t *testing.T) {
   424  	genesis, preMergeBlocks := generatePreMergeChain(10)
   425  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   426  	defer n.Close()
   427  	var (
   428  		parent = ethservice.BlockChain().CurrentBlock()
   429  		// This EVM code generates a log when the contract is created.
   430  		logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
   431  	)
   432  
   433  	callback := func(parent *types.Block) {
   434  		statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
   435  		nonce := statedb.GetNonce(testAddr)
   436  		tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
   437  		ethservice.TxPool().AddLocal(tx)
   438  	}
   439  
   440  	setupBlocks(t, ethservice, 10, parent, callback)
   441  }
   442  
   443  func setupBlocks(t *testing.T, ethservice *eth.Ethereum, n int, parent *types.Block, callback func(parent *types.Block)) {
   444  	api := NewConsensusAPI(ethservice)
   445  	for i := 0; i < n; i++ {
   446  		callback(parent)
   447  
   448  		payload := getNewPayload(t, api, parent)
   449  
   450  		execResp, err := api.NewPayloadV1(*payload)
   451  		if err != nil {
   452  			t.Fatalf("can't execute payload: %v", err)
   453  		}
   454  		if execResp.Status != beacon.VALID {
   455  			t.Fatalf("invalid status: %v", execResp.Status)
   456  		}
   457  		fcState := beacon.ForkchoiceStateV1{
   458  			HeadBlockHash:      payload.BlockHash,
   459  			SafeBlockHash:      payload.ParentHash,
   460  			FinalizedBlockHash: payload.ParentHash,
   461  		}
   462  		if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
   463  			t.Fatalf("Failed to insert block: %v", err)
   464  		}
   465  		if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
   466  			t.Fatal("Chain head should be updated")
   467  		}
   468  		if ethservice.BlockChain().CurrentFinalizedBlock().NumberU64() != payload.Number-1 {
   469  			t.Fatal("Finalized block should be updated")
   470  		}
   471  		parent = ethservice.BlockChain().CurrentBlock()
   472  	}
   473  }
   474  
   475  func TestExchangeTransitionConfig(t *testing.T) {
   476  	genesis, preMergeBlocks := generatePreMergeChain(10)
   477  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   478  	defer n.Close()
   479  	var (
   480  		api = NewConsensusAPI(ethservice)
   481  	)
   482  	// invalid ttd
   483  	config := beacon.TransitionConfigurationV1{
   484  		TerminalTotalDifficulty: (*hexutil.Big)(big.NewInt(0)),
   485  		TerminalBlockHash:       common.Hash{},
   486  		TerminalBlockNumber:     0,
   487  	}
   488  	if _, err := api.ExchangeTransitionConfigurationV1(config); err == nil {
   489  		t.Fatal("expected error on invalid config, invalid ttd")
   490  	}
   491  	// invalid terminal block hash
   492  	config = beacon.TransitionConfigurationV1{
   493  		TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
   494  		TerminalBlockHash:       common.Hash{1},
   495  		TerminalBlockNumber:     0,
   496  	}
   497  	if _, err := api.ExchangeTransitionConfigurationV1(config); err == nil {
   498  		t.Fatal("expected error on invalid config, invalid hash")
   499  	}
   500  	// valid config
   501  	config = beacon.TransitionConfigurationV1{
   502  		TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
   503  		TerminalBlockHash:       common.Hash{},
   504  		TerminalBlockNumber:     0,
   505  	}
   506  	if _, err := api.ExchangeTransitionConfigurationV1(config); err != nil {
   507  		t.Fatalf("expected no error on valid config, got %v", err)
   508  	}
   509  	// valid config
   510  	config = beacon.TransitionConfigurationV1{
   511  		TerminalTotalDifficulty: (*hexutil.Big)(genesis.Config.TerminalTotalDifficulty),
   512  		TerminalBlockHash:       preMergeBlocks[5].Hash(),
   513  		TerminalBlockNumber:     6,
   514  	}
   515  	if _, err := api.ExchangeTransitionConfigurationV1(config); err != nil {
   516  		t.Fatalf("expected no error on valid config, got %v", err)
   517  	}
   518  }
   519  
   520  /*
   521  TestNewPayloadOnInvalidChain sets up a valid chain and tries to feed blocks
   522  from an invalid chain to test if latestValidHash (LVH) works correctly.
   523  
   524  We set up the following chain where P1 ... Pn and P1” are valid while
   525  P1' is invalid.
   526  We expect
   527  (1) The LVH to point to the current inserted payload if it was valid.
   528  (2) The LVH to point to the valid parent on an invalid payload (if the parent is available).
   529  (3) If the parent is unavailable, the LVH should not be set.
   530  
   531  	CommonAncestor◄─▲── P1 ◄── P2  ◄─ P3  ◄─ ... ◄─ Pn
   532  	                │
   533  	                └── P1' ◄─ P2' ◄─ P3' ◄─ ... ◄─ Pn'
   534  	                │
   535  	                └── P1''
   536  */
   537  func TestNewPayloadOnInvalidChain(t *testing.T) {
   538  	genesis, preMergeBlocks := generatePreMergeChain(10)
   539  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   540  	defer n.Close()
   541  
   542  	var (
   543  		api    = NewConsensusAPI(ethservice)
   544  		parent = ethservice.BlockChain().CurrentBlock()
   545  		// This EVM code generates a log when the contract is created.
   546  		logCode = common.Hex2Bytes("60606040525b7f24ec1d3ff24c2f6ff210738839dbc339cd45a5294d85c79361016243157aae7b60405180905060405180910390a15b600a8060416000396000f360606040526008565b00")
   547  	)
   548  	for i := 0; i < 10; i++ {
   549  		statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
   550  		nonce := statedb.GetNonce(testAddr)
   551  		tx, _ := types.SignTx(types.NewContractCreation(nonce, new(big.Int), 1000000, big.NewInt(2*params.InitialBaseFee), logCode), types.LatestSigner(ethservice.BlockChain().Config()), testKey)
   552  		ethservice.TxPool().AddLocal(tx)
   553  
   554  		params := beacon.PayloadAttributesV1{
   555  			Timestamp:             parent.Time() + 1,
   556  			Random:                crypto.Keccak256Hash([]byte{byte(i)}),
   557  			SuggestedFeeRecipient: parent.Coinbase(),
   558  		}
   559  
   560  		fcState := beacon.ForkchoiceStateV1{
   561  			HeadBlockHash:      parent.Hash(),
   562  			SafeBlockHash:      common.Hash{},
   563  			FinalizedBlockHash: common.Hash{},
   564  		}
   565  		resp, err := api.ForkchoiceUpdatedV1(fcState, &params)
   566  		if err != nil {
   567  			t.Fatalf("error preparing payload, err=%v", err)
   568  		}
   569  		if resp.PayloadStatus.Status != beacon.VALID {
   570  			t.Fatalf("error preparing payload, invalid status: %v", resp.PayloadStatus.Status)
   571  		}
   572  		payload, err := api.GetPayloadV1(*resp.PayloadID)
   573  		if err != nil {
   574  			t.Fatalf("can't get payload: %v", err)
   575  		}
   576  		// TODO(493456442, marius) this test can be flaky since we rely on a 100ms
   577  		// allowance for block generation internally.
   578  		if len(payload.Transactions) == 0 {
   579  			t.Fatalf("payload should not be empty")
   580  		}
   581  		execResp, err := api.NewPayloadV1(*payload)
   582  		if err != nil {
   583  			t.Fatalf("can't execute payload: %v", err)
   584  		}
   585  		if execResp.Status != beacon.VALID {
   586  			t.Fatalf("invalid status: %v", execResp.Status)
   587  		}
   588  		fcState = beacon.ForkchoiceStateV1{
   589  			HeadBlockHash:      payload.BlockHash,
   590  			SafeBlockHash:      payload.ParentHash,
   591  			FinalizedBlockHash: payload.ParentHash,
   592  		}
   593  		if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
   594  			t.Fatalf("Failed to insert block: %v", err)
   595  		}
   596  		if ethservice.BlockChain().CurrentBlock().NumberU64() != payload.Number {
   597  			t.Fatalf("Chain head should be updated")
   598  		}
   599  		parent = ethservice.BlockChain().CurrentBlock()
   600  	}
   601  }
   602  
   603  func assembleBlock(api *ConsensusAPI, parentHash common.Hash, params *beacon.PayloadAttributesV1) (*beacon.ExecutableDataV1, error) {
   604  	block, err := api.eth.Miner().GetSealingBlockSync(parentHash, params.Timestamp, params.SuggestedFeeRecipient, params.Random, false)
   605  	if err != nil {
   606  		return nil, err
   607  	}
   608  	return beacon.BlockToExecutableData(block), nil
   609  }
   610  
   611  func TestEmptyBlocks(t *testing.T) {
   612  	genesis, preMergeBlocks := generatePreMergeChain(10)
   613  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   614  	defer n.Close()
   615  
   616  	commonAncestor := ethservice.BlockChain().CurrentBlock()
   617  	api := NewConsensusAPI(ethservice)
   618  
   619  	// Setup 10 blocks on the canonical chain
   620  	setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
   621  
   622  	// (1) check LatestValidHash by sending a normal payload (P1'')
   623  	payload := getNewPayload(t, api, commonAncestor)
   624  
   625  	status, err := api.NewPayloadV1(*payload)
   626  	if err != nil {
   627  		t.Fatal(err)
   628  	}
   629  	if status.Status != beacon.VALID {
   630  		t.Errorf("invalid status: expected VALID got: %v", status.Status)
   631  	}
   632  	if !bytes.Equal(status.LatestValidHash[:], payload.BlockHash[:]) {
   633  		t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, payload.BlockHash)
   634  	}
   635  
   636  	// (2) Now send P1' which is invalid
   637  	payload = getNewPayload(t, api, commonAncestor)
   638  	payload.GasUsed += 1
   639  	payload = setBlockhash(payload)
   640  	// Now latestValidHash should be the common ancestor
   641  	status, err = api.NewPayloadV1(*payload)
   642  	if err != nil {
   643  		t.Fatal(err)
   644  	}
   645  	if status.Status != beacon.INVALID {
   646  		t.Errorf("invalid status: expected INVALID got: %v", status.Status)
   647  	}
   648  	// Expect 0x0 on INVALID block on top of PoW block
   649  	expected := common.Hash{}
   650  	if !bytes.Equal(status.LatestValidHash[:], expected[:]) {
   651  		t.Fatalf("invalid LVH: got %v want %v", status.LatestValidHash, expected)
   652  	}
   653  
   654  	// (3) Now send a payload with unknown parent
   655  	payload = getNewPayload(t, api, commonAncestor)
   656  	payload.ParentHash = common.Hash{1}
   657  	payload = setBlockhash(payload)
   658  	// Now latestValidHash should be the common ancestor
   659  	status, err = api.NewPayloadV1(*payload)
   660  	if err != nil {
   661  		t.Fatal(err)
   662  	}
   663  	if status.Status != beacon.SYNCING {
   664  		t.Errorf("invalid status: expected SYNCING got: %v", status.Status)
   665  	}
   666  	if status.LatestValidHash != nil {
   667  		t.Fatalf("invalid LVH: got %v wanted nil", status.LatestValidHash)
   668  	}
   669  }
   670  
   671  func getNewPayload(t *testing.T, api *ConsensusAPI, parent *types.Block) *beacon.ExecutableDataV1 {
   672  	params := beacon.PayloadAttributesV1{
   673  		Timestamp:             parent.Time() + 1,
   674  		Random:                crypto.Keccak256Hash([]byte{byte(1)}),
   675  		SuggestedFeeRecipient: parent.Coinbase(),
   676  	}
   677  
   678  	payload, err := assembleBlock(api, parent.Hash(), &params)
   679  	if err != nil {
   680  		t.Fatal(err)
   681  	}
   682  	return payload
   683  }
   684  
   685  // setBlockhash sets the blockhash of a modified ExecutableData.
   686  // Can be used to make modified payloads look valid.
   687  func setBlockhash(data *beacon.ExecutableDataV1) *beacon.ExecutableDataV1 {
   688  	txs, _ := decodeTransactions(data.Transactions)
   689  	number := big.NewInt(0)
   690  	number.SetUint64(data.Number)
   691  	header := &types.Header{
   692  		ParentHash:  data.ParentHash,
   693  		UncleHash:   types.EmptyUncleHash,
   694  		Coinbase:    data.FeeRecipient,
   695  		Root:        data.StateRoot,
   696  		TxHash:      types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
   697  		ReceiptHash: data.ReceiptsRoot,
   698  		Bloom:       types.BytesToBloom(data.LogsBloom),
   699  		Difficulty:  common.Big0,
   700  		Number:      number,
   701  		GasLimit:    data.GasLimit,
   702  		GasUsed:     data.GasUsed,
   703  		Time:        data.Timestamp,
   704  		BaseFee:     data.BaseFeePerGas,
   705  		Extra:       data.ExtraData,
   706  		MixDigest:   data.Random,
   707  	}
   708  	block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */)
   709  	data.BlockHash = block.Hash()
   710  	return data
   711  }
   712  
   713  func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
   714  	var txs = make([]*types.Transaction, len(enc))
   715  	for i, encTx := range enc {
   716  		var tx types.Transaction
   717  		if err := tx.UnmarshalBinary(encTx); err != nil {
   718  			return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
   719  		}
   720  		txs[i] = &tx
   721  	}
   722  	return txs, nil
   723  }
   724  
   725  func TestTrickRemoteBlockCache(t *testing.T) {
   726  	// Setup two nodes
   727  	genesis, preMergeBlocks := generatePreMergeChain(10)
   728  	nodeA, ethserviceA := startEthService(t, genesis, preMergeBlocks)
   729  	nodeB, ethserviceB := startEthService(t, genesis, preMergeBlocks)
   730  	defer nodeA.Close()
   731  	defer nodeB.Close()
   732  	for nodeB.Server().NodeInfo().Ports.Listener == 0 {
   733  		time.Sleep(250 * time.Millisecond)
   734  	}
   735  	nodeA.Server().AddPeer(nodeB.Server().Self())
   736  	nodeB.Server().AddPeer(nodeA.Server().Self())
   737  	apiA := NewConsensusAPI(ethserviceA)
   738  	apiB := NewConsensusAPI(ethserviceB)
   739  
   740  	commonAncestor := ethserviceA.BlockChain().CurrentBlock()
   741  
   742  	// Setup 10 blocks on the canonical chain
   743  	setupBlocks(t, ethserviceA, 10, commonAncestor, func(parent *types.Block) {})
   744  	commonAncestor = ethserviceA.BlockChain().CurrentBlock()
   745  
   746  	var invalidChain []*beacon.ExecutableDataV1
   747  	// create a valid payload (P1)
   748  	//payload1 := getNewPayload(t, apiA, commonAncestor)
   749  	//invalidChain = append(invalidChain, payload1)
   750  
   751  	// create an invalid payload2 (P2)
   752  	payload2 := getNewPayload(t, apiA, commonAncestor)
   753  	//payload2.ParentHash = payload1.BlockHash
   754  	payload2.GasUsed += 1
   755  	payload2 = setBlockhash(payload2)
   756  	invalidChain = append(invalidChain, payload2)
   757  
   758  	head := payload2
   759  	// create some valid payloads on top
   760  	for i := 0; i < 10; i++ {
   761  		payload := getNewPayload(t, apiA, commonAncestor)
   762  		payload.ParentHash = head.BlockHash
   763  		payload = setBlockhash(payload)
   764  		invalidChain = append(invalidChain, payload)
   765  		head = payload
   766  	}
   767  
   768  	// feed the payloads to node B
   769  	for _, payload := range invalidChain {
   770  		status, err := apiB.NewPayloadV1(*payload)
   771  		if err != nil {
   772  			panic(err)
   773  		}
   774  		if status.Status == beacon.VALID {
   775  			t.Error("invalid status: VALID on an invalid chain")
   776  		}
   777  		// Now reorg to the head of the invalid chain
   778  		resp, err := apiB.ForkchoiceUpdatedV1(beacon.ForkchoiceStateV1{HeadBlockHash: payload.BlockHash, SafeBlockHash: payload.BlockHash, FinalizedBlockHash: payload.ParentHash}, nil)
   779  		if err != nil {
   780  			t.Fatal(err)
   781  		}
   782  		if resp.PayloadStatus.Status == beacon.VALID {
   783  			t.Error("invalid status: VALID on an invalid chain")
   784  		}
   785  		time.Sleep(100 * time.Millisecond)
   786  	}
   787  }
   788  
   789  func TestInvalidBloom(t *testing.T) {
   790  	genesis, preMergeBlocks := generatePreMergeChain(10)
   791  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   792  	ethservice.Merger().ReachTTD()
   793  	defer n.Close()
   794  
   795  	commonAncestor := ethservice.BlockChain().CurrentBlock()
   796  	api := NewConsensusAPI(ethservice)
   797  
   798  	// Setup 10 blocks on the canonical chain
   799  	setupBlocks(t, ethservice, 10, commonAncestor, func(parent *types.Block) {})
   800  
   801  	// (1) check LatestValidHash by sending a normal payload (P1'')
   802  	payload := getNewPayload(t, api, commonAncestor)
   803  	payload.LogsBloom = append(payload.LogsBloom, byte(1))
   804  	status, err := api.NewPayloadV1(*payload)
   805  	if err != nil {
   806  		t.Fatal(err)
   807  	}
   808  	if status.Status != beacon.INVALIDBLOCKHASH {
   809  		t.Errorf("invalid status: expected VALID got: %v", status.Status)
   810  	}
   811  }
   812  
   813  func TestNewPayloadOnInvalidTerminalBlock(t *testing.T) {
   814  	genesis, preMergeBlocks := generatePreMergeChain(100)
   815  	fmt.Println(genesis.Config.TerminalTotalDifficulty)
   816  	genesis.Config.TerminalTotalDifficulty = preMergeBlocks[0].Difficulty() //.Sub(genesis.Config.TerminalTotalDifficulty, preMergeBlocks[len(preMergeBlocks)-1].Difficulty())
   817  
   818  	fmt.Println(genesis.Config.TerminalTotalDifficulty)
   819  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   820  	defer n.Close()
   821  
   822  	var (
   823  		api    = NewConsensusAPI(ethservice)
   824  		parent = preMergeBlocks[len(preMergeBlocks)-1]
   825  	)
   826  
   827  	// Test parent already post TTD in FCU
   828  	fcState := beacon.ForkchoiceStateV1{
   829  		HeadBlockHash:      parent.Hash(),
   830  		SafeBlockHash:      common.Hash{},
   831  		FinalizedBlockHash: common.Hash{},
   832  	}
   833  	resp, err := api.ForkchoiceUpdatedV1(fcState, nil)
   834  	if err != nil {
   835  		t.Fatalf("error sending forkchoice, err=%v", err)
   836  	}
   837  	if resp.PayloadStatus != beacon.INVALID_TERMINAL_BLOCK {
   838  		t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status)
   839  	}
   840  
   841  	// Test parent already post TTD in NewPayload
   842  	params := beacon.PayloadAttributesV1{
   843  		Timestamp:             parent.Time() + 1,
   844  		Random:                crypto.Keccak256Hash([]byte{byte(1)}),
   845  		SuggestedFeeRecipient: parent.Coinbase(),
   846  	}
   847  	empty, err := api.eth.Miner().GetSealingBlockSync(parent.Hash(), params.Timestamp, params.SuggestedFeeRecipient, params.Random, true)
   848  	if err != nil {
   849  		t.Fatalf("error preparing payload, err=%v", err)
   850  	}
   851  	data := *beacon.BlockToExecutableData(empty)
   852  	resp2, err := api.NewPayloadV1(data)
   853  	if err != nil {
   854  		t.Fatalf("error sending NewPayload, err=%v", err)
   855  	}
   856  	if resp2 != beacon.INVALID_TERMINAL_BLOCK {
   857  		t.Fatalf("error sending invalid forkchoice, invalid status: %v", resp.PayloadStatus.Status)
   858  	}
   859  }
   860  
   861  // TestSimultaneousNewBlock does several parallel inserts, both as
   862  // newPayLoad and forkchoiceUpdate. This is to test that the api behaves
   863  // well even of the caller is not being 'serial'.
   864  func TestSimultaneousNewBlock(t *testing.T) {
   865  	genesis, preMergeBlocks := generatePreMergeChain(10)
   866  	n, ethservice := startEthService(t, genesis, preMergeBlocks)
   867  	defer n.Close()
   868  
   869  	var (
   870  		api    = NewConsensusAPI(ethservice)
   871  		parent = preMergeBlocks[len(preMergeBlocks)-1]
   872  	)
   873  	for i := 0; i < 10; i++ {
   874  		statedb, _ := ethservice.BlockChain().StateAt(parent.Root())
   875  		ethservice.TxPool().AddLocal(types.MustSignNewTx(testKey, types.LatestSigner(ethservice.BlockChain().Config()),
   876  			&types.DynamicFeeTx{
   877  				Nonce:     statedb.GetNonce(testAddr),
   878  				Value:     big.NewInt(0),
   879  				GasFeeCap: big.NewInt(2 * params.InitialBaseFee),
   880  				GasTipCap: big.NewInt(2 * params.InitialBaseFee),
   881  				ChainID:   genesis.Config.ChainID,
   882  				Gas:       1000000,
   883  				To:        &common.Address{99},
   884  			}))
   885  		execData, err := assembleBlock(api, parent.Hash(), &beacon.PayloadAttributesV1{
   886  			Timestamp: parent.Time() + 5,
   887  		})
   888  		if err != nil {
   889  			t.Fatalf("Failed to create the executable data %v", err)
   890  		}
   891  		// Insert it 10 times in parallel. Should be ignored.
   892  		{
   893  			var (
   894  				wg      sync.WaitGroup
   895  				testErr error
   896  				errMu   sync.Mutex
   897  			)
   898  			wg.Add(10)
   899  			for ii := 0; ii < 10; ii++ {
   900  				go func() {
   901  					defer wg.Done()
   902  					if newResp, err := api.NewPayloadV1(*execData); err != nil {
   903  						errMu.Lock()
   904  						testErr = fmt.Errorf("Failed to insert block: %w", err)
   905  						errMu.Unlock()
   906  					} else if newResp.Status != "VALID" {
   907  						errMu.Lock()
   908  						testErr = fmt.Errorf("Failed to insert block: %v", newResp.Status)
   909  						errMu.Unlock()
   910  					}
   911  				}()
   912  			}
   913  			wg.Wait()
   914  			if testErr != nil {
   915  				t.Fatal(testErr)
   916  			}
   917  		}
   918  		block, err := beacon.ExecutableDataToBlock(*execData)
   919  		if err != nil {
   920  			t.Fatalf("Failed to convert executable data to block %v", err)
   921  		}
   922  		if ethservice.BlockChain().CurrentBlock().NumberU64() != block.NumberU64()-1 {
   923  			t.Fatalf("Chain head shouldn't be updated")
   924  		}
   925  		fcState := beacon.ForkchoiceStateV1{
   926  			HeadBlockHash:      block.Hash(),
   927  			SafeBlockHash:      block.Hash(),
   928  			FinalizedBlockHash: block.Hash(),
   929  		}
   930  		{
   931  			var (
   932  				wg      sync.WaitGroup
   933  				testErr error
   934  				errMu   sync.Mutex
   935  			)
   936  			wg.Add(10)
   937  			// Do each FCU 10 times
   938  			for ii := 0; ii < 10; ii++ {
   939  				go func() {
   940  					defer wg.Done()
   941  					if _, err := api.ForkchoiceUpdatedV1(fcState, nil); err != nil {
   942  						errMu.Lock()
   943  						testErr = fmt.Errorf("Failed to insert block: %w", err)
   944  						errMu.Unlock()
   945  					}
   946  				}()
   947  			}
   948  			wg.Wait()
   949  			if testErr != nil {
   950  				t.Fatal(testErr)
   951  			}
   952  		}
   953  		if have, want := ethservice.BlockChain().CurrentBlock().NumberU64(), block.NumberU64(); have != want {
   954  			t.Fatalf("Chain head should be updated, have %d want %d", have, want)
   955  		}
   956  		parent = block
   957  	}
   958  }