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 }