Files
evmgpu/plugin/evm/header/base_fee_test.go

261 lines
7.6 KiB
Go

// Copyright (C) 2019-2025, Lux Industries, Inc. All rights reserved.
// See the file LICENSE for licensing terms.
package header
import (
"math/big"
"testing"
"github.com/luxfi/evmgpu/commontype"
"github.com/luxfi/evmgpu/params/extras"
"github.com/luxfi/evmgpu/plugin/evm/upgrade/feewindow"
"github.com/luxfi/evmgpu/utils"
"github.com/luxfi/geth/common"
"github.com/luxfi/geth/core/types"
"github.com/stretchr/testify/require"
)
const (
maxBaseFee = 225 * utils.GWei
)
func TestBaseFee(t *testing.T) {
t.Run("normal", func(t *testing.T) {
BaseFeeTest(t, testFeeConfig)
})
t.Run("double", func(t *testing.T) {
BaseFeeTest(t, testFeeConfigDouble)
})
}
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: "pre_chain_evm",
upgrades: extras.TestPreEVMChainConfig.NetworkUpgrades,
want: nil,
wantErr: nil,
},
{
name: "chain_evm_first_block",
upgrades: extras.NetworkUpgrades{
EVMTimestamp: utils.NewUint64(1),
},
parent: &types.Header{
Number: big.NewInt(1),
},
timestamp: 1,
want: big.NewInt(feeConfig.MinBaseFee.Int64()),
},
{
name: "chain_evm_genesis_block",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(0),
},
want: big.NewInt(feeConfig.MinBaseFee.Int64()),
},
{
name: "chain_evm_invalid_fee_window",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
},
wantErr: feewindow.ErrWindowInsufficientLength,
},
{
name: "chain_evm_invalid_timestamp",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Time: 1,
Extra: (&feewindow.Window{}).Bytes(),
},
timestamp: 0,
wantErr: errInvalidTimestamp,
},
{
name: "chain_evm_no_change",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: feeConfig.TargetGas.Uint64(),
Time: 1,
Extra: (&feewindow.Window{}).Bytes(),
BaseFee: big.NewInt(feeConfig.MinBaseFee.Int64() + 1),
},
timestamp: 1,
want: big.NewInt(feeConfig.MinBaseFee.Int64() + 1),
},
{
name: "chain_evm_small_decrease",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: (&feewindow.Window{}).Bytes(),
BaseFee: big.NewInt(maxBaseFee),
},
timestamp: 1,
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
delta = baseFeeFractionUnderTarget / smoothingFactor
baseFee = parentBaseFee - delta
)
return big.NewInt(baseFee)
}(),
},
{
name: "chain_evm_large_decrease",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: (&feewindow.Window{}).Bytes(),
BaseFee: big.NewInt(maxBaseFee),
},
timestamp: 2 * feewindow.WindowLen,
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)
}(),
},
{
name: "chain_evm_increase",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: 2 * feeConfig.TargetGas.Uint64(),
Extra: (&feewindow.Window{}).Bytes(),
BaseFee: big.NewInt(feeConfig.MinBaseFee.Int64()),
},
timestamp: 1,
want: func() *big.Int {
var (
gasTarget = feeConfig.TargetGas.Int64()
gasUsed = 2 * gasTarget
amountOverTarget = gasUsed - gasTarget
parentBaseFee = feeConfig.MinBaseFee.Int64()
smoothingFactor = feeConfig.BaseFeeChangeDenominator.Int64()
baseFeeFractionOverTarget = amountOverTarget * parentBaseFee / gasTarget
delta = baseFeeFractionOverTarget / smoothingFactor
baseFee = parentBaseFee + delta
)
return big.NewInt(baseFee)
}(),
},
{
name: "chain_evm_big_1_not_modified",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
GasUsed: 1,
Extra: (&feewindow.Window{}).Bytes(),
BaseFee: big.NewInt(1),
},
timestamp: 2 * feewindow.WindowLen,
want: big.NewInt(feeConfig.MinBaseFee.Int64()),
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)
config := &extras.ChainConfig{
NetworkUpgrades: test.upgrades,
}
got, err := BaseFee(config, feeConfig, test.parent, test.timestamp)
require.ErrorIs(err, test.wantErr)
require.Equal(test.want, got)
// Verify that [common.Big1] is not modified by [BaseFee].
require.Equal(big.NewInt(1), common.Big1)
})
}
}
func TestEstimateNextBaseFee(t *testing.T) {
t.Run("normal", func(t *testing.T) {
EstimateNextBaseFeeTest(t, testFeeConfig)
})
t.Run("double", func(t *testing.T) {
EstimateNextBaseFeeTest(t, testFeeConfigDouble)
})
}
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: "activated",
upgrades: extras.TestEVMChainConfig.NetworkUpgrades,
parent: &types.Header{
Number: big.NewInt(1),
Extra: (&feewindow.Window{}).Bytes(),
BaseFee: new(big.Int).SetUint64(testBaseFee),
},
timestamp: 1,
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)
}(),
},
{
name: "not_scheduled",
upgrades: nilUpgrade,
wantErr: errEstimateBaseFeeWithoutActivation,
},
}
for _, test := range tests {
t.Run(test.name, func(t *testing.T) {
require := require.New(t)
config := &extras.ChainConfig{
NetworkUpgrades: test.upgrades,
}
got, err := EstimateNextBaseFee(config, feeConfig, test.parent, test.timestamp)
require.ErrorIs(err, test.wantErr)
require.Equal(test.want, got)
})
}
}