From 7b4c632066459795f8ff39ca52a71723b40a47e5 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Fri, 1 Jun 2018 10:51:38 +0100 Subject: [PATCH 1/8] autogenerate testaddrs func created --- x/stake/keeper_test.go | 4 ++-- x/stake/test_common.go | 34 ++++++++++++++++++++++++++++++++++ x/stake/tick.go | 6 +++--- x/stake/tick_test.go | 2 +- 4 files changed, 40 insertions(+), 6 deletions(-) diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index f28a2cf684..6e232d4f95 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -115,8 +115,8 @@ func TestValidatorBasics(t *testing.T) { resVals = keeper.GetValidatorsBonded(ctx) require.Equal(t, 3, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[2])) // order doesn't matter here - assert.True(ValEq(t, validators[1], resVals[0])) + assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here + assert.True(ValEq(t, validators[1], resVals[2])) assert.True(ValEq(t, validators[2], resVals[1])) // remove a record diff --git a/x/stake/test_common.go b/x/stake/test_common.go index bf3e665513..2c5785910e 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -3,6 +3,7 @@ package stake import ( "bytes" "encoding/hex" + "strconv" "testing" "github.com/stretchr/testify/require" @@ -162,3 +163,36 @@ func testAddr(addr string, bech string) sdk.Address { return res } + +func createTestAddrs(numAddrs int) []sdk.Address { + var addresses []sdk.Address + var buffer bytes.Buffer + + //start at 10 to avoid changing 1 to 01, 2 to 02, etc + for i := 10; i < numAddrs; i++ { + numString := strconv.Itoa(i) + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA61") //base address string + + buffer.WriteString(numString) //adding on final two digits to make addresses unique + res, _ := sdk.GetAccAddressHex(buffer.String()) + bech, _ := sdk.Bech32CosmosifyAcc(res) + addresses = append(addresses, testAddr(buffer.String(), bech)) + buffer.Reset() + } + return addresses +} + +func createTestPubKeys(numPubKeys int) []crypto.PubKey { + var publicKeys []crypto.PubKey + var buffer bytes.Buffer + + //start at 10 to avoid changing 1 to 01, 2 to 02, etc + for i := 10; i < numPubKeys; i++ { + numString := strconv.Itoa(i) + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB") //base pubkey string + buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + publicKeys = append(publicKeys, newPubKey(buffer.String())) + buffer.Reset() + } + return publicKeys +} diff --git a/x/stake/tick.go b/x/stake/tick.go index a8d9457347..70076c6910 100644 --- a/x/stake/tick.go +++ b/x/stake/tick.go @@ -6,8 +6,8 @@ import ( ) const ( - hrsPerYr = 8766 // as defined by a julian year of 365.25 days - precision = 1000000000 + hrsPerYr = 8766 // as defined by a julian year of 365.25 days + precision = 100000000000 // increased to this precision for accuracy with tests on tick_test.go ) var hrsPerYrRat = sdk.NewRat(hrsPerYr) // as defined by a julian year of 365.25 days @@ -57,7 +57,7 @@ func (k Keeper) nextInflation(ctx sdk.Context) (inflation sdk.Rat) { params := k.GetParams(ctx) pool := k.GetPool(ctx) // The target annual inflation rate is recalculated for each previsions cycle. The - // inflation is also subject to a rate change (positive of negative) depending or + // inflation is also subject to a rate change (positive or negative) depending on // the distance from the desired ratio (67%). The maximum rate change possible is // defined to be 13% per year, however the annual inflation is capped as between // 7% and 20%. diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index 4f0f6dc061..6be3cd59fb 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -112,7 +112,7 @@ func TestProcessProvisions(t *testing.T) { // process the provisions a year for hr := 0; hr < 8766; hr++ { pool := keeper.GetPool(ctx) - expInflation := keeper.nextInflation(ctx).Round(1000000000) + expInflation := keeper.nextInflation(ctx) expProvisions := (expInflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat)).Evaluate() startBondedTokens := pool.BondedTokens startTotalSupply := pool.TokenSupply() From 424ce545ef408aad80b1fb96eb153aa64d41a4f0 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Fri, 1 Jun 2018 11:39:23 +0100 Subject: [PATCH 2/8] autogen addr func updated for 999 addrs if needed --- x/stake/keeper_test.go | 6 +++--- x/stake/test_common.go | 41 ++++++++------------------------------- x/stake/validator_test.go | 8 ++++---- 3 files changed, 15 insertions(+), 40 deletions(-) diff --git a/x/stake/keeper_test.go b/x/stake/keeper_test.go index 6e232d4f95..0e62f0936b 100644 --- a/x/stake/keeper_test.go +++ b/x/stake/keeper_test.go @@ -115,9 +115,9 @@ func TestValidatorBasics(t *testing.T) { resVals = keeper.GetValidatorsBonded(ctx) require.Equal(t, 3, len(resVals)) - assert.True(ValEq(t, validators[0], resVals[0])) // order doesn't matter here - assert.True(ValEq(t, validators[1], resVals[2])) - assert.True(ValEq(t, validators[2], resVals[1])) + assert.True(ValEq(t, validators[0], resVals[2])) // order doesn't matter here + assert.True(ValEq(t, validators[1], resVals[1])) + assert.True(ValEq(t, validators[2], resVals[0])) // remove a record keeper.removeValidator(ctx, validators[1].Owner) diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 2c5785910e..1091120869 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -22,33 +22,8 @@ import ( // dummy addresses used for testing var ( - addrs = []sdk.Address{ - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6160", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctqyxjnwh"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6161", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctpesxxn9"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6162", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctzhrnsa6"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6163", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctr2489qg"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6164", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctytvs4pd"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6165", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ct9k6yqul"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6166", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctxcf3kjq"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6167", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ct89l9r0j"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6168", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctg6jkls2"), - testAddr("A58856F0FD53BF058B4909A21AEC019107BA6169", "cosmosaccaddr:5ky9du8a2wlstz6fpx3p4mqpjyrm5ctf8yz2dc"), - } - - // dummy pubkeys used for testing - pks = []crypto.PubKey{ - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB50"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB51"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB52"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB53"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB54"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB55"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB56"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB57"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB58"), - newPubKey("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB59"), - } - + addrs = createTestAddrs(100) + pks = createTestPubKeys(100) emptyAddr sdk.Address emptyPubkey crypto.PubKey ) @@ -168,10 +143,10 @@ func createTestAddrs(numAddrs int) []sdk.Address { var addresses []sdk.Address var buffer bytes.Buffer - //start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 10; i < numAddrs; i++ { + // start at 100 so we can make up to 999 test addresses with valid test addresses + for i := 100; i < (numAddrs + 100); i++ { numString := strconv.Itoa(i) - buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA61") //base address string + buffer.WriteString("A58856F0FD53BF058B4909A21AEC019107BA6") //base address string buffer.WriteString(numString) //adding on final two digits to make addresses unique res, _ := sdk.GetAccAddressHex(buffer.String()) @@ -187,10 +162,10 @@ func createTestPubKeys(numPubKeys int) []crypto.PubKey { var buffer bytes.Buffer //start at 10 to avoid changing 1 to 01, 2 to 02, etc - for i := 10; i < numPubKeys; i++ { + for i := 100; i < (numPubKeys + 100); i++ { numString := strconv.Itoa(i) - buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AFB") //base pubkey string - buffer.WriteString(numString) //adding on final two digits to make pubkeys unique + buffer.WriteString("0B485CFC0EECC619440448436F8FC9DF40566F2369E72400281454CB552AF") //base pubkey string + buffer.WriteString(numString) //adding on final two digits to make pubkeys unique publicKeys = append(publicKeys, newPubKey(buffer.String())) buffer.Reset() } diff --git a/x/stake/validator_test.go b/x/stake/validator_test.go index 1ca5ba2f75..98a82d1dc1 100644 --- a/x/stake/validator_test.go +++ b/x/stake/validator_test.go @@ -148,7 +148,7 @@ func TestUpdateStatus(t *testing.T) { // TODO refactor this random setup // generate a random validator -func randomValidator(r *rand.Rand) Validator { +func randomValidator(r *rand.Rand, i int) Validator { poolSharesAmt := sdk.NewRat(int64(r.Int31n(10000))) delShares := sdk.NewRat(int64(r.Int31n(10000))) @@ -160,8 +160,8 @@ func randomValidator(r *rand.Rand) Validator { pShares = NewUnbondedShares(poolSharesAmt) } return Validator{ - Owner: addrs[0], - PubKey: pks[0], + Owner: addrs[i], + PubKey: pks[i], PoolShares: pShares, DelegatorShares: delShares, } @@ -173,7 +173,7 @@ func randomSetup(r *rand.Rand, numValidators int) (Pool, Validators) { validators := make([]Validator, numValidators) for i := 0; i < numValidators; i++ { - validator := randomValidator(r) + validator := randomValidator(r, i) if validator.Status() == sdk.Bonded { pool.BondedShares = pool.BondedShares.Add(validator.PoolShares.Bonded()) pool.BondedTokens += validator.PoolShares.Bonded().Evaluate() From 89d6264587f7e8216ed75d5a08b91b3e0cc49b8f Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Tue, 5 Jun 2018 23:02:31 -0400 Subject: [PATCH 3/8] simplified TestProcessProvisions into 4 repeatable funcs. fixed a small bug in it --- x/stake/tick_test.go | 165 +++++++++++++++++++++++++------------------ 1 file changed, 98 insertions(+), 67 deletions(-) diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index 6be3cd59fb..1264814a7b 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -61,80 +61,111 @@ func TestGetInflation(t *testing.T) { func TestProcessProvisions(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - params := defaultParams() - params.MaxValidators = 2 - keeper.setParams(ctx, params) pool := keeper.GetPool(ctx) - var tokenSupply int64 = 550000000 - var bondedShares int64 = 150000000 - var unbondedShares int64 = 400000000 + var ( + initialTotalTokens int64 = 550000000 + initialBondedTokens int64 = 250000000 + initialUnbondedTokens int64 = 300000000 + cumulativeExpProvs int64 + initialBondedShares = sdk.NewRat(250000000, 1) + initialUnbondedShares = sdk.NewRat(300000000, 1) + tokensForValidators = []int64{150000000, 100000000, 100000000, 100000000, 100000000} + bondedValidators uint16 = 2 + ) // create some validators some bonded, some unbonded - var validators [5]Validator - validators[0] = NewValidator(addrs[0], pks[0], Description{}) - validators[0], pool, _ = validators[0].addTokensFromDel(pool, 150000000) - keeper.setPool(ctx, pool) - validators[0] = keeper.updateValidator(ctx, validators[0]) - pool = keeper.GetPool(ctx) - require.Equal(t, bondedShares, pool.BondedTokens, "%v", pool) + _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) - validators[1] = NewValidator(addrs[1], pks[1], Description{}) - validators[1], pool, _ = validators[1].addTokensFromDel(pool, 100000000) - keeper.setPool(ctx, pool) - validators[1] = keeper.updateValidator(ctx, validators[1]) - validators[2] = NewValidator(addrs[2], pks[2], Description{}) - validators[2], pool, _ = validators[2].addTokensFromDel(pool, 100000000) - keeper.setPool(ctx, pool) - validators[2] = keeper.updateValidator(ctx, validators[2]) - validators[3] = NewValidator(addrs[3], pks[3], Description{}) - validators[3], pool, _ = validators[3].addTokensFromDel(pool, 100000000) - keeper.setPool(ctx, pool) - validators[3] = keeper.updateValidator(ctx, validators[3]) - validators[4] = NewValidator(addrs[4], pks[4], Description{}) - validators[4], pool, _ = validators[4].addTokensFromDel(pool, 100000000) - keeper.setPool(ctx, pool) - validators[4] = keeper.updateValidator(ctx, validators[4]) - - assert.Equal(t, tokenSupply, pool.TokenSupply()) - assert.Equal(t, bondedShares, pool.BondedTokens) - assert.Equal(t, unbondedShares, pool.UnbondedTokens) - - // initial bonded ratio ~ 27% - assert.True(t, pool.bondedRatio().Equal(sdk.NewRat(bondedShares, tokenSupply)), "%v", pool.bondedRatio()) - - // test the value of validator shares - assert.True(t, pool.bondedShareExRate().Equal(sdk.OneRat()), "%v", pool.bondedShareExRate()) - - initialSupply := pool.TokenSupply() - initialUnbonded := pool.TokenSupply() - pool.BondedTokens - - // process the provisions a year + // process the provisions for a year for hr := 0; hr < 8766; hr++ { pool := keeper.GetPool(ctx) - expInflation := keeper.nextInflation(ctx) - expProvisions := (expInflation.Mul(sdk.NewRat(pool.TokenSupply())).Quo(hrsPerYrRat)).Evaluate() - startBondedTokens := pool.BondedTokens - startTotalSupply := pool.TokenSupply() - pool = keeper.processProvisions(ctx) - keeper.setPool(ctx, pool) - //fmt.Printf("hr %v, startBondedTokens %v, expProvisions %v, pool.BondedTokens %v\n", hr, startBondedTokens, expProvisions, pool.BondedTokens) - require.Equal(t, startBondedTokens+expProvisions, pool.BondedTokens, "hr %v", hr) - require.Equal(t, startTotalSupply+expProvisions, pool.TokenSupply()) + _, expProvisions, _ := checkAndProcessProvisions(t, keeper, pool, ctx, hr) + cumulativeExpProvs = cumulativeExpProvs + expProvisions } + + //get the pool and do the final value checks from checkFinalPoolValues pool = keeper.GetPool(ctx) - assert.NotEqual(t, initialSupply, pool.TokenSupply()) - assert.Equal(t, initialUnbonded, pool.UnbondedTokens) - //panic(fmt.Sprintf("debug total %v, bonded %v, diff %v\n", p.TotalSupply, p.BondedTokens, pool.TokenSupply()-pool.BondedTokens)) - - // initial bonded ratio ~ from 27% to 40% increase for bonded holders ownership of total supply - assert.True(t, pool.bondedRatio().Equal(sdk.NewRat(211813022, 611813022)), "%v", pool.bondedRatio()) - - // global supply - assert.Equal(t, int64(611813022), pool.TokenSupply()) - assert.Equal(t, int64(211813022), pool.BondedTokens) - assert.Equal(t, unbondedShares, pool.UnbondedTokens) - - // test the value of validator shares - assert.True(t, pool.bondedShareExRate().Mul(sdk.NewRat(bondedShares)).Equal(sdk.NewRat(211813022)), "%v", pool.bondedShareExRate()) + checkFinalPoolValues(t, pool, initialTotalTokens, + initialUnbondedTokens, cumulativeExpProvs, + 0, 0, initialBondedShares, initialUnbondedShares) +} + +////////////////////////////////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 unbonds 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 + 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 candidate 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()) +} + +// Checks provisions are added to the pool correctly every hour +// Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests +func checkAndProcessProvisions(t *testing.T, keeper Keeper, pool Pool, ctx sdk.Context, hr int) (sdk.Rat, int64, Pool) { + + //If we are not doing a random operation, just check that normal provisions are working for each hour + 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 +} + +// Deterministic setup of validators, which updates the pool and choose maxValidators to be bonded +// Allows you to decide how many validators to setup, and which ones you want bonded +// You choose bonded validators by setting params.MaxValidators. If you choose 2, the first 2 Validators in the arrray will be bonded, the rest unbonded +func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTokens []int64, maxValidators uint16) ([]Validator, Keeper, Pool) { + params := defaultParams() + params.MaxValidators = maxValidators //set to limit the amount of validators we want bonded + keeper.setParams(ctx, params) + numValidators := len(validatorTokens) + validators := make([]Validator, numValidators) + + for i := 0; i < numValidators; i++ { + validators[i] = NewValidator(addrs[i], pks[i], Description{}) + validators[i], pool, _ = validators[i].addTokensFromDel(pool, validatorTokens[i]) + keeper.setPool(ctx, pool) + validators[i] = keeper.updateValidator(ctx, validators[i]) + pool = keeper.GetPool(ctx) + } + + return validators, keeper, pool +} + +// Checks that the deterministic candidate setup you wanted matches the values in the pool +func checkValidatorSetup(t *testing.T, pool Pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens int64) { + + assert.Equal(t, initialTotalTokens, pool.TokenSupply()) + assert.Equal(t, initialBondedTokens, pool.BondedTokens) + assert.Equal(t, initialUnbondedTokens, pool.UnbondedTokens) + + // test initial bonded ratio + assert.True(t, pool.bondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.bondedRatio()) + // test the value of candidate shares + assert.True(t, pool.bondedShareExRate().Equal(sdk.OneRat()), "%v", pool.bondedShareExRate()) } From 8d470e5410a04c374c38adbeee537316212d30d1 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Tue, 5 Jun 2018 23:12:28 -0400 Subject: [PATCH 4/8] TestHourlyInflationRateOfChange() added, checks 11.4 years of inflation --- x/stake/tick_test.go | 77 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index 1264814a7b..6bed352f51 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -1,6 +1,7 @@ package stake import ( + "strconv" "testing" sdk "github.com/cosmos/cosmos-sdk/types" @@ -92,6 +93,47 @@ func TestProcessProvisions(t *testing.T) { 0, 0, initialBondedShares, initialUnbondedShares) } +// Tests that the hourly rate of change will be positive, negative, or zero, depending on bonded ratio and inflation rate +// Cycles through the whole gambit of starting at 7% inflation, up to 20%, back down to 7% (it takes ~11.4 years) +func TestHourlyInflationRateOfChange(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + // params := defaultParams() + // keeper.setParams(ctx, params) + pool := keeper.GetPool(ctx) + + // test setUpCandidates returned the token values by passing these vars into checkCandidateSetup() + var ( + initialTotalTokens int64 = 550000000 + initialBondedTokens int64 = 150000000 + initialUnbondedTokens int64 = 400000000 + cumulativeExpProvs int64 + bondedShares = sdk.NewRat(150000000, 1) + unbondedShares = sdk.NewRat(400000000, 1) + tokensForValidators = []int64{150000000, 100000000, 100000000, 100000000, 100000000} + bondedValidators uint16 = 1 + ) + + // create some candidates some bonded, some unbonded + _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + + // ~11.4 years to go from 7%, up to 20%, back down to 7% + for hr := 0; hr < 100000; hr++ { + pool := keeper.GetPool(ctx) + previousInflation := pool.Inflation + updatedInflation, expProvisions, pool := checkAndProcessProvisions(t, keeper, pool, ctx, hr) + cumulativeExpProvs = cumulativeExpProvs + expProvisions + msg := strconv.Itoa(hr) + checkInflation(t, pool, previousInflation, updatedInflation, msg) + } + + // 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) +} + ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions and other functions @@ -169,3 +211,38 @@ func checkValidatorSetup(t *testing.T, pool Pool, initialTotalTokens, initialBon // test the value of candidate shares assert.True(t, pool.bondedShareExRate().Equal(sdk.OneRat()), "%v", pool.bondedShareExRate()) } + +// Checks that The inflation will correctly increase or decrease after an update to the pool +func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Rat, msg string) { + + inflationChange := updatedInflation.Sub(previousInflation) + + switch { + //BELOW 67% - Rate of change positive and increasing, while we are between 7% <= and < 20% inflation + case pool.bondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)): + assert.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + + //BELOW 67% - Rate of change should be 0 while inflation continually stays at 20% until we reach 67% bonded ratio + case pool.bondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): + if previousInflation.Equal(sdk.NewRat(20, 100)) { + assert.Equal(t, true, inflationChange.IsZero(), msg) + //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) + } else { + assert.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) + } + + //ABOVE 67% - Rate of change should be negative while the bond is above 67, and should stay negative until we reach inflation of 7% + case pool.bondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.LT(sdk.NewRat(20, 100)) && updatedInflation.GT(sdk.NewRat(7, 100)): + assert.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + + //ABOVE 67% - Rate of change should be 0 while inflation continually stays at 7%. + case pool.bondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): + if previousInflation.Equal(sdk.NewRat(7, 100)) { + assert.Equal(t, true, inflationChange.IsZero(), msg) + //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) + } else { + assert.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) + } + } + +} From 7cb404d578df12d3d2af921c16e9c9453f0c3131 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Wed, 6 Jun 2018 09:55:34 -0400 Subject: [PATCH 5/8] created a test to check large unbonds lower bonded ratio --- x/stake/tick_test.go | 67 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index 6bed352f51..fb3177f0af 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -1,6 +1,7 @@ package stake import ( + "math/rand" "strconv" "testing" @@ -9,6 +10,9 @@ import ( "github.com/stretchr/testify/require" ) +//change the int in NewSource to generate random input for tests that use r for randomization +var r = rand.New(rand.NewSource(505)) + func TestGetInflation(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) pool := keeper.GetPool(ctx) @@ -97,11 +101,8 @@ func TestProcessProvisions(t *testing.T) { // Cycles through the whole gambit of starting at 7% inflation, up to 20%, back down to 7% (it takes ~11.4 years) func TestHourlyInflationRateOfChange(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - // params := defaultParams() - // keeper.setParams(ctx, params) pool := keeper.GetPool(ctx) - // test setUpCandidates returned the token values by passing these vars into checkCandidateSetup() var ( initialTotalTokens int64 = 550000000 initialBondedTokens int64 = 150000000 @@ -113,7 +114,7 @@ func TestHourlyInflationRateOfChange(t *testing.T) { bondedValidators uint16 = 1 ) - // create some candidates some bonded, some unbonded + // create some validators some bonded, some unbonded _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) @@ -134,6 +135,58 @@ func TestHourlyInflationRateOfChange(t *testing.T) { 0, 0, bondedShares, unbondedShares) } +//Test that a large unbonding will significantly lower the bonded ratio +func TestLargeUnbond(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + // params := defaultParams() + // keeper.setParams(ctx, params) + pool := keeper.GetPool(ctx) + + var ( + initialTotalTokens int64 = 1200000000 + initialBondedTokens int64 = 900000000 + initialUnbondedTokens int64 = 300000000 + val0UnbondedTokens int64 + bondedShares = sdk.NewRat(900000000, 1) + unbondedShares = sdk.NewRat(300000000, 1) + bondSharesVal0 = sdk.NewRat(300000000, 1) + tokensForValidators = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} + bondedValidators uint16 = 7 + ) + + _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + + pool = keeper.GetPool(ctx) + validator, found := keeper.GetValidator(ctx, addrs[0]) + assert.True(t, found) + + // initialBondedRatio that we can use to compare to the new values after the unbond + initialBondedRatio := pool.bondedRatio() + // validator[0] will be unbonded, bringing us from 75% to ~50% + // This func will unbond 300,000,000 tokens that were previously bonded + pool, validator, _, _ = OpBondOrUnbond(r, pool, validator) + keeper.setPool(ctx, pool) + + // process provisions after the bonding, to compare the difference in expProvisions and expInflation + _, expProvisionsAfter, pool := checkAndProcessProvisions(t, keeper, pool, ctx, 0) + + bondedShares = bondedShares.Sub(bondSharesVal0) + val0UnbondedTokens = pool.unbondedShareExRate().Mul(validator.PoolShares.Unbonded()).Evaluate() + unbondedShares = unbondedShares.Add(sdk.NewRat(val0UnbondedTokens, 1).Mul(pool.unbondedShareExRate())) + + // unbonded shares should increase + assert.True(t, unbondedShares.GT(sdk.NewRat(150000000, 1))) + // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 55 < 72) + assert.True(t, (pool.bondedRatio().LT(initialBondedRatio))) + + // 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) +} + ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions and other functions @@ -154,7 +207,7 @@ func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, initialUn assert.Equal(t, calculatedBondedTokens, pool.BondedTokens) assert.Equal(t, calculatedUnbondedTokens, pool.UnbondedTokens) - // test the value of candidate shares + // 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()) } @@ -199,7 +252,7 @@ func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTok return validators, keeper, pool } -// Checks that the deterministic candidate setup you wanted matches the values in the pool +// Checks that the deterministic validator setup you wanted matches the values in the pool func checkValidatorSetup(t *testing.T, pool Pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens int64) { assert.Equal(t, initialTotalTokens, pool.TokenSupply()) @@ -208,7 +261,7 @@ func checkValidatorSetup(t *testing.T, pool Pool, initialTotalTokens, initialBon // test initial bonded ratio assert.True(t, pool.bondedRatio().Equal(sdk.NewRat(initialBondedTokens, initialTotalTokens)), "%v", pool.bondedRatio()) - // test the value of candidate shares + // test the value of validator shares assert.True(t, pool.bondedShareExRate().Equal(sdk.OneRat()), "%v", pool.bondedShareExRate()) } From 5aa6c96cb6316f2d914bee32f8e6ded788c798ab Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Wed, 6 Jun 2018 13:11:36 -0400 Subject: [PATCH 6/8] added Large Bond test for provisions --- x/stake/tick_test.go | 63 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index fb3177f0af..27b3072f9e 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -138,8 +138,6 @@ func TestHourlyInflationRateOfChange(t *testing.T) { //Test that a large unbonding will significantly lower the bonded ratio func TestLargeUnbond(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - // params := defaultParams() - // keeper.setParams(ctx, params) pool := keeper.GetPool(ctx) var ( @@ -176,7 +174,7 @@ func TestLargeUnbond(t *testing.T) { unbondedShares = unbondedShares.Add(sdk.NewRat(val0UnbondedTokens, 1).Mul(pool.unbondedShareExRate())) // unbonded shares should increase - assert.True(t, unbondedShares.GT(sdk.NewRat(150000000, 1))) + assert.True(t, unbondedShares.GT(sdk.NewRat(300000000, 1))) // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 55 < 72) assert.True(t, (pool.bondedRatio().LT(initialBondedRatio))) @@ -187,6 +185,63 @@ func TestLargeUnbond(t *testing.T) { -val0UnbondedTokens, val0UnbondedTokens, bondedShares, unbondedShares) } +//Test that a large bonding will significantly increase the bonded ratio +func TestLargeBond(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + pool := keeper.GetPool(ctx) + + var ( + initialTotalTokens int64 = 1600000000 + initialBondedTokens int64 = 400000000 + initialUnbondedTokens int64 = 1200000000 + val9UnbondedTokens int64 = 400000000 + val9BondedTokens int64 + bondedShares = sdk.NewRat(400000000, 1) + unbondedShares = sdk.NewRat(1200000000, 1) + unbondedSharesVal9 = sdk.NewRat(400000000, 1) + tokensForValidators = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} + bondedValidators uint16 = 1 + ) + + _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) + + pool = keeper.GetPool(ctx) + validator, found := keeper.GetValidator(ctx, addrs[9]) + assert.True(t, found) + + // initialBondedRatio that we can use to compare to the new values after the unbond + initialBondedRatio := pool.bondedRatio() + + params := defaultParams() + params.MaxValidators = bondedValidators + 1 //must do this to allow for an extra validator to bond + keeper.setParams(ctx, params) + + // validator[9] will be bonded, bringing us from 25% to ~50% + // This func will bond 400,000,000 tokens that were previously unbonded + pool, validator, _, _ = OpBondOrUnbond(r, pool, validator) + keeper.setPool(ctx, pool) + + // process provisions after the bonding, to compare the difference in expProvisions and expInflation + _, expProvisionsAfter, pool := checkAndProcessProvisions(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))) + // Ensure that new bonded ratio is greater than old bonded ratio (i.e. 50% > 25%) + assert.True(t, (pool.bondedRatio().GT(initialBondedRatio))) + // 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) +} + ////////////////////////////////HELPER FUNCTIONS BELOW///////////////////////////////////// // Final check on the global pool values for what the total tokens accumulated from each hour of provisions and other functions @@ -245,7 +300,7 @@ func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTok validators[i] = NewValidator(addrs[i], pks[i], Description{}) validators[i], pool, _ = validators[i].addTokensFromDel(pool, validatorTokens[i]) keeper.setPool(ctx, pool) - validators[i] = keeper.updateValidator(ctx, validators[i]) + validators[i] = keeper.updateValidator(ctx, validators[i]) //will kick out lower power validators. must keep in mind when setting up the test validators order pool = keeper.GetPool(ctx) } From 5352b650787fffe7f6302983305ee6201149f79c Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Wed, 6 Jun 2018 14:05:51 -0400 Subject: [PATCH 7/8] Added TestInflationWithRandomOperations --- x/stake/tick_test.go | 119 +++++++++++++++++++++++++++++++------------ 1 file changed, 86 insertions(+), 33 deletions(-) diff --git a/x/stake/tick_test.go b/x/stake/tick_test.go index 27b3072f9e..8096119f42 100644 --- a/x/stake/tick_test.go +++ b/x/stake/tick_test.go @@ -10,8 +10,8 @@ import ( "github.com/stretchr/testify/require" ) -//change the int in NewSource to generate random input for tests that use r for randomization -var r = rand.New(rand.NewSource(505)) +//changing the int in NewSource will allow you to test different, deterministic, sets of operations +var r = rand.New(rand.NewSource(6595)) func TestGetInflation(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) @@ -64,6 +64,7 @@ func TestGetInflation(t *testing.T) { } } +// Test that provisions are correctly added to the pool and validators each hour for 1 year func TestProcessProvisions(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) pool := keeper.GetPool(ctx) @@ -75,18 +76,18 @@ func TestProcessProvisions(t *testing.T) { cumulativeExpProvs int64 initialBondedShares = sdk.NewRat(250000000, 1) initialUnbondedShares = sdk.NewRat(300000000, 1) - tokensForValidators = []int64{150000000, 100000000, 100000000, 100000000, 100000000} + validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} bondedValidators uint16 = 2 ) // create some validators some bonded, some unbonded - _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) // process the provisions for a year for hr := 0; hr < 8766; hr++ { pool := keeper.GetPool(ctx) - _, expProvisions, _ := checkAndProcessProvisions(t, keeper, pool, ctx, hr) + _, expProvisions, _ := updateProvisions(t, keeper, pool, ctx, hr) cumulativeExpProvs = cumulativeExpProvs + expProvisions } @@ -97,8 +98,8 @@ func TestProcessProvisions(t *testing.T) { 0, 0, initialBondedShares, initialUnbondedShares) } -// Tests that the hourly rate of change will be positive, negative, or zero, depending on bonded ratio and inflation rate -// Cycles through the whole gambit of starting at 7% inflation, up to 20%, back down to 7% (it takes ~11.4 years) +// Tests that the hourly rate of change of inflation will be positive, negative, or zero, depending on bonded ratio and inflation rate +// Cycles through the whole gambit of inflation possibilities, starting at 7% inflation, up to 20%, back down to 7% (it takes ~11.4 years) func TestHourlyInflationRateOfChange(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) pool := keeper.GetPool(ctx) @@ -110,19 +111,19 @@ func TestHourlyInflationRateOfChange(t *testing.T) { cumulativeExpProvs int64 bondedShares = sdk.NewRat(150000000, 1) unbondedShares = sdk.NewRat(400000000, 1) - tokensForValidators = []int64{150000000, 100000000, 100000000, 100000000, 100000000} + validatorTokens = []int64{150000000, 100000000, 100000000, 100000000, 100000000} bondedValidators uint16 = 1 ) // create some validators some bonded, some unbonded - _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) // ~11.4 years to go from 7%, up to 20%, back down to 7% for hr := 0; hr < 100000; hr++ { pool := keeper.GetPool(ctx) previousInflation := pool.Inflation - updatedInflation, expProvisions, pool := checkAndProcessProvisions(t, keeper, pool, ctx, hr) + updatedInflation, expProvisions, pool := updateProvisions(t, keeper, pool, ctx, hr) cumulativeExpProvs = cumulativeExpProvs + expProvisions msg := strconv.Itoa(hr) checkInflation(t, pool, previousInflation, updatedInflation, msg) @@ -148,11 +149,11 @@ func TestLargeUnbond(t *testing.T) { bondedShares = sdk.NewRat(900000000, 1) unbondedShares = sdk.NewRat(300000000, 1) bondSharesVal0 = sdk.NewRat(300000000, 1) - tokensForValidators = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} + validatorTokens = []int64{300000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000} bondedValidators uint16 = 7 ) - _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) pool = keeper.GetPool(ctx) @@ -161,13 +162,13 @@ func TestLargeUnbond(t *testing.T) { // initialBondedRatio that we can use to compare to the new values after the unbond initialBondedRatio := pool.bondedRatio() - // validator[0] will be unbonded, bringing us from 75% to ~50% - // This func will unbond 300,000,000 tokens that were previously bonded + + // validator[0] will be unbonded, bringing us from 75% bonded ratio to ~50% (unbonding 300,000,000) pool, validator, _, _ = OpBondOrUnbond(r, pool, validator) keeper.setPool(ctx, pool) // process provisions after the bonding, to compare the difference in expProvisions and expInflation - _, expProvisionsAfter, pool := checkAndProcessProvisions(t, keeper, pool, ctx, 0) + _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) bondedShares = bondedShares.Sub(bondSharesVal0) val0UnbondedTokens = pool.unbondedShareExRate().Mul(validator.PoolShares.Unbonded()).Evaluate() @@ -175,7 +176,7 @@ func TestLargeUnbond(t *testing.T) { // unbonded shares should increase assert.True(t, unbondedShares.GT(sdk.NewRat(300000000, 1))) - // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 55 < 72) + // Ensure that new bonded ratio is less than old bonded ratio , because before they were increasing (i.e. 50% < 75) assert.True(t, (pool.bondedRatio().LT(initialBondedRatio))) // Final check that the pool equals initial values + provisions and adjustments we recorded @@ -199,11 +200,11 @@ func TestLargeBond(t *testing.T) { bondedShares = sdk.NewRat(400000000, 1) unbondedShares = sdk.NewRat(1200000000, 1) unbondedSharesVal9 = sdk.NewRat(400000000, 1) - tokensForValidators = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} + validatorTokens = []int64{400000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 100000000, 400000000} bondedValidators uint16 = 1 ) - _, keeper, pool = setupTestValidators(pool, keeper, ctx, tokensForValidators, bondedValidators) + _, keeper, pool = setupTestValidators(pool, keeper, ctx, validatorTokens, bondedValidators) checkValidatorSetup(t, pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens) pool = keeper.GetPool(ctx) @@ -217,13 +218,12 @@ func TestLargeBond(t *testing.T) { params.MaxValidators = bondedValidators + 1 //must do this to allow for an extra validator to bond keeper.setParams(ctx, params) - // validator[9] will be bonded, bringing us from 25% to ~50% - // This func will bond 400,000,000 tokens that were previously unbonded + // validator[9] will be bonded, bringing us from 25% to ~50% (bonding 400,000,000 tokens) pool, validator, _, _ = OpBondOrUnbond(r, pool, validator) keeper.setPool(ctx, pool) // process provisions after the bonding, to compare the difference in expProvisions and expInflation - _, expProvisionsAfter, pool := checkAndProcessProvisions(t, keeper, pool, ctx, 0) + _, expProvisionsAfter, pool := updateProvisions(t, keeper, pool, ctx, 0) unbondedShares = unbondedShares.Sub(unbondedSharesVal9) val9BondedTokens = val9UnbondedTokens val9UnbondedTokens = 0 @@ -242,10 +242,65 @@ func TestLargeBond(t *testing.T) { val9BondedTokens, -val9BondedTokens, bondedShares, unbondedShares) } +// Tests that inflation increases or decreases as expected when we do a random operation on 20 different validators +func TestInflationWithRandomOperations(t *testing.T) { + ctx, _, keeper := createTestInput(t, false, 0) + params := defaultParams() + keeper.setParams(ctx, params) + numValidators := 20 + + // start off by randomly setting up 20 validators + pool, validators := randomSetup(r, numValidators) + require.Equal(t, numValidators, len(validators)) + + for i := 0; i < len(validators); i++ { + keeper.setValidator(ctx, validators[i]) + } + keeper.setPool(ctx, pool) + + // Used to rotate validators so each random operation is applied to a different validator + validatorCounter := 0 + + // Loop through 20 random operations, and check the inflation after each operation + for i := 0; i < numValidators; i++ { + pool := keeper.GetPool(ctx) + + // Get inflation before randomOperation, for comparison later + previousInflation := pool.Inflation + + // Perform the random operation, and record how validators are modified + poolMod, validatorMod, tokens, msg := randomOperation(r)(r, pool, validators[validatorCounter]) + validatorsMod := make([]Validator, len(validators)) + copy(validatorsMod[:], validators[:]) + require.Equal(t, numValidators, len(validators), "i %v", validatorCounter) + require.Equal(t, numValidators, len(validatorsMod), "i %v", validatorCounter) + validatorsMod[validatorCounter] = validatorMod + + assertInvariants(t, msg, + pool, validators, + poolMod, validatorsMod, tokens) + + // set pool and validators after the random operation + pool = poolMod + keeper.setPool(ctx, pool) + validators = validatorsMod + + // Must set inflation here manually, as opposed to most other tests in this suite, where we call keeper.processProvisions(), which updates pool.Inflation + updatedInflation := keeper.nextInflation(ctx) + pool.Inflation = updatedInflation + keeper.setPool(ctx, pool) + + // Ensure inflation changes as expected when random operations are applied. + checkInflation(t, pool, previousInflation, updatedInflation, msg) + validatorCounter++ + } +} + ////////////////////////////////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 unbonds happened, their total value would be passed as unbondedAdjustment) +// 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) { @@ -267,11 +322,9 @@ func checkFinalPoolValues(t *testing.T, pool Pool, initialTotalTokens, initialUn assert.True(t, pool.unbondedShareExRate().Mul(unbondedShares).Equal(sdk.NewRat(calculatedUnbondedTokens)), "%v", pool.unbondedShareExRate()) } -// Checks provisions are added to the pool correctly every hour +// Processes provisions are added to the pool correctly every hour // Returns expected Provisions, expected Inflation, and pool, to help with cumulative calculations back in main Tests -func checkAndProcessProvisions(t *testing.T, keeper Keeper, pool Pool, ctx sdk.Context, hr int) (sdk.Rat, int64, Pool) { - - //If we are not doing a random operation, just check that normal provisions are working for each hour +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 @@ -286,12 +339,12 @@ func checkAndProcessProvisions(t *testing.T, keeper Keeper, pool Pool, ctx sdk.C return expInflation, expProvisions, pool } -// Deterministic setup of validators, which updates the pool and choose maxValidators to be bonded -// Allows you to decide how many validators to setup, and which ones you want bonded -// You choose bonded validators by setting params.MaxValidators. If you choose 2, the first 2 Validators in the arrray will be bonded, the rest unbonded +// Deterministic setup of validators and pool +// Allows you to decide how many validators to setup +// Allows you to pick which validators are bonded by adjusting the MaxValidators of params func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTokens []int64, maxValidators uint16) ([]Validator, Keeper, Pool) { params := defaultParams() - params.MaxValidators = maxValidators //set to limit the amount of validators we want bonded + params.MaxValidators = maxValidators keeper.setParams(ctx, params) numValidators := len(validatorTokens) validators := make([]Validator, numValidators) @@ -300,7 +353,7 @@ func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTok validators[i] = NewValidator(addrs[i], pks[i], Description{}) validators[i], pool, _ = validators[i].addTokensFromDel(pool, validatorTokens[i]) keeper.setPool(ctx, pool) - validators[i] = keeper.updateValidator(ctx, validators[i]) //will kick out lower power validators. must keep in mind when setting up the test validators order + validators[i] = keeper.updateValidator(ctx, validators[i]) //will kick out lower power validators. Keep this in mind when setting up the test validators order pool = keeper.GetPool(ctx) } @@ -309,7 +362,6 @@ func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTok // Checks that the deterministic validator setup you wanted matches the values in the pool func checkValidatorSetup(t *testing.T, pool Pool, initialTotalTokens, initialBondedTokens, initialUnbondedTokens int64) { - assert.Equal(t, initialTotalTokens, pool.TokenSupply()) assert.Equal(t, initialBondedTokens, pool.BondedTokens) assert.Equal(t, initialUnbondedTokens, pool.UnbondedTokens) @@ -322,7 +374,6 @@ func checkValidatorSetup(t *testing.T, pool Pool, initialTotalTokens, initialBon // Checks that The inflation will correctly increase or decrease after an update to the pool func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation sdk.Rat, msg string) { - inflationChange := updatedInflation.Sub(previousInflation) switch { @@ -334,6 +385,7 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation case pool.bondedRatio().LT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(20, 100)): if previousInflation.Equal(sdk.NewRat(20, 100)) { assert.Equal(t, true, inflationChange.IsZero(), msg) + //This else statement covers the one off case where we first hit 20%, but we still needed a positive ROC to get to 67% bonded ratio (i.e. we went from 19.99999% to 20%) } else { assert.Equal(t, true, inflationChange.GT(sdk.ZeroRat()), msg) @@ -347,6 +399,7 @@ func checkInflation(t *testing.T, pool Pool, previousInflation, updatedInflation case pool.bondedRatio().GT(sdk.NewRat(67, 100)) && updatedInflation.Equal(sdk.NewRat(7, 100)): if previousInflation.Equal(sdk.NewRat(7, 100)) { assert.Equal(t, true, inflationChange.IsZero(), msg) + //This else statement covers the one off case where we first hit 7%, but we still needed a negative ROC to continue to get down to 67%. (i.e. we went from 7.00001% to 7%) } else { assert.Equal(t, true, inflationChange.LT(sdk.ZeroRat()), msg) From 78703f027d77cb881a5f1eec4575f689fa06b270 Mon Sep 17 00:00:00 2001 From: David Kajpust Date: Wed, 6 Jun 2018 15:49:22 -0400 Subject: [PATCH 8/8] fixed small breaking changes from pulling in develop --- x/stake/inflation_test.go | 6 +++--- x/stake/test_common.go | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/x/stake/inflation_test.go b/x/stake/inflation_test.go index 8096119f42..7fa393edc8 100644 --- a/x/stake/inflation_test.go +++ b/x/stake/inflation_test.go @@ -214,7 +214,7 @@ func TestLargeBond(t *testing.T) { // initialBondedRatio that we can use to compare to the new values after the unbond initialBondedRatio := pool.bondedRatio() - params := defaultParams() + params := DefaultParams() params.MaxValidators = bondedValidators + 1 //must do this to allow for an extra validator to bond keeper.setParams(ctx, params) @@ -245,7 +245,7 @@ func TestLargeBond(t *testing.T) { // Tests that inflation increases or decreases as expected when we do a random operation on 20 different validators func TestInflationWithRandomOperations(t *testing.T) { ctx, _, keeper := createTestInput(t, false, 0) - params := defaultParams() + params := DefaultParams() keeper.setParams(ctx, params) numValidators := 20 @@ -343,7 +343,7 @@ func updateProvisions(t *testing.T, keeper Keeper, pool Pool, ctx sdk.Context, h // Allows you to decide how many validators to setup // Allows you to pick which validators are bonded by adjusting the MaxValidators of params func setupTestValidators(pool Pool, keeper Keeper, ctx sdk.Context, validatorTokens []int64, maxValidators uint16) ([]Validator, Keeper, Pool) { - params := defaultParams() + params := DefaultParams() params.MaxValidators = maxValidators keeper.setParams(ctx, params) numValidators := len(validatorTokens) diff --git a/x/stake/test_common.go b/x/stake/test_common.go index 50d8dc37e3..3cea0b281a 100644 --- a/x/stake/test_common.go +++ b/x/stake/test_common.go @@ -150,7 +150,7 @@ func createTestAddrs(numAddrs int) []sdk.Address { buffer.WriteString(numString) //adding on final two digits to make addresses unique res, _ := sdk.GetAccAddressHex(buffer.String()) - bech, _ := sdk.Bech32CosmosifyAcc(res) + bech, _ := sdk.Bech32ifyAcc(res) addresses = append(addresses, testAddr(buffer.String(), bech)) buffer.Reset() }