github.com/ethereum-optimism/optimism@v1.7.2/op-node/rollup/types_test.go (about)

     1  package rollup
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"fmt"
     7  	"math/big"
     8  	"math/rand"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  
    15  	"github.com/ethereum/go-ethereum/common"
    16  
    17  	"github.com/ethereum-optimism/optimism/op-service/eth"
    18  )
    19  
    20  func randConfig() *Config {
    21  	rng := rand.New(rand.NewSource(1234))
    22  	randHash := func() (out [32]byte) {
    23  		rng.Read(out[:])
    24  		return
    25  	}
    26  	randAddr := func() (out common.Address) { // we need generics...
    27  		rng.Read(out[:])
    28  		return
    29  	}
    30  	return &Config{
    31  		Genesis: Genesis{
    32  			L1:     eth.BlockID{Hash: randHash(), Number: 424242},
    33  			L2:     eth.BlockID{Hash: randHash(), Number: 1337},
    34  			L2Time: uint64(time.Now().Unix()),
    35  			SystemConfig: eth.SystemConfig{
    36  				BatcherAddr: randAddr(),
    37  				Overhead:    randHash(),
    38  				Scalar:      randHash(),
    39  				GasLimit:    1234567,
    40  			},
    41  		},
    42  		BlockTime:              2,
    43  		MaxSequencerDrift:      100,
    44  		SeqWindowSize:          2,
    45  		ChannelTimeout:         123,
    46  		L1ChainID:              big.NewInt(900),
    47  		L2ChainID:              big.NewInt(901),
    48  		BatchInboxAddress:      randAddr(),
    49  		DepositContractAddress: randAddr(),
    50  		L1SystemConfigAddress:  randAddr(),
    51  	}
    52  }
    53  
    54  func TestConfigJSON(t *testing.T) {
    55  	config := randConfig()
    56  	data, err := json.Marshal(config)
    57  	assert.NoError(t, err)
    58  	var roundTripped Config
    59  	assert.NoError(t, json.Unmarshal(data, &roundTripped))
    60  	assert.Equal(t, &roundTripped, config)
    61  }
    62  
    63  type mockL1Client struct {
    64  	chainID *big.Int
    65  	Hash    common.Hash
    66  }
    67  
    68  func (m *mockL1Client) ChainID(context.Context) (*big.Int, error) {
    69  	return m.chainID, nil
    70  }
    71  
    72  func (m *mockL1Client) L1BlockRefByNumber(ctx context.Context, number uint64) (eth.L1BlockRef, error) {
    73  	return eth.L1BlockRef{
    74  		Hash:   m.Hash,
    75  		Number: 100,
    76  	}, nil
    77  }
    78  
    79  func TestValidateL1Config(t *testing.T) {
    80  	config := randConfig()
    81  	config.L1ChainID = big.NewInt(100)
    82  	config.Genesis.L1.Number = 100
    83  	config.Genesis.L1.Hash = [32]byte{0x01}
    84  	mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
    85  	err := config.ValidateL1Config(context.TODO(), &mockClient)
    86  	assert.NoError(t, err)
    87  }
    88  
    89  func TestValidateL1ConfigInvalidChainIdFails(t *testing.T) {
    90  	config := randConfig()
    91  	config.L1ChainID = big.NewInt(101)
    92  	config.Genesis.L1.Number = 100
    93  	config.Genesis.L1.Hash = [32]byte{0x01}
    94  	mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
    95  	err := config.ValidateL1Config(context.TODO(), &mockClient)
    96  	assert.Error(t, err)
    97  	config.L1ChainID = big.NewInt(99)
    98  	err = config.ValidateL1Config(context.TODO(), &mockClient)
    99  	assert.Error(t, err)
   100  }
   101  
   102  func TestValidateL1ConfigInvalidGenesisHashFails(t *testing.T) {
   103  	config := randConfig()
   104  	config.L1ChainID = big.NewInt(100)
   105  	config.Genesis.L1.Number = 100
   106  	config.Genesis.L1.Hash = [32]byte{0x00}
   107  	mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   108  	err := config.ValidateL1Config(context.TODO(), &mockClient)
   109  	assert.Error(t, err)
   110  	config.Genesis.L1.Hash = [32]byte{0x02}
   111  	err = config.ValidateL1Config(context.TODO(), &mockClient)
   112  	assert.Error(t, err)
   113  }
   114  
   115  func TestCheckL1ChainID(t *testing.T) {
   116  	config := randConfig()
   117  	config.L1ChainID = big.NewInt(100)
   118  	err := config.CheckL1ChainID(context.TODO(), &mockL1Client{chainID: big.NewInt(100)})
   119  	assert.NoError(t, err)
   120  	err = config.CheckL1ChainID(context.TODO(), &mockL1Client{chainID: big.NewInt(101)})
   121  	assert.Error(t, err)
   122  	err = config.CheckL1ChainID(context.TODO(), &mockL1Client{chainID: big.NewInt(99)})
   123  	assert.Error(t, err)
   124  }
   125  
   126  func TestCheckL1BlockRefByNumber(t *testing.T) {
   127  	config := randConfig()
   128  	config.Genesis.L1.Number = 100
   129  	config.Genesis.L1.Hash = [32]byte{0x01}
   130  	mockClient := mockL1Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   131  	err := config.CheckL1GenesisBlockHash(context.TODO(), &mockClient)
   132  	assert.NoError(t, err)
   133  	mockClient.Hash = common.Hash{0x02}
   134  	err = config.CheckL1GenesisBlockHash(context.TODO(), &mockClient)
   135  	assert.Error(t, err)
   136  	mockClient.Hash = common.Hash{0x00}
   137  	err = config.CheckL1GenesisBlockHash(context.TODO(), &mockClient)
   138  	assert.Error(t, err)
   139  }
   140  
   141  // TestRandomConfigDescription tests that the description works for different variations of a random rollup config.
   142  func TestRandomConfigDescription(t *testing.T) {
   143  	t.Run("named L2", func(t *testing.T) {
   144  		config := randConfig()
   145  		out := config.Description(map[string]string{config.L2ChainID.String(): "foobar chain"})
   146  		require.Contains(t, out, "foobar chain")
   147  	})
   148  	t.Run("named L1", func(t *testing.T) {
   149  		config := randConfig()
   150  		config.L1ChainID = big.NewInt(5)
   151  		out := config.Description(map[string]string{config.L2ChainID.String(): "foobar chain"})
   152  		require.Contains(t, out, "goerli")
   153  	})
   154  	t.Run("unnamed", func(t *testing.T) {
   155  		config := randConfig()
   156  		out := config.Description(nil)
   157  		require.Contains(t, out, "(unknown L1)")
   158  		require.Contains(t, out, "(unknown L2)")
   159  	})
   160  	t.Run("regolith unset", func(t *testing.T) {
   161  		config := randConfig()
   162  		config.RegolithTime = nil
   163  		out := config.Description(nil)
   164  		require.Contains(t, out, "Regolith: (not configured)")
   165  	})
   166  	t.Run("regolith genesis", func(t *testing.T) {
   167  		config := randConfig()
   168  		config.RegolithTime = new(uint64)
   169  		out := config.Description(nil)
   170  		require.Contains(t, out, "Regolith: @ genesis")
   171  	})
   172  	t.Run("regolith date", func(t *testing.T) {
   173  		config := randConfig()
   174  		x := uint64(1677119335)
   175  		config.RegolithTime = &x
   176  		out := config.Description(nil)
   177  		// Don't check human-readable part of the date, it's timezone-dependent.
   178  		// Don't make this test fail only in Australia :')
   179  		require.Contains(t, out, fmt.Sprintf("Regolith: @ %d ~ ", x))
   180  	})
   181  }
   182  
   183  // TestRegolithActivation tests the activation condition of the Regolith upgrade.
   184  func TestRegolithActivation(t *testing.T) {
   185  	config := randConfig()
   186  	config.RegolithTime = nil
   187  	require.False(t, config.IsRegolith(0), "false if nil time, even if checking 0")
   188  	require.False(t, config.IsRegolith(123456), "false if nil time")
   189  	config.RegolithTime = new(uint64)
   190  	require.True(t, config.IsRegolith(0), "true at zero")
   191  	require.True(t, config.IsRegolith(123456), "true for any")
   192  	x := uint64(123)
   193  	config.RegolithTime = &x
   194  	require.False(t, config.IsRegolith(0))
   195  	require.False(t, config.IsRegolith(122))
   196  	require.True(t, config.IsRegolith(123))
   197  	require.True(t, config.IsRegolith(124))
   198  }
   199  
   200  type mockL2Client struct {
   201  	chainID *big.Int
   202  	Hash    common.Hash
   203  }
   204  
   205  func (m *mockL2Client) ChainID(context.Context) (*big.Int, error) {
   206  	return m.chainID, nil
   207  }
   208  
   209  func (m *mockL2Client) L2BlockRefByNumber(ctx context.Context, number uint64) (eth.L2BlockRef, error) {
   210  	return eth.L2BlockRef{
   211  		Hash:   m.Hash,
   212  		Number: 100,
   213  	}, nil
   214  }
   215  
   216  func TestValidateL2Config(t *testing.T) {
   217  	config := randConfig()
   218  	config.L2ChainID = big.NewInt(100)
   219  	config.Genesis.L2.Number = 100
   220  	config.Genesis.L2.Hash = [32]byte{0x01}
   221  	mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   222  	err := config.ValidateL2Config(context.TODO(), &mockClient, false)
   223  	assert.NoError(t, err)
   224  }
   225  
   226  func TestValidateL2ConfigInvalidChainIdFails(t *testing.T) {
   227  	config := randConfig()
   228  	config.L2ChainID = big.NewInt(101)
   229  	config.Genesis.L2.Number = 100
   230  	config.Genesis.L2.Hash = [32]byte{0x01}
   231  	mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   232  	err := config.ValidateL2Config(context.TODO(), &mockClient, false)
   233  	assert.Error(t, err)
   234  	config.L2ChainID = big.NewInt(99)
   235  	err = config.ValidateL2Config(context.TODO(), &mockClient, false)
   236  	assert.Error(t, err)
   237  }
   238  
   239  func TestValidateL2ConfigInvalidGenesisHashFails(t *testing.T) {
   240  	config := randConfig()
   241  	config.L2ChainID = big.NewInt(100)
   242  	config.Genesis.L2.Number = 100
   243  	config.Genesis.L2.Hash = [32]byte{0x00}
   244  	mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   245  	err := config.ValidateL2Config(context.TODO(), &mockClient, false)
   246  	assert.Error(t, err)
   247  	config.Genesis.L2.Hash = [32]byte{0x02}
   248  	err = config.ValidateL2Config(context.TODO(), &mockClient, false)
   249  	assert.Error(t, err)
   250  }
   251  
   252  func TestValidateL2ConfigInvalidGenesisHashSkippedWhenRequested(t *testing.T) {
   253  	config := randConfig()
   254  	config.L2ChainID = big.NewInt(100)
   255  	config.Genesis.L2.Number = 100
   256  	config.Genesis.L2.Hash = [32]byte{0x00}
   257  	mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   258  	err := config.ValidateL2Config(context.TODO(), &mockClient, true)
   259  	assert.NoError(t, err)
   260  	config.Genesis.L2.Hash = [32]byte{0x02}
   261  	err = config.ValidateL2Config(context.TODO(), &mockClient, true)
   262  	assert.NoError(t, err)
   263  }
   264  
   265  func TestCheckL2ChainID(t *testing.T) {
   266  	config := randConfig()
   267  	config.L2ChainID = big.NewInt(100)
   268  	err := config.CheckL2ChainID(context.TODO(), &mockL2Client{chainID: big.NewInt(100)})
   269  	assert.NoError(t, err)
   270  	err = config.CheckL2ChainID(context.TODO(), &mockL2Client{chainID: big.NewInt(101)})
   271  	assert.Error(t, err)
   272  	err = config.CheckL2ChainID(context.TODO(), &mockL2Client{chainID: big.NewInt(99)})
   273  	assert.Error(t, err)
   274  }
   275  
   276  func TestCheckL2BlockRefByNumber(t *testing.T) {
   277  	config := randConfig()
   278  	config.Genesis.L2.Number = 100
   279  	config.Genesis.L2.Hash = [32]byte{0x01}
   280  	mockClient := mockL2Client{chainID: big.NewInt(100), Hash: common.Hash{0x01}}
   281  	err := config.CheckL2GenesisBlockHash(context.TODO(), &mockClient)
   282  	assert.NoError(t, err)
   283  	mockClient.Hash = common.Hash{0x02}
   284  	err = config.CheckL2GenesisBlockHash(context.TODO(), &mockClient)
   285  	assert.Error(t, err)
   286  	mockClient.Hash = common.Hash{0x00}
   287  	err = config.CheckL2GenesisBlockHash(context.TODO(), &mockClient)
   288  	assert.Error(t, err)
   289  }
   290  
   291  func TestConfig_Check(t *testing.T) {
   292  	tests := []struct {
   293  		name        string
   294  		modifier    func(cfg *Config)
   295  		expectedErr error
   296  	}{
   297  		{
   298  			name:        "BlockTimeZero",
   299  			modifier:    func(cfg *Config) { cfg.BlockTime = 0 },
   300  			expectedErr: ErrBlockTimeZero,
   301  		},
   302  		{
   303  			name:        "ChannelTimeoutZero",
   304  			modifier:    func(cfg *Config) { cfg.ChannelTimeout = 0 },
   305  			expectedErr: ErrMissingChannelTimeout,
   306  		},
   307  		{
   308  			name:        "SeqWindowSizeZero",
   309  			modifier:    func(cfg *Config) { cfg.SeqWindowSize = 0 },
   310  			expectedErr: ErrInvalidSeqWindowSize,
   311  		},
   312  		{
   313  			name:        "SeqWindowSizeOne",
   314  			modifier:    func(cfg *Config) { cfg.SeqWindowSize = 1 },
   315  			expectedErr: ErrInvalidSeqWindowSize,
   316  		},
   317  		{
   318  			name:        "NoL1Genesis",
   319  			modifier:    func(cfg *Config) { cfg.Genesis.L1.Hash = common.Hash{} },
   320  			expectedErr: ErrMissingGenesisL1Hash,
   321  		},
   322  		{
   323  			name:        "NoL2Genesis",
   324  			modifier:    func(cfg *Config) { cfg.Genesis.L2.Hash = common.Hash{} },
   325  			expectedErr: ErrMissingGenesisL2Hash,
   326  		},
   327  		{
   328  			name:        "GenesisHashesEqual",
   329  			modifier:    func(cfg *Config) { cfg.Genesis.L2.Hash = cfg.Genesis.L1.Hash },
   330  			expectedErr: ErrGenesisHashesSame,
   331  		},
   332  		{
   333  			name:        "GenesisL2TimeZero",
   334  			modifier:    func(cfg *Config) { cfg.Genesis.L2Time = 0 },
   335  			expectedErr: ErrMissingGenesisL2Time,
   336  		},
   337  		{
   338  			name:        "NoBatcherAddr",
   339  			modifier:    func(cfg *Config) { cfg.Genesis.SystemConfig.BatcherAddr = common.Address{} },
   340  			expectedErr: ErrMissingBatcherAddr,
   341  		},
   342  		{
   343  			name:        "NoOverhead",
   344  			modifier:    func(cfg *Config) { cfg.Genesis.SystemConfig.Overhead = eth.Bytes32{} },
   345  			expectedErr: ErrMissingOverhead,
   346  		},
   347  		{
   348  			name:        "NoScalar",
   349  			modifier:    func(cfg *Config) { cfg.Genesis.SystemConfig.Scalar = eth.Bytes32{} },
   350  			expectedErr: ErrMissingScalar,
   351  		},
   352  		{
   353  			name:        "NoGasLimit",
   354  			modifier:    func(cfg *Config) { cfg.Genesis.SystemConfig.GasLimit = 0 },
   355  			expectedErr: ErrMissingGasLimit,
   356  		},
   357  		{
   358  			name:        "NoBatchInboxAddress",
   359  			modifier:    func(cfg *Config) { cfg.BatchInboxAddress = common.Address{} },
   360  			expectedErr: ErrMissingBatchInboxAddress,
   361  		},
   362  		{
   363  			name:        "NoDepositContractAddress",
   364  			modifier:    func(cfg *Config) { cfg.DepositContractAddress = common.Address{} },
   365  			expectedErr: ErrMissingDepositContractAddress,
   366  		},
   367  		{
   368  			name:        "NoL1ChainId",
   369  			modifier:    func(cfg *Config) { cfg.L1ChainID = nil },
   370  			expectedErr: ErrMissingL1ChainID,
   371  		},
   372  		{
   373  			name:        "NoL2ChainId",
   374  			modifier:    func(cfg *Config) { cfg.L2ChainID = nil },
   375  			expectedErr: ErrMissingL2ChainID,
   376  		},
   377  		{
   378  			name:        "ChainIDsEqual",
   379  			modifier:    func(cfg *Config) { cfg.L2ChainID = cfg.L1ChainID },
   380  			expectedErr: ErrChainIDsSame,
   381  		},
   382  		{
   383  			name:        "L1ChainIdNegative",
   384  			modifier:    func(cfg *Config) { cfg.L1ChainID = big.NewInt(-1) },
   385  			expectedErr: ErrL1ChainIDNotPositive,
   386  		},
   387  		{
   388  			name:        "L1ChainIdZero",
   389  			modifier:    func(cfg *Config) { cfg.L1ChainID = big.NewInt(0) },
   390  			expectedErr: ErrL1ChainIDNotPositive,
   391  		},
   392  		{
   393  			name:        "L2ChainIdNegative",
   394  			modifier:    func(cfg *Config) { cfg.L2ChainID = big.NewInt(-1) },
   395  			expectedErr: ErrL2ChainIDNotPositive,
   396  		},
   397  		{
   398  			name:        "L2ChainIdZero",
   399  			modifier:    func(cfg *Config) { cfg.L2ChainID = big.NewInt(0) },
   400  			expectedErr: ErrL2ChainIDNotPositive,
   401  		},
   402  	}
   403  	for _, test := range tests {
   404  		t.Run(test.name, func(t *testing.T) {
   405  			cfg := randConfig()
   406  			test.modifier(cfg)
   407  			err := cfg.Check()
   408  			assert.Same(t, err, test.expectedErr)
   409  		})
   410  	}
   411  
   412  	forkTests := []struct {
   413  		name        string
   414  		modifier    func(cfg *Config)
   415  		expectedErr error
   416  	}{
   417  		{
   418  			name: "PriorForkMissing",
   419  			modifier: func(cfg *Config) {
   420  				ecotoneTime := uint64(1)
   421  				cfg.EcotoneTime = &ecotoneTime
   422  			},
   423  			expectedErr: fmt.Errorf("fork ecotone set (to 1), but prior fork delta missing"),
   424  		},
   425  		{
   426  			name: "PriorForkHasHigherOffset",
   427  			modifier: func(cfg *Config) {
   428  				regolithTime := uint64(2)
   429  				canyonTime := uint64(1)
   430  				cfg.RegolithTime = &regolithTime
   431  				cfg.CanyonTime = &canyonTime
   432  			},
   433  			expectedErr: fmt.Errorf("fork canyon set to 1, but prior fork regolith has higher offset 2"),
   434  		},
   435  		{
   436  			name: "PriorForkOK",
   437  			modifier: func(cfg *Config) {
   438  				regolithTime := uint64(1)
   439  				canyonTime := uint64(2)
   440  				deltaTime := uint64(3)
   441  				ecotoneTime := uint64(4)
   442  				cfg.RegolithTime = &regolithTime
   443  				cfg.CanyonTime = &canyonTime
   444  				cfg.DeltaTime = &deltaTime
   445  				cfg.EcotoneTime = &ecotoneTime
   446  			},
   447  			expectedErr: nil,
   448  		},
   449  	}
   450  
   451  	for _, test := range forkTests {
   452  		t.Run(test.name, func(t *testing.T) {
   453  			cfg := randConfig()
   454  			test.modifier(cfg)
   455  			err := cfg.Check()
   456  			assert.Equal(t, err, test.expectedErr)
   457  		})
   458  	}
   459  }
   460  
   461  func TestTimestampForBlock(t *testing.T) {
   462  	config := randConfig()
   463  
   464  	tests := []struct {
   465  		name              string
   466  		genesisTime       uint64
   467  		genesisBlock      uint64
   468  		blockTime         uint64
   469  		blockNum          uint64
   470  		expectedBlockTime uint64
   471  	}{
   472  		{
   473  			name:              "FirstBlock",
   474  			genesisTime:       100,
   475  			genesisBlock:      0,
   476  			blockTime:         2,
   477  			blockNum:          0,
   478  			expectedBlockTime: 100,
   479  		},
   480  		{
   481  			name:              "SecondBlock",
   482  			genesisTime:       100,
   483  			genesisBlock:      0,
   484  			blockTime:         2,
   485  			blockNum:          1,
   486  			expectedBlockTime: 102,
   487  		},
   488  		{
   489  			name:              "NBlock",
   490  			genesisTime:       100,
   491  			genesisBlock:      0,
   492  			blockTime:         2,
   493  			blockNum:          25,
   494  			expectedBlockTime: 150,
   495  		},
   496  	}
   497  
   498  	for _, test := range tests {
   499  		test := test
   500  		t.Run(fmt.Sprintf("TestTimestampForBlock_%s", test.name), func(t *testing.T) {
   501  			config.Genesis.L2Time = test.genesisTime
   502  			config.Genesis.L2.Number = test.genesisBlock
   503  			config.BlockTime = test.blockTime
   504  
   505  			timestamp := config.TimestampForBlock(test.blockNum)
   506  			assert.Equal(t, timestamp, test.expectedBlockTime)
   507  		})
   508  	}
   509  
   510  }
   511  
   512  func TestForkchoiceUpdatedVersion(t *testing.T) {
   513  	config := randConfig()
   514  	tests := []struct {
   515  		name           string
   516  		canyonTime     uint64
   517  		ecotoneTime    uint64
   518  		attrs          *eth.PayloadAttributes
   519  		expectedMethod eth.EngineAPIMethod
   520  	}{
   521  		{
   522  			name:           "NoAttrs",
   523  			canyonTime:     10,
   524  			ecotoneTime:    20,
   525  			attrs:          nil,
   526  			expectedMethod: eth.FCUV3,
   527  		},
   528  		{
   529  			name:           "BeforeCanyon",
   530  			canyonTime:     10,
   531  			ecotoneTime:    20,
   532  			attrs:          &eth.PayloadAttributes{Timestamp: 5},
   533  			expectedMethod: eth.FCUV1,
   534  		},
   535  		{
   536  			name:           "Canyon",
   537  			canyonTime:     10,
   538  			ecotoneTime:    20,
   539  			attrs:          &eth.PayloadAttributes{Timestamp: 15},
   540  			expectedMethod: eth.FCUV2,
   541  		},
   542  		{
   543  			name:           "Ecotone",
   544  			canyonTime:     10,
   545  			ecotoneTime:    20,
   546  			attrs:          &eth.PayloadAttributes{Timestamp: 25},
   547  			expectedMethod: eth.FCUV3,
   548  		},
   549  	}
   550  
   551  	for _, test := range tests {
   552  		test := test
   553  		t.Run(fmt.Sprintf("TestForkchoiceUpdatedVersion_%s", test.name), func(t *testing.T) {
   554  			config.CanyonTime = &test.canyonTime
   555  			config.EcotoneTime = &test.ecotoneTime
   556  			assert.Equal(t, config.ForkchoiceUpdatedVersion(test.attrs), test.expectedMethod)
   557  		})
   558  	}
   559  }
   560  
   561  func TestNewPayloadVersion(t *testing.T) {
   562  	config := randConfig()
   563  	canyonTime := uint64(0)
   564  	config.CanyonTime = &canyonTime
   565  	tests := []struct {
   566  		name           string
   567  		ecotoneTime    uint64
   568  		payloadTime    uint64
   569  		expectedMethod eth.EngineAPIMethod
   570  	}{
   571  		{
   572  			name:           "BeforeEcotone",
   573  			ecotoneTime:    10,
   574  			payloadTime:    5,
   575  			expectedMethod: eth.NewPayloadV2,
   576  		},
   577  		{
   578  			name:           "Ecotone",
   579  			ecotoneTime:    10,
   580  			payloadTime:    15,
   581  			expectedMethod: eth.NewPayloadV3,
   582  		},
   583  	}
   584  
   585  	for _, test := range tests {
   586  		test := test
   587  		t.Run(fmt.Sprintf("TestNewPayloadVersion_%s", test.name), func(t *testing.T) {
   588  			config.EcotoneTime = &test.ecotoneTime
   589  			assert.Equal(t, config.NewPayloadVersion(test.payloadTime), test.expectedMethod)
   590  		})
   591  	}
   592  }
   593  
   594  func TestGetPayloadVersion(t *testing.T) {
   595  	config := randConfig()
   596  	canyonTime := uint64(0)
   597  	config.CanyonTime = &canyonTime
   598  	tests := []struct {
   599  		name           string
   600  		ecotoneTime    uint64
   601  		payloadTime    uint64
   602  		expectedMethod eth.EngineAPIMethod
   603  	}{
   604  		{
   605  			name:           "BeforeEcotone",
   606  			ecotoneTime:    10,
   607  			payloadTime:    5,
   608  			expectedMethod: eth.GetPayloadV2,
   609  		},
   610  		{
   611  			name:           "Ecotone",
   612  			ecotoneTime:    10,
   613  			payloadTime:    15,
   614  			expectedMethod: eth.GetPayloadV3,
   615  		},
   616  	}
   617  
   618  	for _, test := range tests {
   619  		test := test
   620  		t.Run(fmt.Sprintf("TestGetPayloadVersion_%s", test.name), func(t *testing.T) {
   621  			config.EcotoneTime = &test.ecotoneTime
   622  			assert.Equal(t, config.GetPayloadVersion(test.payloadTime), test.expectedMethod)
   623  		})
   624  	}
   625  }