diff --git a/consensus/misc/eip1559/eip1559.go b/consensus/misc/eip1559/eip1559.go index d21e41654d..cbbb1e048d 100644 --- a/consensus/misc/eip1559/eip1559.go +++ b/consensus/misc/eip1559/eip1559.go @@ -57,7 +57,15 @@ func VerifyEIP1559Header(config *params.ChainConfig, parent, header *types.Heade // CalcBaseFee calculates the basefee of the header. // The time belongs to the new block to check if Canyon is activted or not -func CalcBaseFee(config *params.ChainConfig, parent *types.Header, time uint64) *big.Int { +// **Notice** that the return value is catched by the deferred function which can change the return value +func CalcBaseFee(config *params.ChainConfig, parent *types.Header, time uint64) (response *big.Int) { + defer func() { + // If the base fee response is below the floor, intercept the return and return the floor instead. + if config.Celo != nil { + response = math.BigMax(response, new(big.Int).SetUint64(config.Celo.EIP1559BaseFeeFloor)) + } + }() + // If this is the cel2 transition block and the parent block has a base fee // then use that. if config.Cel2Time != nil && *config.Cel2Time == time && parent.BaseFee != nil { diff --git a/consensus/misc/eip1559/eip1559_test.go b/consensus/misc/eip1559/eip1559_test.go index 39766b57cc..fb6a7c5332 100644 --- a/consensus/misc/eip1559/eip1559_test.go +++ b/consensus/misc/eip1559/eip1559_test.go @@ -69,6 +69,15 @@ func opConfig() *params.ChainConfig { return config } +func celoConfig() *params.ChainConfig { + config := copyConfig(params.TestChainConfig) + ct := uint64(10) + config.Cel2Time = &ct + config.Celo = ¶ms.CeloConfig{EIP1559BaseFeeFloor: params.InitialBaseFee} + + return config +} + // TestBlockGasLimits tests the gasLimit checks for blocks both across // the EIP-1559 boundary and post-1559 blocks func TestBlockGasLimits(t *testing.T) { @@ -176,3 +185,47 @@ func TestCalcBaseFeeOptimism(t *testing.T) { } } } + +// TestCalcBaseFeeCeloFloor assumes all blocks are 1559-blocks +func TestCalcBaseFeeCeloFloor(t *testing.T) { + config := celoConfig() + tests := []struct { + parentBaseFee int64 + parentGasLimit uint64 + parentGasUsed uint64 + expectedBaseFee int64 + }{ + {params.InitialBaseFee, 20000000, 10000000, params.InitialBaseFee}, // usage == target + {params.InitialBaseFee, 20000000, 7000000, params.InitialBaseFee}, // usage below target + {params.InitialBaseFee, 20000000, 11000000, 1012500000}, // usage above target + } + for i, test := range tests { + parent := &types.Header{ + Number: common.Big32, + GasLimit: test.parentGasLimit, + GasUsed: test.parentGasUsed, + BaseFee: big.NewInt(test.parentBaseFee), + Time: *config.Cel2Time, + } + if have, want := CalcBaseFee(config, parent, parent.Time+2), big.NewInt(test.expectedBaseFee); have.Cmp(want) != 0 { + t.Errorf("test %d: have %d want %d, ", i, have, want) + } + } +} + +// TestCalcBaseFeeCeloBlockActivation tests the base fee calculation for the celo block activation, mantaining the same base fee as the parent block +func TestCalcBaseFeeCeloBlockActivation(t *testing.T) { + config := celoConfig() + // Before activation + // usage above target + parent := &types.Header{ + Number: common.Big32, + GasLimit: 20000000, + GasUsed: 15000000, + BaseFee: big.NewInt(params.InitialBaseFee * 3), + Time: *config.Cel2Time - 2, + } + if have, want := CalcBaseFee(config, parent, parent.Time+2), big.NewInt(params.InitialBaseFee*3); have.Cmp(want) != 0 { + t.Errorf("have %d want %d, ", have, want) + } +} diff --git a/params/config.go b/params/config.go index 69b1c92f44..3cb9eeec72 100644 --- a/params/config.go +++ b/params/config.go @@ -458,6 +458,8 @@ type ChainConfig struct { // Optimism config, nil if not active Optimism *OptimismConfig `json:"optimism,omitempty"` + // Celo config, nil if not active + Celo *CeloConfig `json:"celo,omitempty"` } // EthashConfig is the consensus engine configs for proof-of-work based sealing. @@ -488,7 +490,21 @@ type OptimismConfig struct { // String implements the stringer interface, returning the optimism fee config details. func (o *OptimismConfig) String() string { - return "optimism" + denominatorCanyonStr := "nil" + if o.EIP1559DenominatorCanyon != nil { + denominatorCanyonStr = fmt.Sprintf("%d", *o.EIP1559DenominatorCanyon) + } + return fmt.Sprintf("optimism(eip1559Elasticity: %d, eip1559Denominator: %d, eip1559DenominatorCanyon: %s)", + o.EIP1559Elasticity, o.EIP1559Denominator, denominatorCanyonStr) +} + +type CeloConfig struct { + EIP1559BaseFeeFloor uint64 `json:"eip1559BaseFeeFloor"` +} + +// String implements the stringer interface, returning the celo config details. +func (o *CeloConfig) String() string { + return fmt.Sprintf("celo(eip1559BaseFeeFloor: %d)", o.EIP1559BaseFeeFloor) } // Description returns a human-readable description of ChainConfig. @@ -504,6 +520,8 @@ func (c *ChainConfig) Description() string { switch { case c.Optimism != nil: banner += "Consensus: Optimism\n" + banner += fmt.Sprintf(" - %s\n", c.Optimism) + banner += fmt.Sprintf(" - %s\n", c.Celo) case c.Ethash != nil: if c.TerminalTotalDifficulty == nil { banner += "Consensus: Ethash (proof-of-work)\n"