diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index eacea1f5b6..ce82b71d48 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -232,7 +232,7 @@ func applyLondonChecks(env *stEnv, chainConfig *params.ChainConfig) error { } configExtra := params.GetExtra(chainConfig) var err error - env.BaseFee, err = customheader.BaseFee(configExtra, feeConfig, parent, env.Timestamp) + env.BaseFee, err = customheader.BaseFee(configExtra, feeConfig, parent, env.Timestamp*1000) if err != nil { return NewError(ErrorConfig, fmt.Errorf("failed calculating base fee: %v", err)) } diff --git a/consensus/dummy/consensus.go b/consensus/dummy/consensus.go index 47d868382c..5c3186a498 100644 --- a/consensus/dummy/consensus.go +++ b/consensus/dummy/consensus.go @@ -118,7 +118,8 @@ func verifyHeaderGasFields(config *extras.ChainConfig, header *types.Header, par } // Verify header.BaseFee matches the expected value. - expectedBaseFee, err := customheader.BaseFee(config, feeConfig, parent, header.Time) + timeMS := customtypes.HeaderTimeMilliseconds(header) + expectedBaseFee, err := customheader.BaseFee(config, feeConfig, parent, timeMS) if err != nil { return fmt.Errorf("failed to calculate base fee: %w", err) } diff --git a/core/chain_makers.go b/core/chain_makers.go index 4c1540540b..d96b3f1161 100644 --- a/core/chain_makers.go +++ b/core/chain_makers.go @@ -378,16 +378,18 @@ func GenerateChainWithGenesis(genesis *Genesis, engine consensus.Engine, n int, func (cm *chainMaker) makeHeader(parent *types.Block, gap uint64, state *state.StateDB, engine consensus.Engine) *types.Header { time := parent.Time() + gap // block time is fixed at [gap] seconds + timeMS := customtypes.HeaderTimeMilliseconds(parent.Header()) + gap*1000 + feeConfig, _, err := cm.GetFeeConfigAt(parent.Header()) if err != nil { panic(err) } config := params.GetExtra(cm.config) - gasLimit, err := customheader.GasLimit(config, feeConfig, parent.Header(), time) + gasLimit, err := customheader.GasLimit(config, feeConfig, parent.Header(), timeMS) if err != nil { panic(err) } - baseFee, err := customheader.BaseFee(config, feeConfig, parent.Header(), time) + baseFee, err := customheader.BaseFee(config, feeConfig, parent.Header(), timeMS) if err != nil { panic(err) } @@ -420,8 +422,7 @@ func (cm *chainMaker) makeHeader(parent *types.Block, gap uint64, state *state.S if config.IsGranite(header.Time) { headerExtra := customtypes.GetHeaderExtra(header) - timeMilliseconds := header.Time * 1000 // convert to milliseconds - headerExtra.TimeMilliseconds = &timeMilliseconds + headerExtra.TimeMilliseconds = &timeMS } return header } diff --git a/core/state_processor_test.go b/core/state_processor_test.go index fd5d66098b..8be0809067 100644 --- a/core/state_processor_test.go +++ b/core/state_processor_test.go @@ -48,6 +48,7 @@ import ( "github.com/ava-labs/subnet-evm/plugin/evm/customheader" "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/plugin/evm/upgrade/legacy" + "github.com/ava-labs/subnet-evm/utils" "github.com/holiman/uint256" "golang.org/x/crypto/sha3" ) @@ -357,14 +358,16 @@ func TestStateProcessorErrors(t *testing.T) { // - valid pow (fake), ancestry, difficulty, gaslimit etc func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Transactions, config *params.ChainConfig) *types.Block { fakeChainReader := newChainMaker(nil, config, engine) - time := parent.Time() + 10 feeConfig, _, err := fakeChainReader.GetFeeConfigAt(parent.Header()) if err != nil { panic(err) } configExtra := params.GetExtra(config) - gasLimit, _ := customheader.GasLimit(configExtra, feeConfig, parent.Header(), time) - baseFee, _ := customheader.BaseFee(configExtra, feeConfig, parent.Header(), time) + gap := uint64(10) // 10 seconds + time := parent.Time() + gap + timeMS := customtypes.HeaderTimeMilliseconds(parent.Header()) + gap*1000 + gasLimit, _ := customheader.GasLimit(configExtra, feeConfig, parent.Header(), timeMS) + baseFee, _ := customheader.BaseFee(configExtra, feeConfig, parent.Header(), timeMS) header := &types.Header{ ParentHash: parent.Hash(), Coinbase: parent.Coinbase(), @@ -380,6 +383,10 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr UncleHash: types.EmptyUncleHash, BaseFee: baseFee, } + if configExtra.IsGranite(header.Time) { + headerExtra := customtypes.GetHeaderExtra(header) + headerExtra.TimeMilliseconds = utils.NewUint64(timeMS) + } if params.GetExtra(config).IsSubnetEVM(header.Time) { headerExtra := customtypes.GetHeaderExtra(header) @@ -418,12 +425,6 @@ func GenerateBadBlock(parent *types.Block, engine consensus.Engine, txs types.Tr header.ParentBeaconRoot = new(common.Hash) } - if configExtra.IsGranite(header.Time) { - headerExtra := customtypes.GetHeaderExtra(header) - headerExtra.TimeMilliseconds = new(uint64) - *headerExtra.TimeMilliseconds = header.Time * 1000 - } - // Assemble and return the final block for sealing return types.NewBlock(header, txs, nil, receipts, trie.NewStackTrie(nil)) } diff --git a/core/txpool/blobpool/blobpool.go b/core/txpool/blobpool/blobpool.go index ce549ed0cd..668a26b076 100644 --- a/core/txpool/blobpool/blobpool.go +++ b/core/txpool/blobpool/blobpool.go @@ -421,7 +421,7 @@ func (p *BlobPool) Init(gasTip uint64, head *types.Header, reserve txpool.Addres params.GetExtra(p.chain.Config()), feeConfig, p.head, - uint64(time.Now().Unix()), + uint64(time.Now().UnixMilli()), ) if err != nil { p.Close() @@ -857,7 +857,7 @@ func (p *BlobPool) Reset(oldHead, newHead *types.Header) { params.GetExtra(p.chain.Config()), feeConfig, p.head, - uint64(time.Now().Unix()), + uint64(time.Now().UnixMilli()), ) if err != nil { log.Error("Failed to estimate next base fee to reset blobpool fees", "err", err) diff --git a/core/txpool/blobpool/blobpool_test.go b/core/txpool/blobpool/blobpool_test.go index b519622f30..479044be50 100644 --- a/core/txpool/blobpool/blobpool_test.go +++ b/core/txpool/blobpool/blobpool_test.go @@ -56,6 +56,7 @@ import ( "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/params" "github.com/ava-labs/subnet-evm/plugin/evm/customheader" + "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/ava-labs/subnet-evm/plugin/evm/upgrade/legacy" "github.com/ava-labs/subnet-evm/plugin/evm/upgrade/subnetevm" "github.com/holiman/billy" @@ -76,6 +77,7 @@ var testChainConfig *params.ChainConfig func init() { params.RegisterExtras() + customtypes.Register() testChainConfig = new(params.ChainConfig) *testChainConfig = params.Copy(params.TestChainConfig) @@ -123,8 +125,12 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { Extra: make([]byte, subnetevm.WindowSize), } config := params.GetExtra(bc.config) + timeMS := blockTime * 1000 + if config.IsGranite(blockTime) { + customtypes.GetHeaderExtra(parent).TimeMilliseconds = &timeMS + } baseFee, err := customheader.BaseFee( - config, config.FeeConfig, parent, blockTime, + config, config.FeeConfig, parent, timeMS, ) if err != nil { panic(err) @@ -154,7 +160,7 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { } excessBlobGas := lo.Uint64() - return &types.Header{ + head := &types.Header{ Number: blockNumber, Time: blockTime, GasLimit: gasLimit, @@ -162,6 +168,11 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { ExcessBlobGas: &excessBlobGas, Extra: make([]byte, subnetevm.WindowSize), } + if params.GetExtra(bc.config).IsGranite(blockTime) { + timeMS := blockTime * 1000 + customtypes.GetHeaderExtra(head).TimeMilliseconds = &timeMS + } + return head } func (bc *testBlockChain) CurrentFinalBlock() *types.Header { diff --git a/core/txpool/legacypool/legacypool.go b/core/txpool/legacypool/legacypool.go index b5db21638e..66684224a6 100644 --- a/core/txpool/legacypool/legacypool.go +++ b/core/txpool/legacypool/legacypool.go @@ -1852,7 +1852,7 @@ func (pool *LegacyPool) updateBaseFeeAt(head *types.Header) error { return err } chainConfig := params.GetExtra(pool.chainconfig) - baseFeeEstimate, err := customheader.EstimateNextBaseFee(chainConfig, feeConfig, head, uint64(time.Now().Unix())) + baseFeeEstimate, err := customheader.EstimateNextBaseFee(chainConfig, feeConfig, head, uint64(time.Now().UnixMilli())) if err != nil { return err } diff --git a/core/txpool/legacypool/legacypool_test.go b/core/txpool/legacypool/legacypool_test.go index 7957f1e330..c4152b08bf 100644 --- a/core/txpool/legacypool/legacypool_test.go +++ b/core/txpool/legacypool/legacypool_test.go @@ -51,11 +51,13 @@ import ( "github.com/ava-labs/subnet-evm/core" "github.com/ava-labs/subnet-evm/core/txpool" "github.com/ava-labs/subnet-evm/params" + "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" "github.com/holiman/uint256" ) func TestMain(m *testing.M) { params.RegisterExtras() + customtypes.Register() os.Exit(m.Run()) } @@ -110,10 +112,14 @@ func (bc *testBlockChain) CurrentBlock() *types.Header { bc.lock.Lock() defer bc.lock.Unlock() - return &types.Header{ + header := &types.Header{ Number: new(big.Int), GasLimit: bc.gasLimit.Load(), } + if params.GetExtra(bc.config).IsGranite(0) { + customtypes.GetHeaderExtra(header).TimeMilliseconds = new(uint64) + } + return header } func (bc *testBlockChain) GetBlock(hash common.Hash, number uint64) *types.Block { diff --git a/eth/gasprice/gasprice.go b/eth/gasprice/gasprice.go index e25f2903fc..f8bf3eb883 100644 --- a/eth/gasprice/gasprice.go +++ b/eth/gasprice/gasprice.go @@ -241,7 +241,7 @@ func (oracle *Oracle) estimateNextBaseFee(ctx context.Context) (*big.Int, error) // based on the current time and add it to the tip to estimate the // total gas price estimate. chainConfig := params.GetExtra(oracle.backend.ChainConfig()) - return customheader.EstimateNextBaseFee(chainConfig, feeConfig, header, oracle.clock.Unix()) + return customheader.EstimateNextBaseFee(chainConfig, feeConfig, header, uint64(oracle.clock.Time().UnixMilli())) } // SuggestPrice returns an estimated price for legacy transactions. diff --git a/miner/worker.go b/miner/worker.go index 7d2b8a7a5e..c669efaaaf 100644 --- a/miner/worker.go +++ b/miner/worker.go @@ -163,13 +163,13 @@ func (w *worker) commitNewWork(predicateContext *precompileconfig.PredicateConte if err != nil { return nil, err } - gasLimit, err := customheader.GasLimit(chainExtra, feeConfig, parent, header.Time) + gasLimit, err := customheader.GasLimit(chainExtra, feeConfig, parent, timestampMS) if err != nil { return nil, fmt.Errorf("calculating new gas limit: %w", err) } header.GasLimit = gasLimit - baseFee, err := customheader.BaseFee(chainExtra, feeConfig, parent, header.Time) + baseFee, err := customheader.BaseFee(chainExtra, feeConfig, parent, timestampMS) if err != nil { return nil, fmt.Errorf("failed to calculate new base fee: %w", err) } @@ -287,7 +287,8 @@ func (w *worker) createCurrentEnvironment(predicateContext *precompileconfig.Pre return nil, err } chainConfig := params.GetExtra(w.chainConfig) - capacity, err := customheader.GasCapacity(chainConfig, feeConfig, parent, header.Time) + timeMS := customtypes.HeaderTimeMilliseconds(header) + capacity, err := customheader.GasCapacity(chainConfig, feeConfig, parent, timeMS) if err != nil { return nil, fmt.Errorf("calculating gas capacity: %w", err) } diff --git a/plugin/evm/customheader/base_fee.go b/plugin/evm/customheader/base_fee.go index e23d7e5960..704c8763f3 100644 --- a/plugin/evm/customheader/base_fee.go +++ b/plugin/evm/customheader/base_fee.go @@ -4,17 +4,15 @@ package customheader import ( - "errors" "math/big" "github.com/ava-labs/libevm/core/types" "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/params/extras" + "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" ) -var errEstimateBaseFeeWithoutActivation = errors.New("cannot estimate base fee for chain without activation scheduled") - // BaseFee takes the previous header and the timestamp of its child block and // calculates the expected base fee for the child block. // @@ -23,8 +21,9 @@ func BaseFee( config *extras.ChainConfig, feeConfig commontype.FeeConfig, parent *types.Header, - timestamp uint64, + timeMS uint64, ) (*big.Int, error) { + timestamp := timeMS / 1000 switch { case config.IsSubnetEVM(timestamp): return baseFeeFromWindow(config, feeConfig, parent, timestamp) @@ -46,12 +45,9 @@ func EstimateNextBaseFee( config *extras.ChainConfig, feeConfig commontype.FeeConfig, parent *types.Header, - timestamp uint64, + timeMS uint64, ) (*big.Int, error) { - if config.SubnetEVMTimestamp == nil { - return nil, errEstimateBaseFeeWithoutActivation - } - - timestamp = max(timestamp, parent.Time, *config.SubnetEVMTimestamp) - return BaseFee(config, feeConfig, parent, timestamp) + parentMS := customtypes.HeaderTimeMilliseconds(parent) + timeMS = max(timeMS, parentMS) + return BaseFee(config, feeConfig, parent, timeMS) } diff --git a/plugin/evm/customheader/base_fee_test.go b/plugin/evm/customheader/base_fee_test.go index 328d6c6ee1..0d39b066fd 100644 --- a/plugin/evm/customheader/base_fee_test.go +++ b/plugin/evm/customheader/base_fee_test.go @@ -32,12 +32,12 @@ func TestBaseFee(t *testing.T) { func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { tests := []struct { - name string - upgrades extras.NetworkUpgrades - parent *types.Header - timestamp uint64 - want *big.Int - wantErr error + name string + upgrades extras.NetworkUpgrades + parent *types.Header + timeMS uint64 + want *big.Int + wantErr error }{ { name: "pre_subnet_evm", @@ -53,8 +53,8 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { parent: &types.Header{ Number: big.NewInt(1), }, - timestamp: 1, - want: big.NewInt(feeConfig.MinBaseFee.Int64()), + timeMS: 1000, + want: big.NewInt(feeConfig.MinBaseFee.Int64()), }, { name: "subnet_evm_genesis_block", @@ -80,8 +80,7 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { Time: 1, Extra: (&subnetevm.Window{}).Bytes(), }, - timestamp: 0, - wantErr: errInvalidTimestamp, + wantErr: errInvalidTimestamp, }, { name: "subnet_evm_no_change", @@ -93,8 +92,8 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { Extra: (&subnetevm.Window{}).Bytes(), BaseFee: big.NewInt(feeConfig.MinBaseFee.Int64() + 1), }, - timestamp: 1, - want: big.NewInt(feeConfig.MinBaseFee.Int64() + 1), + timeMS: 1000, + want: big.NewInt(feeConfig.MinBaseFee.Int64() + 1), }, { name: "subnet_evm_small_decrease", @@ -104,7 +103,7 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { Extra: (&subnetevm.Window{}).Bytes(), BaseFee: big.NewInt(maxBaseFee), }, - timestamp: 1, + timeMS: 1000, want: func() *big.Int { var ( gasTarget = feeConfig.TargetGas.Int64() @@ -127,7 +126,7 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { Extra: (&subnetevm.Window{}).Bytes(), BaseFee: big.NewInt(maxBaseFee), }, - timestamp: 2 * subnetevm.WindowLen, + timeMS: 2 * 1000 * subnetevm.WindowLen, want: func() *big.Int { var ( gasTarget = feeConfig.TargetGas.Int64() @@ -152,7 +151,7 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { Extra: (&subnetevm.Window{}).Bytes(), BaseFee: big.NewInt(feeConfig.MinBaseFee.Int64()), }, - timestamp: 1, + timeMS: 1000, want: func() *big.Int { var ( gasTarget = feeConfig.TargetGas.Int64() @@ -176,8 +175,32 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { Extra: (&subnetevm.Window{}).Bytes(), BaseFee: big.NewInt(1), }, - timestamp: 2 * subnetevm.WindowLen, - want: big.NewInt(feeConfig.MinBaseFee.Int64()), + timeMS: 2 * 1000 * subnetevm.WindowLen, + want: big.NewInt(feeConfig.MinBaseFee.Int64()), + }, + { + name: "granite_rounds_seconds", + upgrades: extras.TestGraniteChainConfig.NetworkUpgrades, + parent: &types.Header{ + Number: big.NewInt(1), + Extra: (&subnetevm.Window{}).Bytes(), + BaseFee: big.NewInt(maxBaseFee), + }, + timeMS: 2*1000*subnetevm.WindowLen + 999, + want: func() *big.Int { + var ( + gasTarget = feeConfig.TargetGas.Int64() + gasUsed = int64(0) + amountUnderTarget = gasTarget - gasUsed + parentBaseFee = int64(maxBaseFee) + smoothingFactor = feeConfig.BaseFeeChangeDenominator.Int64() + baseFeeFractionUnderTarget = amountUnderTarget * parentBaseFee / gasTarget + windowsElapsed = int64(2) + delta = windowsElapsed * baseFeeFractionUnderTarget / smoothingFactor + baseFee = parentBaseFee - delta + ) + return big.NewInt(baseFee) + }(), }, } for _, test := range tests { @@ -187,7 +210,7 @@ func BaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { config := &extras.ChainConfig{ NetworkUpgrades: test.upgrades, } - got, err := BaseFee(config, feeConfig, test.parent, test.timestamp) + got, err := BaseFee(config, feeConfig, test.parent, test.timeMS) require.ErrorIs(err, test.wantErr) require.Equal(test.want, got) @@ -208,24 +231,22 @@ func TestEstimateNextBaseFee(t *testing.T) { func EstimateNextBaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { testBaseFee := uint64(225 * utils.GWei) - nilUpgrade := extras.NetworkUpgrades{} tests := []struct { - name string - upgrades extras.NetworkUpgrades - parent *types.Header - timestamp uint64 - want *big.Int - wantErr error + name string + upgrades extras.NetworkUpgrades + parent *types.Header + timeMS uint64 + want *big.Int }{ { - name: "activated", + name: "subnetevm_activated", upgrades: extras.TestSubnetEVMChainConfig.NetworkUpgrades, parent: &types.Header{ Number: big.NewInt(1), Extra: (&subnetevm.Window{}).Bytes(), BaseFee: new(big.Int).SetUint64(testBaseFee), }, - timestamp: 1, + timeMS: 1000, want: func() *big.Int { var ( gasTarget = feeConfig.TargetGas.Uint64() @@ -241,9 +262,27 @@ func EstimateNextBaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { }(), }, { - name: "not_scheduled", - upgrades: nilUpgrade, - wantErr: errEstimateBaseFeeWithoutActivation, + name: "granite_activated_rounds_seconds", + upgrades: extras.TestGraniteChainConfig.NetworkUpgrades, + parent: &types.Header{ + Number: big.NewInt(1), + Extra: (&subnetevm.Window{}).Bytes(), + BaseFee: new(big.Int).SetUint64(testBaseFee), + }, + timeMS: 1999, + want: func() *big.Int { + var ( + gasTarget = feeConfig.TargetGas.Uint64() + gasUsed = uint64(0) + amountUnderTarget = gasTarget - gasUsed + parentBaseFee = testBaseFee + smoothingFactor = feeConfig.BaseFeeChangeDenominator.Uint64() + baseFeeFractionUnderTarget = amountUnderTarget * parentBaseFee / gasTarget + delta = baseFeeFractionUnderTarget / smoothingFactor + baseFee = parentBaseFee - delta + ) + return new(big.Int).SetUint64(baseFee) + }(), }, } for _, test := range tests { @@ -253,8 +292,8 @@ func EstimateNextBaseFeeTest(t *testing.T, feeConfig commontype.FeeConfig) { config := &extras.ChainConfig{ NetworkUpgrades: test.upgrades, } - got, err := EstimateNextBaseFee(config, feeConfig, test.parent, test.timestamp) - require.ErrorIs(err, test.wantErr) + got, err := EstimateNextBaseFee(config, feeConfig, test.parent, test.timeMS) + require.NoError(err) require.Equal(test.want, got) }) } diff --git a/plugin/evm/customheader/gas_limit.go b/plugin/evm/customheader/gas_limit.go index d191403310..77b37f1442 100644 --- a/plugin/evm/customheader/gas_limit.go +++ b/plugin/evm/customheader/gas_limit.go @@ -12,6 +12,7 @@ import ( "github.com/ava-labs/subnet-evm/commontype" "github.com/ava-labs/subnet-evm/params/extras" + "github.com/ava-labs/subnet-evm/plugin/evm/customtypes" ethparams "github.com/ava-labs/libevm/params" ) @@ -29,8 +30,9 @@ func GasLimit( config *extras.ChainConfig, feeConfig commontype.FeeConfig, parent *types.Header, - timestamp uint64, + timeMS uint64, ) (uint64, error) { + timestamp := timeMS / 1000 switch { case config.IsSubnetEVM(timestamp): return feeConfig.GasLimit.Uint64(), nil @@ -52,7 +54,8 @@ func VerifyGasUsed( header *types.Header, ) error { gasUsed := header.GasUsed - capacity, err := GasCapacity(config, feeConfig, parent, header.Time) + timeMS := customtypes.HeaderTimeMilliseconds(header) + capacity, err := GasCapacity(config, feeConfig, parent, timeMS) if err != nil { return fmt.Errorf("calculating gas capacity: %w", err) } @@ -114,7 +117,7 @@ func GasCapacity( config *extras.ChainConfig, feeConfig commontype.FeeConfig, parent *types.Header, - timestamp uint64, + timeMS uint64, ) (uint64, error) { - return GasLimit(config, feeConfig, parent, timestamp) + return GasLimit(config, feeConfig, parent, timeMS) } diff --git a/plugin/evm/customheader/gas_limit_test.go b/plugin/evm/customheader/gas_limit_test.go index 2b4f434117..3276c289c3 100644 --- a/plugin/evm/customheader/gas_limit_test.go +++ b/plugin/evm/customheader/gas_limit_test.go @@ -26,12 +26,11 @@ func TestGasLimit(t *testing.T) { func GasLimitTest(t *testing.T, feeConfig commontype.FeeConfig) { tests := []struct { - name string - upgrades extras.NetworkUpgrades - parent *types.Header - timestamp uint64 - want uint64 - wantErr error + name string + upgrades extras.NetworkUpgrades + parent *types.Header + want uint64 + wantErr error }{ { name: "subnet_evm", @@ -54,7 +53,7 @@ func GasLimitTest(t *testing.T, feeConfig commontype.FeeConfig) { config := &extras.ChainConfig{ NetworkUpgrades: test.upgrades, } - got, err := GasLimit(config, feeConfig, test.parent, test.timestamp) + got, err := GasLimit(config, feeConfig, test.parent, 0) require.ErrorIs(err, test.wantErr) require.Equal(test.want, got) }) @@ -159,12 +158,11 @@ func TestGasCapacity(t *testing.T) { func GasCapacityTest(t *testing.T, feeConfig commontype.FeeConfig) { tests := []struct { - name string - upgrades extras.NetworkUpgrades - parent *types.Header - timestamp uint64 - want uint64 - wantErr error + name string + upgrades extras.NetworkUpgrades + parent *types.Header + want uint64 + wantErr error }{ { name: "subnet_evm", @@ -179,7 +177,7 @@ func GasCapacityTest(t *testing.T, feeConfig commontype.FeeConfig) { config := &extras.ChainConfig{ NetworkUpgrades: test.upgrades, } - got, err := GasCapacity(config, feeConfig, test.parent, test.timestamp) + got, err := GasCapacity(config, feeConfig, test.parent, 0) require.ErrorIs(err, test.wantErr) require.Equal(test.want, got) }) diff --git a/plugin/evm/customtypes/header_ext.go b/plugin/evm/customtypes/header_ext.go index b67816036b..b32a1e4a68 100644 --- a/plugin/evm/customtypes/header_ext.go +++ b/plugin/evm/customtypes/header_ext.go @@ -42,6 +42,17 @@ type HeaderExtra struct { MinDelayExcess *acp226.DelayExcess } +// HeaderTimeMilliseconds returns the header timestamp in milliseconds. +// If the header has the Granite field TimeMilliseconds set in extras, it is used. +// Otherwise, it falls back to seconds-based Time multiplied by 1000. +func HeaderTimeMilliseconds(h *ethtypes.Header) uint64 { + extra := GetHeaderExtra(h) + if extra != nil && extra.TimeMilliseconds != nil { + return *extra.TimeMilliseconds + } + return h.Time * 1000 +} + // EncodeRLP RLP encodes the given [ethtypes.Header] and [HeaderExtra] together // to the `writer`. It does merge both structs into a single [HeaderSerializable]. func (h *HeaderExtra) EncodeRLP(eth *ethtypes.Header, writer io.Writer) error {