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:
Christopher Goes
2018-12-04 10:17:02 -08:00
committed by Jack Zampolin
parent bcfd93f544
commit dfd00a661a
11 changed files with 93 additions and 72 deletions
+2
View File
@@ -60,6 +60,8 @@ var (
NewMsgWithdrawValidatorRewardsAll = types.NewMsgWithdrawValidatorRewardsAll
NewDecCoins = types.NewDecCoins
NewTotalAccum = types.NewTotalAccum
)
const (
+10
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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)
}
}