diff --git a/consensus/misc/basefee.go b/consensus/misc/basefee.go index e2c64b70950c..3b918d74a0ff 100644 --- a/consensus/misc/basefee.go +++ b/consensus/misc/basefee.go @@ -21,6 +21,7 @@ import ( "math/big" "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/params" ) @@ -59,66 +60,55 @@ func VerifyEIP1559BaseFee(config *params.ChainConfig, header, parent *types.Head } // CalcBaseFee returns the baseFee for the current block provided the parent header and config parameters -func CalcBaseFee(config *params.ChainConfig, parent *types.Header) (baseFee *big.Int) { +func CalcBaseFee(config *params.ChainConfig, parent *types.Header) *big.Int { height := new(big.Int).Add(parent.Number, common.Big1) + // If we are before EIP1559 activation, the baseFee is nil if !config.IsEIP1559(height) { - return + return nil } - // never let baseFee drop below 0 - defer func() { - if baseFee.Cmp(common.Big0) < 0 { - baseFee.Set(common.Big0) - } - }() + // If we are at the block of EIP1559 activation then the BaseFee is set to the initial value if config.EIP1559Block.Cmp(height) == 0 { - baseFee = new(big.Int).SetUint64(config.EIP1559.InitialBaseFee) - return + return new(big.Int).SetUint64(config.EIP1559.InitialBaseFee) } - // Otherwise, - // BASEFEE = PARENT_BASEFEE + PARENT_BASEFEE * delta // PARENT_EIP1559_GAS_TARGET // BASEFEE_MAX_CHANGE_DENOMINATOR - // Where delta = PARENT_GAS_USED - PARENT_EIP1559_GAS_TARGET (possibly negative) - parentGasTarget := CalcEIP1559GasTarget(config, parent.Number, new(big.Int).SetUint64(parent.GasLimit)) - delta := new(big.Int).Sub(new(big.Int).SetUint64(parent.GasUsed), parentGasTarget) - // If PARENT_GAS_USAGE == TARGET_GAS_USAGE; BASEFEE = PARENT_BASEFEE - 1 - if delta.Cmp(common.Big0) == 0 { - baseFee = new(big.Int).Sub(parent.BaseFee, common.Big1) - return - } - mul := new(big.Int).Mul(parent.BaseFee, delta) - div := new(big.Int).Div(mul, parentGasTarget) - div2 := new(big.Int).Div(div, new(big.Int).SetUint64(config.EIP1559.EIP1559BaseFeeMaxChangeDenominator)) - baseFee = new(big.Int).Add(parent.BaseFee, div2) + parentBaseFee := parent.BaseFee + parentBlockGasUsed := new(big.Int).SetUint64(parent.GasUsed) + targetGasUsed := new(big.Int).SetUint64(parent.GasLimit) + baseFeeMaxChangeDenominator := new(big.Int).SetUint64(config.EIP1559.EIP1559BaseFeeMaxChangeDenominator) - // A valid BASEFEE is one such that - // abs(BASEFEE - PARENT_BASEFEE) <= max(1, PARENT_BASEFEE // BASEFEE_MAX_CHANGE_DENOMINATOR) - // abs(BASEFEE - PARENT_BASEFEE) >= 1 - diff := new(big.Int).Sub(baseFee, parent.BaseFee) - neg := false - if diff.Sign() < 0 { - neg = true - diff.Neg(diff) - } - min := common.Big1 - max := new(big.Int).Div(parent.BaseFee, new(big.Int).SetUint64(config.EIP1559.EIP1559BaseFeeMaxChangeDenominator)) - if max.Cmp(common.Big1) < 0 { - max = common.Big1 + cmp := parentBlockGasUsed.Cmp(targetGasUsed) + + if cmp == 0 { + return targetGasUsed } - // If BASEFEE is not valid, restrict it within the bounds - if diff.Cmp(max) > 0 { - if neg { - max.Neg(max) - } - baseFee.Set(new(big.Int).Add(parent.BaseFee, max)) - } else if diff.Cmp(min) < 0 { - if neg { - min.Neg(min) - } - baseFee.Set(new(big.Int).Add(parent.BaseFee, min)) + + if cmp > 0 { + gasDelta := new(big.Int).Sub(parentBlockGasUsed, targetGasUsed) + feeDelta := math.BigMax( + new(big.Int).Div( + new(big.Int).Div( + new(big.Int).Mul(parentBaseFee, gasDelta), + targetGasUsed, + ), + baseFeeMaxChangeDenominator, + ), + common.Big1, + ) + return new(big.Int).Add(parentBaseFee, feeDelta) } - return baseFee + + gasDelta := new(big.Int).Sub(targetGasUsed, parentBlockGasUsed) + feeDelta := new(big.Int).Div( + new(big.Int).Div( + new(big.Int).Mul(parentBaseFee, gasDelta), + targetGasUsed, + ), + baseFeeMaxChangeDenominator, + ) + + return new(big.Int).Sub(parentBaseFee, feeDelta) } // CalcEIP1559GasTarget returns the EIP1559GasTarget at the current height and header.GasLimit