Merge PR #1233: Inflation now unbonded

working debug fix
add broken test
fix testnet bug
updated provision test
changelog
cwgoes comments
This commit is contained in:
Rigel 2018-06-13 00:12:57 -07:00 committed by Christopher Goes
parent ef2e7a5129
commit 83c1183e25
7 changed files with 138 additions and 52 deletions

View File

@ -12,8 +12,10 @@ IMPROVEMENTS
* [tests] Application module tests now use a mock application
* [gaiacli] Fix error message when account isn't found when running gaiacli account
* [lcd] refactored to eliminate use of global variables, and interdependent tests
* [x/stake] More stake tests added to test ByPower index
FIXES
* [x/stake] bonded inflation removed, non-bonded inflation partially implemented
* [lcd] Switch to bech32 for addresses on all human readable inputs and outputs
* [lcd] fixed tx indexing/querying
* [cli] Added `--gas` flag to specify transaction gas limit

View File

@ -33,6 +33,78 @@ func newTestMsgDelegate(delegatorAddr, validatorAddr sdk.Address, amt int64) Msg
//______________________________________________________________________
func TestValidatorByPowerIndex(t *testing.T) {
validatorAddr, validatorAddr3 := addrs[0], addrs[1]
initBond := int64(1000000)
initBondStr := "1000"
ctx, _, keeper := createTestInput(t, false, initBond)
// create validator
msgCreateValidator := newTestMsgCreateValidator(validatorAddr, pks[0], initBond)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
// verify the self-delegation exists
bond, found := keeper.GetDelegation(ctx, validatorAddr, validatorAddr)
require.True(t, found)
gotBond := bond.Shares.Evaluate()
require.Equal(t, initBond, gotBond,
"initBond: %v\ngotBond: %v\nbond: %v\n",
initBond, gotBond, bond)
// verify that the by power index exists
validator, found := keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
pool := keeper.GetPool(ctx)
power := GetValidatorsByPowerKey(validator, pool)
require.True(t, keeper.validatorByPowerIndexExists(ctx, power))
// create a second validator keep it bonded
msgCreateValidator = newTestMsgCreateValidator(validatorAddr3, pks[2], int64(1000000))
got = handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
assert.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
// slash and revoke the first validator
keeper.Slash(ctx, pks[0], 0, sdk.NewRat(1, 2))
keeper.Revoke(ctx, pks[0])
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.Equal(t, sdk.Unbonded, validator.PoolShares.Status) // ensure is unbonded
require.Equal(t, int64(500000), validator.PoolShares.Amount.Evaluate()) // ensure is unbonded
// the old power record should have been deleted as the power changed
assert.False(t, keeper.validatorByPowerIndexExists(ctx, power))
// but the new power record should have been created
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
pool = keeper.GetPool(ctx)
power2 := GetValidatorsByPowerKey(validator, pool)
require.True(t, keeper.validatorByPowerIndexExists(ctx, power2))
// inflate a bunch
for i := 0; i < 20000; i++ {
pool = keeper.processProvisions(ctx)
keeper.setPool(ctx, pool)
}
// now the new record power index should be the same as the original record
power3 := GetValidatorsByPowerKey(validator, pool)
assert.Equal(t, power2, power3)
// unbond self-delegation
msgUnbond := NewMsgUnbond(validatorAddr, validatorAddr, "MAX")
got = handleMsgUnbond(ctx, msgUnbond, keeper)
assert.True(t, got.IsOK(),
"got: %v\nmsgUnbond: %v\ninitBondStr: %v\n", got, msgUnbond, initBondStr)
// verify that by power key nolonger exists
_, found = keeper.GetValidator(ctx, validatorAddr)
require.False(t, found)
assert.False(t, keeper.validatorByPowerIndexExists(ctx, power3))
}
func TestDuplicatesMsgCreateValidator(t *testing.T) {
ctx, _, keeper := createTestInput(t, false, 1000)
@ -42,6 +114,7 @@ func TestDuplicatesMsgCreateValidator(t *testing.T) {
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
assert.True(t, got.IsOK(), "%v", got)
validator, found := keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
assert.Equal(t, sdk.Bonded, validator.Status())
assert.Equal(t, validatorAddr, validator.Owner)

View File

@ -22,7 +22,9 @@ func (k Keeper) processProvisions(ctx sdk.Context) Pool {
// which needs to be updated is the `BondedPool`. So for each previsions cycle:
provisions := pool.Inflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat).Evaluate()
pool.BondedTokens += provisions
// TODO add to the fees provisions
pool.LooseUnbondedTokens += provisions
return pool
}

View File

@ -74,8 +74,6 @@ func TestProcessProvisions(t *testing.T) {
initialBondedTokens int64 = 250000000
initialUnbondedTokens int64 = 300000000
cumulativeExpProvs int64
initialBondedShares = sdk.NewRat(250000000, 1)
initialUnbondedShares = sdk.NewRat(300000000, 1)
validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000}
bondedValidators uint16 = 2
)
@ -93,9 +91,7 @@ func TestProcessProvisions(t *testing.T) {
//get the pool and do the final value checks from checkFinalPoolValues
pool = keeper.GetPool(ctx)
checkFinalPoolValues(t, pool, initialTotalTokens,
initialUnbondedTokens, cumulativeExpProvs,
0, 0, initialBondedShares, initialUnbondedShares)
checkFinalPoolValues(t, pool, initialTotalTokens, cumulativeExpProvs)
}
// Tests that the hourly rate of change of inflation will be positive, negative, or zero, depending on bonded ratio and inflation rate
@ -109,8 +105,6 @@ func TestHourlyInflationRateOfChange(t *testing.T) {
initialBondedTokens int64 = 150000000
initialUnbondedTokens int64 = 400000000
cumulativeExpProvs int64
bondedShares = sdk.NewRat(150000000, 1)
unbondedShares = sdk.NewRat(400000000, 1)
validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000}
bondedValidators uint16 = 1
)
@ -131,9 +125,7 @@ func TestHourlyInflationRateOfChange(t *testing.T) {
// Final check that the pool equals initial values + cumulative provisions and adjustments we recorded
pool = keeper.GetPool(ctx)
checkFinalPoolValues(t, pool, initialTotalTokens,
initialUnbondedTokens, cumulativeExpProvs,
0, 0, bondedShares, unbondedShares)
checkFinalPoolValues(t, pool, initialTotalTokens, cumulativeExpProvs)
}
//Test that a large unbonding will significantly lower the bonded ratio
@ -181,9 +173,7 @@ func TestLargeUnbond(t *testing.T) {
// Final check that the pool equals initial values + provisions and adjustments we recorded
pool = keeper.GetPool(ctx)
checkFinalPoolValues(t, pool, initialTotalTokens,
initialUnbondedTokens, expProvisionsAfter,
-val0UnbondedTokens, val0UnbondedTokens, bondedShares, unbondedShares)
checkFinalPoolValues(t, pool, initialTotalTokens, expProvisionsAfter)
}
//Test that a large bonding will significantly increase the bonded ratio
@ -192,12 +182,9 @@ func TestLargeBond(t *testing.T) {
pool := keeper.GetPool(ctx)
var (
initialTotalTokens int64 = 1600000000
initialBondedTokens int64 = 400000000
initialUnbondedTokens int64 = 1200000000
val9UnbondedTokens int64 = 400000000
val9BondedTokens int64
bondedShares = sdk.NewRat(400000000, 1)
initialTotalTokens int64 = 1600000000
initialBondedTokens int64 = 400000000
initialUnbondedTokens int64 = 1200000000
unbondedShares = sdk.NewRat(1200000000, 1)
unbondedSharesVal9 = sdk.NewRat(400000000, 1)
validatorTokens = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000}
@ -225,10 +212,6 @@ func TestLargeBond(t *testing.T) {
// process provisions after the bonding, to compare the difference in expProvisions and expInflation
_, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0)
unbondedShares = unbondedShares.Sub(unbondedSharesVal9)
val9BondedTokens = val9UnbondedTokens
val9UnbondedTokens = 0
bondedTokens := initialBondedTokens + val9BondedTokens + expProvisionsAfter
bondedShares = sdk.NewRat(bondedTokens, 1).Quo(pool.bondedShareExRate())
// unbonded shares should decrease
assert.True(t, unbondedShares.LT(sdk.NewRat(1200000000, 1)))
@ -237,9 +220,7 @@ func TestLargeBond(t *testing.T) {
// Final check that the pool equals initial values + provisions and adjustments we recorded
pool = keeper.GetPool(ctx)
checkFinalPoolValues(t, pool, initialTotalTokens,
initialUnbondedTokens, expProvisionsAfter,
val9BondedTokens, -val9BondedTokens, bondedShares, unbondedShares)
checkFinalPoolValues(t, pool, initialTotalTokens, expProvisionsAfter)
}
// Tests that inflation increases or decreases as expected when we do a random operation on 20 different validators
@ -296,30 +277,13 @@ func TestInflationWithRandomOperations(t *testing.T) {
}
}
//_________________________________________________________________________________________
////////////////////////////////HELPER FUNCTIONS BELOW/////////////////////////////////////
// Final check on the global pool values for what the total tokens accumulated from each hour of provisions and other functions
// bondedAdjustment and unbondedAdjustment are the accumulated changes for the operations of the test
// (i.e. if three unbond operations happened, their total value would be passed as unbondedAdjustment)
func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, initialUnbondedTokens,
cumulativeExpProvs, bondedAdjustment, unbondedAdjustment int64, bondedShares, unbondedShares sdk.Rat) {
initialBonded := initialTotalTokens - initialUnbondedTokens
// Final check on the global pool values for what the total tokens accumulated from each hour of provisions
func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, cumulativeExpProvs int64) {
calculatedTotalTokens := initialTotalTokens + cumulativeExpProvs
calculatedBondedTokens := initialBonded + cumulativeExpProvs + bondedAdjustment
calculatedUnbondedTokens := initialUnbondedTokens + unbondedAdjustment
// test that the bonded ratio the pool has is equal to what we calculated for tokens
assert.True(t, pool.bondedRatio().Equal(sdk.NewRat(calculatedBondedTokens, calculatedTotalTokens)), "%v", pool.bondedRatio())
// test global supply
assert.Equal(t, calculatedTotalTokens, pool.TokenSupply())
assert.Equal(t, calculatedBondedTokens, pool.BondedTokens)
assert.Equal(t, calculatedUnbondedTokens, pool.UnbondedTokens)
// test the value of validator shares
assert.True(t, pool.bondedShareExRate().Mul(bondedShares).Equal(sdk.NewRat(calculatedBondedTokens)), "%v", pool.bondedShareExRate())
assert.True(t, pool.unbondedShareExRate().Mul(unbondedShares).Equal(sdk.NewRat(calculatedUnbondedTokens)), "%v", pool.unbondedShareExRate())
}
// Processes provisions are added to the pool correctly every hour
@ -327,13 +291,11 @@ func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, initialUn
func updateProvisions(t *testing.T, keeper Keeper, pool Pool, ctx sdk.Context, hr int) (sdk.Rat, int64, Pool) {
expInflation := keeper.nextInflation(ctx)
expProvisions := (expInflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat)).Evaluate()
startBondedPool := pool.BondedTokens
startTotalSupply := pool.TokenSupply()
pool = keeper.processProvisions(ctx)
keeper.setPool(ctx, pool)
//check provisions were added to pool
require.Equal(t, startBondedPool+expProvisions, pool.BondedTokens, "hr %v", hr)
require.Equal(t, startTotalSupply+expProvisions, pool.TokenSupply())
return expInflation, expProvisions, pool
@ -405,5 +367,4 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation
assert.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg)
}
}
}

View File

@ -78,6 +78,12 @@ func (k Keeper) setValidatorByPowerIndex(ctx sdk.Context, validator Validator, p
store.Set(GetValidatorsByPowerKey(validator, pool), validator.Owner)
}
// used in testing
func (k Keeper) validatorByPowerIndexExists(ctx sdk.Context, power []byte) bool {
store := ctx.KVStore(k.storeKey)
return store.Get(power) != nil
}
// Get the set of all validators with no limits, used during genesis dump
func (k Keeper) getAllValidators(ctx sdk.Context) (validators Validators) {
store := ctx.KVStore(k.storeKey)

View File

@ -24,6 +24,47 @@ var (
}
)
func TestUpdateValidatorByPowerIndex(t *testing.T) {
ctx, _, keeper := createTestInput(t, false, 0)
pool := keeper.GetPool(ctx)
// create a random pool
pool.BondedTokens = 1234
pool.BondedShares = sdk.NewRat(124)
pool.UnbondingTokens = 13934
pool.UnbondingShares = sdk.NewRat(145)
pool.UnbondedTokens = 154
pool.UnbondedShares = sdk.NewRat(1333)
keeper.setPool(ctx, pool)
// add a validator
validator := NewValidator(addrVals[0], pks[0], Description{})
validator, pool, delSharesCreated := validator.addTokensFromDel(pool, 100)
require.Equal(t, sdk.Unbonded, validator.Status())
assert.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate())
keeper.setPool(ctx, pool)
keeper.updateValidator(ctx, validator)
validator, found := keeper.GetValidator(ctx, addrVals[0])
require.True(t, found)
assert.Equal(t, int64(100), validator.PoolShares.Tokens(pool).Evaluate(), "\nvalidator %v\npool %v", validator, pool)
pool = keeper.GetPool(ctx)
power := GetValidatorsByPowerKey(validator, pool)
assert.True(t, keeper.validatorByPowerIndexExists(ctx, power))
// burn half the delegator shares
validator, pool, burned := validator.removeDelShares(pool, delSharesCreated.Quo(sdk.NewRat(2)))
assert.Equal(t, int64(50), burned)
keeper.setPool(ctx, pool) // update the pool
keeper.updateValidator(ctx, validator) // update the validator, possibly kicking it out
assert.False(t, keeper.validatorByPowerIndexExists(ctx, power))
pool = keeper.GetPool(ctx)
validator, found = keeper.GetValidator(ctx, addrVals[0])
power = GetValidatorsByPowerKey(validator, pool)
assert.True(t, keeper.validatorByPowerIndexExists(ctx, power))
}
func TestSetValidator(t *testing.T) {
ctx, _, keeper := createTestInput(t, false, 0)
pool := keeper.GetPool(ctx)

View File

@ -118,13 +118,14 @@ func (s PoolShares) ToBonded(p Pool) PoolShares {
//_________________________________________________________________________________________________________
// TODO better tests
// get the equivalent amount of tokens contained by the shares
func (s PoolShares) Tokens(p Pool) sdk.Rat {
switch s.Status {
case sdk.Bonded:
return p.unbondedShareExRate().Mul(s.Amount) // (tokens/shares) * shares
return p.bondedShareExRate().Mul(s.Amount) // (tokens/shares) * shares
case sdk.Unbonding:
return p.unbondedShareExRate().Mul(s.Amount)
return p.unbondingShareExRate().Mul(s.Amount)
case sdk.Unbonded:
return p.unbondedShareExRate().Mul(s.Amount)
default: