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