Inflation bug fixes (#2982)
* PENDING.md; swap BeginBlocker ordering * Calculate inflation every block * Update x/mint spec * Reset distribution info bond height instead
This commit is contained in:
committed by
Jack Zampolin
parent
bcfd93f544
commit
dfd00a661a
@@ -60,6 +60,8 @@ var (
|
||||
NewMsgWithdrawValidatorRewardsAll = types.NewMsgWithdrawValidatorRewardsAll
|
||||
|
||||
NewDecCoins = types.NewDecCoins
|
||||
|
||||
NewTotalAccum = types.NewTotalAccum
|
||||
)
|
||||
|
||||
const (
|
||||
|
||||
@@ -193,3 +193,13 @@ func (coins DecCoins) HasNegative() bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// return whether all coins are zero
|
||||
func (coins DecCoins) IsZero() bool {
|
||||
for _, coin := range coins {
|
||||
if !coin.Amount.IsZero() {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
+8
-13
@@ -1,31 +1,26 @@
|
||||
package mint
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Inflate every block, update inflation parameters once per hour
|
||||
func BeginBlocker(ctx sdk.Context, k Keeper) {
|
||||
|
||||
blockTime := ctx.BlockHeader().Time
|
||||
// fetch stored minter & params
|
||||
minter := k.GetMinter(ctx)
|
||||
params := k.GetParams(ctx)
|
||||
|
||||
mintedCoin := minter.BlockProvision(params)
|
||||
k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin})
|
||||
k.sk.InflateSupply(ctx, sdk.NewDecFromInt(mintedCoin.Amount))
|
||||
|
||||
if blockTime.Sub(minter.LastUpdate) < time.Hour {
|
||||
return
|
||||
}
|
||||
|
||||
// adjust the inflation, hourly-provision rate every hour
|
||||
// recalculate inflation rate
|
||||
totalSupply := k.sk.TotalPower(ctx)
|
||||
bondedRatio := k.sk.BondedRatio(ctx)
|
||||
minter.Inflation = minter.NextInflationRate(params, bondedRatio)
|
||||
minter.AnnualProvisions = minter.NextAnnualProvisions(params, totalSupply)
|
||||
minter.LastUpdate = blockTime
|
||||
k.SetMinter(ctx, minter)
|
||||
|
||||
// mint coins, add to collected fees, update supply
|
||||
mintedCoin := minter.BlockProvision(params)
|
||||
k.fck.AddCollectedFees(ctx, sdk.Coins{mintedCoin})
|
||||
k.sk.InflateSupply(ctx, sdk.NewDecFromInt(mintedCoin.Amount))
|
||||
|
||||
}
|
||||
|
||||
+4
-11
@@ -2,24 +2,20 @@ package mint
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
// Minter represents the minting state
|
||||
type Minter struct {
|
||||
LastUpdate time.Time `json:"last_update"` // time which the last update was made to the minter
|
||||
Inflation sdk.Dec `json:"inflation"` // current annual inflation rate
|
||||
AnnualProvisions sdk.Dec `json:"annual_provisions"` // current annual expected provisions
|
||||
Inflation sdk.Dec `json:"inflation"` // current annual inflation rate
|
||||
AnnualProvisions sdk.Dec `json:"annual_provisions"` // current annual expected provisions
|
||||
}
|
||||
|
||||
// Create a new minter object
|
||||
func NewMinter(lastUpdate time.Time, inflation,
|
||||
annualProvisions sdk.Dec) Minter {
|
||||
func NewMinter(inflation, annualProvisions sdk.Dec) Minter {
|
||||
|
||||
return Minter{
|
||||
LastUpdate: lastUpdate,
|
||||
Inflation: inflation,
|
||||
AnnualProvisions: annualProvisions,
|
||||
}
|
||||
@@ -28,7 +24,6 @@ func NewMinter(lastUpdate time.Time, inflation,
|
||||
// minter object for a new chain
|
||||
func InitialMinter(inflation sdk.Dec) Minter {
|
||||
return NewMinter(
|
||||
time.Unix(0, 0),
|
||||
inflation,
|
||||
sdk.NewDec(0),
|
||||
)
|
||||
@@ -50,8 +45,6 @@ func validateMinter(minter Minter) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var hrsPerYr = sdk.NewDec(8766) // as defined by a julian year of 365.25 days
|
||||
|
||||
// get the new inflation rate for the next hour
|
||||
func (m Minter) NextInflationRate(params Params, bondedRatio sdk.Dec) (
|
||||
inflation sdk.Dec) {
|
||||
@@ -66,7 +59,7 @@ func (m Minter) NextInflationRate(params Params, bondedRatio sdk.Dec) (
|
||||
inflationRateChangePerYear := sdk.OneDec().
|
||||
Sub(bondedRatio.Quo(params.GoalBonded)).
|
||||
Mul(params.InflationRateChange)
|
||||
inflationRateChange := inflationRateChangePerYear.Quo(hrsPerYr)
|
||||
inflationRateChange := inflationRateChangePerYear.Quo(sdk.NewDec(int64(params.BlocksPerYear)))
|
||||
|
||||
// increase the new annual inflation for this next cycle
|
||||
inflation = m.Inflation.Add(inflationRateChange)
|
||||
|
||||
+35
-6
@@ -12,6 +12,7 @@ import (
|
||||
func TestNextInflation(t *testing.T) {
|
||||
minter := DefaultInitialMinter()
|
||||
params := DefaultParams()
|
||||
blocksPerYr := sdk.NewDec(int64(params.BlocksPerYear))
|
||||
|
||||
// Governing Mechanism:
|
||||
// inflationRateChangePerYear = (1- BondedRatio/ GoalBonded) * MaxInflationRateChange
|
||||
@@ -20,24 +21,24 @@ func TestNextInflation(t *testing.T) {
|
||||
bondedRatio, setInflation, expChange sdk.Dec
|
||||
}{
|
||||
// with 0% bonded atom supply the inflation should increase by InflationRateChange
|
||||
{sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(hrsPerYr)},
|
||||
{sdk.ZeroDec(), sdk.NewDecWithPrec(7, 2), params.InflationRateChange.Quo(blocksPerYr)},
|
||||
|
||||
// 100% bonded, starting at 20% inflation and being reduced
|
||||
// (1 - (1/0.67))*(0.13/8667)
|
||||
{sdk.OneDec(), sdk.NewDecWithPrec(20, 2),
|
||||
sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYr)},
|
||||
sdk.OneDec().Sub(sdk.OneDec().Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(blocksPerYr)},
|
||||
|
||||
// 50% bonded, starting at 10% inflation and being increased
|
||||
{sdk.NewDecWithPrec(5, 1), sdk.NewDecWithPrec(10, 2),
|
||||
sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(hrsPerYr)},
|
||||
sdk.OneDec().Sub(sdk.NewDecWithPrec(5, 1).Quo(params.GoalBonded)).Mul(params.InflationRateChange).Quo(blocksPerYr)},
|
||||
|
||||
// test 7% minimum stop (testing with 100% bonded)
|
||||
{sdk.OneDec(), sdk.NewDecWithPrec(7, 2), sdk.ZeroDec()},
|
||||
{sdk.OneDec(), sdk.NewDecWithPrec(70001, 6), sdk.NewDecWithPrec(-1, 6)},
|
||||
{sdk.OneDec(), sdk.NewDecWithPrec(700000001, 10), sdk.NewDecWithPrec(-1, 10)},
|
||||
|
||||
// test 20% maximum stop (testing with 0% bonded)
|
||||
{sdk.ZeroDec(), sdk.NewDecWithPrec(20, 2), sdk.ZeroDec()},
|
||||
{sdk.ZeroDec(), sdk.NewDecWithPrec(199999, 6), sdk.NewDecWithPrec(1, 6)},
|
||||
{sdk.ZeroDec(), sdk.NewDecWithPrec(1999999999, 10), sdk.NewDecWithPrec(1, 10)},
|
||||
|
||||
// perfect balance shouldn't change inflation
|
||||
{sdk.NewDecWithPrec(67, 2), sdk.NewDecWithPrec(15, 2), sdk.ZeroDec()},
|
||||
@@ -95,8 +96,36 @@ func BenchmarkBlockProvision(b *testing.B) {
|
||||
r1 := rand.New(s1)
|
||||
minter.AnnualProvisions = sdk.NewDec(r1.Int63n(1000000))
|
||||
|
||||
// run the Fib function b.N times
|
||||
// run the BlockProvision function b.N times
|
||||
for n := 0; n < b.N; n++ {
|
||||
minter.BlockProvision(params)
|
||||
}
|
||||
}
|
||||
|
||||
// Next inflation benchmarking
|
||||
// BenchmarkNextInflation-4 1000000 1828 ns/op
|
||||
func BenchmarkNextInflation(b *testing.B) {
|
||||
minter := InitialMinter(sdk.NewDecWithPrec(1, 1))
|
||||
params := DefaultParams()
|
||||
bondedRatio := sdk.NewDecWithPrec(1, 1)
|
||||
|
||||
// run the NextInflationRate function b.N times
|
||||
for n := 0; n < b.N; n++ {
|
||||
minter.NextInflationRate(params, bondedRatio)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Next annual provisions benchmarking
|
||||
// BenchmarkNextAnnualProvisions-4 5000000 251 ns/op
|
||||
func BenchmarkNextAnnualProvisions(b *testing.B) {
|
||||
minter := InitialMinter(sdk.NewDecWithPrec(1, 1))
|
||||
params := DefaultParams()
|
||||
totalSupply := sdk.NewDec(100000000000000)
|
||||
|
||||
// run the NextAnnualProvisions function b.N times
|
||||
for n := 0; n < b.N; n++ {
|
||||
minter.NextAnnualProvisions(params, totalSupply)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user