github.com/klaytn/klaytn@v1.12.1/consensus/misc/kip71.go (about)

     1  package misc
     2  
     3  import (
     4  	"fmt"
     5  	"math/big"
     6  
     7  	"github.com/klaytn/klaytn/blockchain/types"
     8  	"github.com/klaytn/klaytn/common"
     9  	"github.com/klaytn/klaytn/common/math"
    10  	"github.com/klaytn/klaytn/consensus"
    11  	"github.com/klaytn/klaytn/params"
    12  )
    13  
    14  func VerifyMagmaHeader(parentHeader, header *types.Header, kip71Config *params.KIP71Config) error {
    15  	if parentHeader == nil {
    16  		return consensus.ErrUnknownAncestor
    17  	}
    18  	if header.BaseFee == nil {
    19  		return fmt.Errorf("header is missing baseFee")
    20  	}
    21  	// Verify the baseFee is correct based on the parent header.
    22  	expectedBaseFee := NextMagmaBlockBaseFee(parentHeader, kip71Config)
    23  	if header.BaseFee.Cmp(expectedBaseFee) != 0 {
    24  		return fmt.Errorf("invalid baseFee: have %s, want %s, parentBaseFee %s, parentGasUsed %d",
    25  			header.BaseFee, expectedBaseFee, parentHeader.BaseFee, parentHeader.GasUsed)
    26  	}
    27  	return nil
    28  }
    29  
    30  func makeEvenByFloor(baseFee *big.Int) *big.Int {
    31  	if baseFee.Bit(0) != 0 {
    32  		baseFee.Sub(baseFee, common.Big1)
    33  	}
    34  	return baseFee
    35  }
    36  
    37  func makeEvenByCeil(baseFee *big.Int) *big.Int {
    38  	if baseFee.Bit(0) != 0 {
    39  		baseFee.Add(baseFee, common.Big1)
    40  	}
    41  	return baseFee
    42  }
    43  
    44  func NextMagmaBlockBaseFee(parentHeader *types.Header, kip71Config *params.KIP71Config) *big.Int {
    45  	// governance parameters
    46  	lowerBoundBaseFee := new(big.Int).SetUint64(kip71Config.LowerBoundBaseFee)
    47  	upperBoundBaseFee := new(big.Int).SetUint64(kip71Config.UpperBoundBaseFee)
    48  	makeEvenByCeil(lowerBoundBaseFee)
    49  	makeEvenByFloor(upperBoundBaseFee)
    50  
    51  	nextFee := nextBlockBaseFee(parentHeader, kip71Config, lowerBoundBaseFee, upperBoundBaseFee)
    52  	return makeEvenByFloor(nextFee)
    53  }
    54  
    55  func nextBlockBaseFee(parentHeader *types.Header, kip71Config *params.KIP71Config, lowerBoundBaseFee, upperBoundBaseFee *big.Int) *big.Int {
    56  	// If the parent is the magma disabled block or genesis, then return the lowerBoundBaseFee (default 25ston)
    57  	if parentHeader.Number.Cmp(new(big.Int).SetUint64(0)) == 0 || parentHeader.BaseFee == nil {
    58  		return lowerBoundBaseFee
    59  	}
    60  
    61  	var baseFeeDenominator *big.Int
    62  	if kip71Config.BaseFeeDenominator == 0 {
    63  		// To avoid panic, set the fluctuation range small
    64  		baseFeeDenominator = new(big.Int).SetUint64(64)
    65  	} else {
    66  		baseFeeDenominator = new(big.Int).SetUint64(kip71Config.BaseFeeDenominator)
    67  	}
    68  	gasTarget := kip71Config.GasTarget
    69  	upperGasLimit := kip71Config.MaxBlockGasUsedForBaseFee
    70  
    71  	// check the case of upper/lowerBoundBaseFee is updated by governance mechanism
    72  	parentBaseFee := parentHeader.BaseFee
    73  	if parentBaseFee.Cmp(upperBoundBaseFee) >= 0 {
    74  		parentBaseFee = upperBoundBaseFee
    75  	} else if parentBaseFee.Cmp(lowerBoundBaseFee) <= 0 {
    76  		parentBaseFee = lowerBoundBaseFee
    77  	}
    78  
    79  	parentGasUsed := parentHeader.GasUsed
    80  	// upper gas limit cut off the impulse of used gas to upper bound
    81  	if parentGasUsed > upperGasLimit {
    82  		parentGasUsed = upperGasLimit
    83  	}
    84  	if parentGasUsed == gasTarget {
    85  		return parentBaseFee
    86  	} else if parentGasUsed > gasTarget {
    87  		// shortcut. If parentBaseFee is already reached upperbound, do not calculate.
    88  		if parentBaseFee.Cmp(upperBoundBaseFee) == 0 {
    89  			return upperBoundBaseFee
    90  		}
    91  		// If the parent block used more gas than its target,
    92  		// the baseFee of the next block should increase.
    93  		// baseFeeDelta = max(1, parentBaseFee * (parentGasUsed - gasTarget) / gasTarget / baseFeeDenominator)
    94  		gasUsedDelta := new(big.Int).SetUint64(parentGasUsed - gasTarget)
    95  		x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
    96  		y := x.Div(x, new(big.Int).SetUint64(gasTarget))
    97  		baseFeeDelta := math.BigMax(x.Div(y, baseFeeDenominator), common.Big1)
    98  
    99  		nextBaseFee := x.Add(parentBaseFee, baseFeeDelta)
   100  		if nextBaseFee.Cmp(upperBoundBaseFee) > 0 {
   101  			return upperBoundBaseFee
   102  		}
   103  		return nextBaseFee
   104  	} else {
   105  		// shortcut. If parentBaseFee is already reached lower bound, do not calculate.
   106  		if parentBaseFee.Cmp(lowerBoundBaseFee) == 0 {
   107  			return lowerBoundBaseFee
   108  		}
   109  		// Otherwise if the parent block used less gas than its target,
   110  		// the baseFee of the next block should decrease.
   111  		// baseFeeDelta = parentBaseFee * (gasTarget - parentGasUsed) / gasTarget / baseFeeDenominator
   112  		gasUsedDelta := new(big.Int).SetUint64(gasTarget - parentGasUsed)
   113  		x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
   114  		y := x.Div(x, new(big.Int).SetUint64(gasTarget))
   115  		baseFeeDelta := x.Div(y, baseFeeDenominator)
   116  
   117  		nextBaseFee := x.Sub(parentBaseFee, baseFeeDelta)
   118  		if nextBaseFee.Cmp(lowerBoundBaseFee) < 0 {
   119  			return lowerBoundBaseFee
   120  		}
   121  		return nextBaseFee
   122  	}
   123  }