-
Notifications
You must be signed in to change notification settings - Fork 73
/
base_fee.go
155 lines (128 loc) · 4.94 KB
/
base_fee.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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
package keeper
import (
"fmt"
"math/big"
"github.com/artela-network/artela/x/fee/types"
cosmos "github.com/cosmos/cosmos-sdk/types"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/math"
)
// CalculateBaseFee calculates the base fee for the current block. This is only calculated once per
// block during BeginBlock. If the NoBaseFee parameter is enabled or below activation height, this function returns nil.
// NOTE: This code is inspired from the go-ethereum EIP1559 implementation and adapted to Cosmos SDK-based
// chains. For the canonical code refer to: https://github.com/ethereum/go-ethereum/blob/master/consensus/misc/eip1559.go
func (k Keeper) CalculateBaseFee(ctx cosmos.Context) *big.Int {
params := k.GetParams(ctx)
// Ignore the calculation if not enabled
if !params.IsBaseFeeEnabled(ctx.BlockHeight()) {
return nil
}
consParams := ctx.ConsensusParams()
// If the current block is the first EIP-1559 block, return the base fee
// defined in the parameters (DefaultBaseFee if it hasn't been changed by
// governance).
if ctx.BlockHeight() == params.EnableHeight {
return params.BaseFee.BigInt()
}
// get the block gas used and the base fee values for the parent block.
// NOTE: this is not the parent's base fee but the current block's base fee,
// as it is retrieved from the transient store, which is committed to the
// persistent KVStore after EndBlock (ABCI Commit).
parentBaseFee := params.BaseFee.BigInt()
if parentBaseFee == nil {
return nil
}
parentGasUsed := k.GetBlockGasWanted(ctx)
gasLimit := new(big.Int).SetUint64(math.MaxUint64)
// NOTE: a MaxGas equal to -1 means that block gas is unlimited
if consParams != nil && consParams.Block.MaxGas > -1 {
gasLimit = big.NewInt(consParams.Block.MaxGas)
}
// CONTRACT: ElasticityMultiplier cannot be 0 as it's checked in the params
// validation
parentGasTargetBig := new(big.Int).Div(gasLimit, new(big.Int).SetUint64(uint64(params.ElasticityMultiplier)))
if !parentGasTargetBig.IsUint64() {
return nil
}
parentGasTarget := parentGasTargetBig.Uint64()
baseFeeChangeDenominator := new(big.Int).SetUint64(uint64(params.BaseFeeChangeDenominator))
// If the parent gasUsed is the same as the target, the baseFee remains
// unchanged.
if parentGasUsed == parentGasTarget {
return new(big.Int).Set(parentBaseFee)
}
if parentGasUsed > parentGasTarget {
// If the parent block used more gas than its target, the baseFee should
// increase.
gasUsedDelta := new(big.Int).SetUint64(parentGasUsed - parentGasTarget)
x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := math.BigMax(
x.Div(y, baseFeeChangeDenominator),
common.Big1,
)
return x.Add(parentBaseFee, baseFeeDelta)
}
// Otherwise if the parent block used less gas than its target, the baseFee
// should decrease.
gasUsedDelta := new(big.Int).SetUint64(parentGasTarget - parentGasUsed)
x := new(big.Int).Mul(parentBaseFee, gasUsedDelta)
y := x.Div(x, parentGasTargetBig)
baseFeeDelta := x.Div(y, baseFeeChangeDenominator)
// Set global min gas price as lower bound of the base fee, transactions below
// the min gas price don't even reach the mempool.
minGasPrice := params.MinGasPrice.TruncateInt().BigInt()
return math.BigMax(x.Sub(parentBaseFee, baseFeeDelta), minGasPrice)
}
// GetParams returns the total set of fee market parameters.
func (k Keeper) GetParams(ctx cosmos.Context) (params types.Params) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(types.ParamsKey)
if len(bz) == 0 {
var p types.Params
k.ss.GetParamSetIfExists(ctx, &p)
return p
}
k.cdc.MustUnmarshal(bz, ¶ms)
return params
}
// SetParams sets the fee market params in a single key
func (k Keeper) SetParams(ctx cosmos.Context, params types.Params) error {
store := ctx.KVStore(k.storeKey)
bz, err := k.cdc.Marshal(¶ms)
if err != nil {
return err
}
store.Set(types.ParamsKey, bz)
k.Logger(ctx).Debug("setState: SetBlockGasWanted",
"key", string(types.ParamsKey),
"params", fmt.Sprintf("%+v", params))
return nil
}
// ----------------------------------------------------------------------------
// Parent Base Fee
// Required by EIP1559 base fee calculation.
// ----------------------------------------------------------------------------
// GetBaseFeeEnabled returns true if base fee is enabled
func (k Keeper) GetBaseFeeEnabled(ctx cosmos.Context) bool {
params := k.GetParams(ctx)
return !params.NoBaseFee && ctx.BlockHeight() >= params.EnableHeight
}
// GetBaseFee gets the base fee from the store
func (k Keeper) GetBaseFee(ctx cosmos.Context) *big.Int {
params := k.GetParams(ctx)
if params.NoBaseFee {
return nil
}
baseFee := params.BaseFee.BigInt()
return baseFee
}
// SetBaseFee set's the base fee in the store
func (k Keeper) SetBaseFee(ctx cosmos.Context, baseFee *big.Int) {
params := k.GetParams(ctx)
params.BaseFee = cosmos.NewIntFromBigInt(baseFee)
err := k.SetParams(ctx, params)
if err != nil {
return
}
}