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