Merge PR #2238: Ensure Tendermint Validator Update Invariants

This commit is contained in:
Alexander Bezobchuk 2018-09-12 07:16:28 +00:00 committed by Christopher Goes
parent 55b7c6adf1
commit 854aca2f7d
7 changed files with 258 additions and 72 deletions

View File

@ -122,6 +122,8 @@ BUG FIXES
* [cli] [\#2265](https://github.com/cosmos/cosmos-sdk/issues/2265) Fix JSON formatting of the `gaiacli send` command.
* Gaia
* [x/stake] Return correct Tendermint validator update set on `EndBlocker` by not
including non previously bonded validators that have zero power. [#2189](https://github.com/cosmos/cosmos-sdk/issues/2189)
* SDK
* [\#1988](https://github.com/cosmos/cosmos-sdk/issues/1988) Make us compile on OpenBSD (disable ledger) [#1988] (https://github.com/cosmos/cosmos-sdk/issues/1988)

View File

@ -12,7 +12,7 @@ the changes cleared
```golang
EndBlock() ValidatorSetChanges
vsc = GetTendermintUpdates()
vsc = GetValidTendermintUpdates()
ClearTendermintUpdates()
return vsc
```

View File

@ -156,13 +156,16 @@ func SimulateMsgVote(k gov.Keeper, sk stake.Keeper) simulation.Operation {
return operationSimulateMsgVote(k, sk, nil, -1)
}
// nolint: unparam
func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey, proposalID int64) simulation.Operation {
return func(r *rand.Rand, app *baseapp.BaseApp, ctx sdk.Context, keys []crypto.PrivKey, event func(string)) (action string, fOp []simulation.FutureOperation, err error) {
if key == nil {
key = simulation.RandomKey(r, keys)
}
var ok bool
if proposalID < 0 {
proposalID, ok = randomProposalID(r, k, ctx)
if !ok {
@ -171,15 +174,18 @@ func operationSimulateMsgVote(k gov.Keeper, sk stake.Keeper, key crypto.PrivKey,
}
addr := sdk.AccAddress(key.PubKey().Address())
option := randomVotingOption(r)
msg := gov.NewMsgVote(addr, proposalID, option)
if msg.ValidateBasic() != nil {
return "", nil, fmt.Errorf("expected msg to pass ValidateBasic: %s", msg.GetSignBytes())
}
ctx, write := ctx.CacheContext()
result := gov.NewHandler(k)(ctx, msg)
if result.IsOK() {
write()
}
event(fmt.Sprintf("gov/MsgVote/%v", result.IsOK()))
action = fmt.Sprintf("TestMsgVote: ok %v, msg %s", result.IsOK(), msg.GetSignBytes())
return action, nil, nil

View File

@ -342,18 +342,14 @@ func RandomRequestBeginBlock(r *rand.Rand, validators map[string]mockValidator,
// updateValidators mimicks Tendermint's update logic
// nolint: unparam
func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValidator, updates []abci.Validator, event func(string)) map[string]mockValidator {
for _, update := range updates {
switch {
case update.Power == 0:
// // TEMPORARY DEBUG CODE TO PROVE THAT THE OLD METHOD WAS BROKEN
// // (i.e. didn't catch in the event of problem)
// if val, ok := tb.(*testing.T); ok {
// require.NotNil(val, current[string(update.PubKey.Data)])
// }
// // CORRECT CHECK
// if _, ok := current[string(update.PubKey.Data)]; !ok {
// tb.Fatalf("tried to delete a nonexistent validator")
// }
if _, ok := current[string(update.PubKey.Data)]; !ok {
tb.Fatalf("tried to delete a nonexistent validator")
}
event("endblock/validatorupdates/kicked")
delete(current, string(update.PubKey.Data))
default:
@ -368,5 +364,6 @@ func updateValidators(tb testing.TB, r *rand.Rand, current map[string]mockValida
}
}
}
return current
}

View File

@ -52,7 +52,7 @@ func EndBlocker(ctx sdk.Context, k keeper.Keeper) (ValidatorUpdates []abci.Valid
k.SetIntraTxCounter(ctx, 0)
// calculate validator set changes
ValidatorUpdates = k.GetTendermintUpdates(ctx)
ValidatorUpdates = k.GetValidTendermintUpdates(ctx)
k.ClearTendermintUpdates(ctx)
return
}

View File

@ -198,16 +198,37 @@ func (k Keeper) GetValidatorsByPower(ctx sdk.Context) []types.Validator {
// Accumulated updates to the active/bonded validator set for tendermint
// get the most recently updated validators
func (k Keeper) GetTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) {
//
// CONTRACT: Only validators with non-zero power or zero-power that were bonded
// at the previous block height or were removed from the validator set entirely
// are returned to Tendermint.
func (k Keeper) GetValidTendermintUpdates(ctx sdk.Context) (updates []abci.Validator) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesKey) //smallest to largest
iterator := sdk.KVStorePrefixIterator(store, TendermintUpdatesKey)
for ; iterator.Valid(); iterator.Next() {
valBytes := iterator.Value()
var val abci.Validator
k.cdc.MustUnmarshalBinary(valBytes, &val)
updates = append(updates, val)
var abciVal abci.Validator
abciValBytes := iterator.Value()
k.cdc.MustUnmarshalBinary(abciValBytes, &abciVal)
val, found := k.GetValidator(ctx, abciVal.GetAddress())
if found {
// The validator is new or already exists in the store and must adhere to
// Tendermint invariants.
prevBonded := val.BondHeight < ctx.BlockHeight() && val.BondHeight > val.UnbondingHeight
zeroPower := val.GetPower().Equal(sdk.ZeroDec())
if !zeroPower || zeroPower && prevBonded {
updates = append(updates, abciVal)
}
} else {
// Add the ABCI validator in such a case where the validator was removed
// from the store as it must have existed before.
updates = append(updates, abciVal)
}
}
iterator.Close()
return
}
@ -240,7 +261,7 @@ func (k Keeper) UpdateValidator(ctx sdk.Context, validator types.Validator) type
validator = k.updateForJailing(ctx, oldFound, oldValidator, validator)
powerIncreasing := k.getPowerIncreasing(ctx, oldFound, oldValidator, validator)
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator, validator)
validator.BondHeight, validator.BondIntraTxCounter = k.bondIncrement(ctx, oldFound, oldValidator)
valPower := k.updateValidatorPower(ctx, oldFound, oldValidator, validator, pool)
cliffPower := k.GetCliffValidatorPower(ctx)
cliffValExists := (cliffPower != nil)
@ -316,7 +337,7 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
oldCliffVal, found := k.GetValidator(ctx, cliffAddr)
if !found {
panic(fmt.Sprintf("cliff validator record not found for address: %v\n", cliffAddr))
panic(fmt.Sprintf("cliff validator record not found for address: %X\n", cliffAddr))
}
// Create a validator iterator ranging from smallest to largest by power
@ -331,7 +352,7 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
ensureValidatorFound(found, ownerAddr)
if currVal.Status != sdk.Bonded || currVal.Jailed {
panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %s\n", ownerAddr))
panic(fmt.Sprintf("unexpected jailed or unbonded validator for address: %X\n", ownerAddr))
}
newCliffVal = currVal
@ -344,13 +365,10 @@ func (k Keeper) updateCliffValidator(ctx sdk.Context, affectedVal types.Validato
newCliffValRank := GetValidatorsByPowerIndexKey(newCliffVal, pool)
if bytes.Equal(affectedVal.OperatorAddr, newCliffVal.OperatorAddr) {
// The affected validator remains the cliff validator, however, since
// the store does not contain the new power, update the new power rank.
store.Set(ValidatorPowerCliffKey, affectedValRank)
} else if bytes.Compare(affectedValRank, newCliffValRank) > 0 {
// The affected validator no longer remains the cliff validator as it's
// power is greater than the new cliff validator.
k.setCliffValidator(ctx, newCliffVal, pool)
@ -381,18 +399,20 @@ func (k Keeper) getPowerIncreasing(ctx sdk.Context, oldFound bool, oldValidator,
// get the bond height and incremented intra-tx counter
// nolint: unparam
func (k Keeper) bondIncrement(ctx sdk.Context, oldFound bool, oldValidator,
newValidator types.Validator) (height int64, intraTxCounter int16) {
func (k Keeper) bondIncrement(
ctx sdk.Context, found bool, oldValidator types.Validator) (height int64, intraTxCounter int16) {
// if already a validator, copy the old block height and counter, else set them
if oldFound && oldValidator.Status == sdk.Bonded {
// if already a validator, copy the old block height and counter
if found && oldValidator.Status == sdk.Bonded {
height = oldValidator.BondHeight
intraTxCounter = oldValidator.BondIntraTxCounter
return
}
height = ctx.BlockHeight()
counter := k.GetIntraTxCounter(ctx)
intraTxCounter = counter
k.SetIntraTxCounter(ctx, counter+1)
return
}
@ -458,22 +478,20 @@ func (k Keeper) UpdateBondedValidators(
// if we've reached jailed validators no further bonded validators exist
if validator.Jailed {
break
}
// increment bondedValidatorsCount / get the validator to bond
if validator.Status != sdk.Bonded {
validatorToBond = validator
if newValidatorBonded {
panic("already decided to bond a validator, can't bond another!")
if validator.Status == sdk.Bonded {
panic(fmt.Sprintf("jailed validator cannot be bonded, address: %X\n", ownerAddr))
}
newValidatorBonded = true
break
}
// increment the total number of bonded validators and potentially mark
// the validator to bond
if validator.Status != sdk.Bonded {
validatorToBond = validator
if newValidatorBonded {
panic("already decided to bond a validator, can't bond another!")
}
newValidatorBonded = true
}
@ -507,7 +525,6 @@ func (k Keeper) UpdateBondedValidators(
// validator was newly bonded and has greater power
k.beginUnbondingValidator(ctx, oldCliffVal)
} else {
// otherwise begin unbonding the affected validator, which must
// have been kicked out
affectedValidator = k.beginUnbondingValidator(ctx, affectedValidator)
@ -653,6 +670,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
panic(fmt.Sprintf("should not already be bonded, validator: %v\n", validator))
}
validator.BondHeight = ctx.BlockHeight()
// set the status
validator, pool = validator.UpdateStatus(pool, sdk.Bonded)
k.SetPool(ctx, pool)

View File

@ -16,8 +16,11 @@ func TestSetValidator(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 10)
pool := keeper.GetPool(ctx)
valPubKey := PKs[0]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
// test how the validator is set from a purely unbonbed pool
validator := types.NewValidator(addrVals[0], PKs[0], types.Description{})
validator := types.NewValidator(valAddr, valPubKey, types.Description{})
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(10))
require.Equal(t, sdk.Unbonded, validator.Status)
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
@ -26,14 +29,14 @@ func TestSetValidator(t *testing.T) {
keeper.UpdateValidator(ctx, validator)
// after the save the validator should be bonded
validator, found := keeper.GetValidator(ctx, addrVals[0])
validator, found := keeper.GetValidator(ctx, valAddr)
require.True(t, found)
require.Equal(t, sdk.Bonded, validator.Status)
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.Tokens))
assert.True(sdk.DecEq(t, sdk.NewDec(10), validator.DelegatorShares))
// Check each store for being saved
resVal, found := keeper.GetValidator(ctx, addrVals[0])
resVal, found := keeper.GetValidator(ctx, valAddr)
assert.True(ValEq(t, validator, resVal))
require.True(t, found)
@ -45,7 +48,7 @@ func TestSetValidator(t *testing.T) {
require.Equal(t, 1, len(resVals))
assert.True(ValEq(t, validator, resVals[0]))
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 1, len(updates))
require.Equal(t, validator.ABCIValidator(), updates[0])
}
@ -641,38 +644,47 @@ func TestClearTendermintUpdates(t *testing.T) {
validators := make([]types.Validator, len(amts))
for i, amt := range amts {
pool := keeper.GetPool(ctx)
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{})
valPubKey := PKs[i]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
keeper.SetPool(ctx, pool)
keeper.UpdateValidator(ctx, validators[i])
}
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, len(amts), len(updates))
keeper.ClearTendermintUpdates(ctx)
updates = keeper.GetTendermintUpdates(ctx)
updates = keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 0, len(updates))
}
func TestGetTendermintUpdatesAllNone(t *testing.T) {
func TestGetValidTendermintUpdatesAllNone(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{10, 20}
var validators [2]types.Validator
for i, amt := range amts {
pool := keeper.GetPool(ctx)
validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{})
valPubKey := PKs[i+1]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
keeper.SetPool(ctx, pool)
}
// test from nothing to something
// tendermintUpdate set: {} -> {c1, c3}
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
assert.Equal(t, 2, len(updates))
assert.Equal(t, validators[0].ABCIValidator(), updates[0])
assert.Equal(t, validators[1].ABCIValidator(), updates[1])
@ -680,12 +692,12 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) {
// test from something to nothing
// tendermintUpdate set: {} -> {c1, c2, c3, c4}
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
keeper.RemoveValidator(ctx, validators[0].OperatorAddr)
keeper.RemoveValidator(ctx, validators[1].OperatorAddr)
updates = keeper.GetTendermintUpdates(ctx)
updates = keeper.GetValidTendermintUpdates(ctx)
assert.Equal(t, 2, len(updates))
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[0].ConsPubKey), updates[0].PubKey)
assert.Equal(t, tmtypes.TM2PB.PubKey(validators[1].ConsPubKey), updates[1].PubKey)
@ -693,7 +705,7 @@ func TestGetTendermintUpdatesAllNone(t *testing.T) {
assert.Equal(t, int64(0), updates[1].Power)
}
func TestGetTendermintUpdatesIdentical(t *testing.T) {
func TestGetValidTendermintUpdatesIdentical(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{10, 20}
@ -707,16 +719,16 @@ func TestGetTendermintUpdatesIdentical(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// test identical,
// tendermintUpdate set: {} -> {}
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
}
func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
func TestGetValidTendermintUpdatesSingleValueChange(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{10, 20}
@ -730,7 +742,7 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// test single value change
// tendermintUpdate set: {} -> {c1'}
@ -738,13 +750,13 @@ func TestGetTendermintUpdatesSingleValueChange(t *testing.T) {
validators[0].Tokens = sdk.NewDec(600)
validators[0] = keeper.UpdateValidator(ctx, validators[0])
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 1, len(updates))
require.Equal(t, validators[0].ABCIValidator(), updates[0])
}
func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
func TestGetValidTendermintUpdatesMultipleValueChange(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{10, 20}
@ -758,7 +770,7 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// test multiple value change
// tendermintUpdate set: {c1, c3} -> {c1', c3'}
@ -769,13 +781,13 @@ func TestGetTendermintUpdatesMultipleValueChange(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 2, len(updates))
require.Equal(t, validators[0].ABCIValidator(), updates[0])
require.Equal(t, validators[1].ABCIValidator(), updates[1])
}
func TestGetTendermintUpdatesInserted(t *testing.T) {
func TestGetValidTendermintUpdatesInserted(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{10, 20, 5, 15, 25}
@ -789,12 +801,12 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// test validtor added at the beginning
// tendermintUpdate set: {} -> {c0}
validators[2] = keeper.UpdateValidator(ctx, validators[2])
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 1, len(updates))
require.Equal(t, validators[2].ABCIValidator(), updates[0])
@ -802,7 +814,7 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
// tendermintUpdate set: {} -> {c0}
keeper.ClearTendermintUpdates(ctx)
validators[3] = keeper.UpdateValidator(ctx, validators[3])
updates = keeper.GetTendermintUpdates(ctx)
updates = keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 1, len(updates))
require.Equal(t, validators[3].ABCIValidator(), updates[0])
@ -810,12 +822,12 @@ func TestGetTendermintUpdatesInserted(t *testing.T) {
// tendermintUpdate set: {} -> {c0}
keeper.ClearTendermintUpdates(ctx)
validators[4] = keeper.UpdateValidator(ctx, validators[4])
updates = keeper.GetTendermintUpdates(ctx)
updates = keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 1, len(updates))
require.Equal(t, validators[4].ABCIValidator(), updates[0])
}
func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) {
func TestGetValidTendermintUpdatesWithCliffValidator(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
params := types.DefaultParams()
params.MaxValidators = 2
@ -832,31 +844,31 @@ func TestGetTendermintUpdatesWithCliffValidator(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// test validator added at the end but not inserted in the valset
// tendermintUpdate set: {} -> {}
keeper.UpdateValidator(ctx, validators[2])
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 0, len(updates))
// test validator change its power and become a gotValidator (pushing out an existing)
// tendermintUpdate set: {} -> {c0, c4}
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
pool := keeper.GetPool(ctx)
validators[2], pool, _ = validators[2].AddTokensFromDel(pool, sdk.NewInt(10))
keeper.SetPool(ctx, pool)
validators[2] = keeper.UpdateValidator(ctx, validators[2])
updates = keeper.GetTendermintUpdates(ctx)
updates = keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 2, len(updates), "%v", updates)
require.Equal(t, validators[0].ABCIValidatorZero(), updates[0])
require.Equal(t, validators[2].ABCIValidator(), updates[1])
}
func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
func TestGetValidTendermintUpdatesPowerDecrease(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
amts := []int64{100, 100}
@ -870,7 +882,7 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
validators[0] = keeper.UpdateValidator(ctx, validators[0])
validators[1] = keeper.UpdateValidator(ctx, validators[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetTendermintUpdates(ctx)))
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// check initial power
require.Equal(t, sdk.NewDec(100).RoundInt64(), validators[0].GetPower().RoundInt64())
@ -890,8 +902,158 @@ func TestGetTendermintUpdatesPowerDecrease(t *testing.T) {
require.Equal(t, sdk.NewDec(70).RoundInt64(), validators[1].GetPower().RoundInt64())
// Tendermint updates should reflect power change
updates := keeper.GetTendermintUpdates(ctx)
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 2, len(updates))
require.Equal(t, validators[0].ABCIValidator(), updates[0])
require.Equal(t, validators[1].ABCIValidator(), updates[1])
}
func TestGetValidTendermintUpdatesNewValidator(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
params := keeper.GetParams(ctx)
params.MaxValidators = uint16(3)
keeper.SetParams(ctx, params)
amts := []int64{100, 100}
var validators [2]types.Validator
// initialize some validators into the state
for i, amt := range amts {
pool := keeper.GetPool(ctx)
valPubKey := PKs[i+1]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
keeper.SetPool(ctx, pool)
validators[i] = keeper.UpdateValidator(ctx, validators[i])
}
// verify initial Tendermint updates are correct
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, len(validators), len(updates))
require.Equal(t, validators[0].ABCIValidator(), updates[0])
require.Equal(t, validators[1].ABCIValidator(), updates[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// update initial validator set
for i, amt := range amts {
pool := keeper.GetPool(ctx)
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
keeper.SetPool(ctx, pool)
validators[i] = keeper.UpdateValidator(ctx, validators[i])
}
// add a new validator that goes from zero power, to non-zero power, back to
// zero power
pool := keeper.GetPool(ctx)
valPubKey := PKs[len(validators)+1]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
amt := sdk.NewInt(100)
validator := types.NewValidator(valAddr, valPubKey, types.Description{})
validator, pool, _ = validator.AddTokensFromDel(pool, amt)
keeper.SetPool(ctx, pool)
validator = keeper.UpdateValidator(ctx, validator)
validator, pool, _ = validator.RemoveDelShares(pool, sdk.NewDecFromInt(amt))
validator = keeper.UpdateValidator(ctx, validator)
// add a new validator that increases in power
valPubKey = PKs[len(validators)+2]
valAddr = sdk.ValAddress(valPubKey.Address().Bytes())
validator = types.NewValidator(valAddr, valPubKey, types.Description{})
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(500))
keeper.SetPool(ctx, pool)
validator = keeper.UpdateValidator(ctx, validator)
// verify initial Tendermint updates are correct
updates = keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, len(validators)+1, len(updates))
require.Equal(t, validator.ABCIValidator(), updates[0])
require.Equal(t, validators[0].ABCIValidator(), updates[1])
require.Equal(t, validators[1].ABCIValidator(), updates[2])
}
func TestGetValidTendermintUpdatesBondTransition(t *testing.T) {
ctx, _, keeper := CreateTestInput(t, false, 1000)
params := keeper.GetParams(ctx)
params.MaxValidators = uint16(2)
keeper.SetParams(ctx, params)
amts := []int64{100, 200, 300}
var validators [3]types.Validator
// initialize some validators into the state
for i, amt := range amts {
pool := keeper.GetPool(ctx)
moniker := fmt.Sprintf("%d", i)
valPubKey := PKs[i+1]
valAddr := sdk.ValAddress(valPubKey.Address().Bytes())
validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{Moniker: moniker})
validators[i], pool, _ = validators[i].AddTokensFromDel(pool, sdk.NewInt(amt))
keeper.SetPool(ctx, pool)
validators[i] = keeper.UpdateValidator(ctx, validators[i])
}
// verify initial Tendermint updates are correct
updates := keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 2, len(updates))
require.Equal(t, validators[2].ABCIValidator(), updates[0])
require.Equal(t, validators[1].ABCIValidator(), updates[1])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// delegate to validator with lowest power but not enough to bond
ctx = ctx.WithBlockHeight(1)
pool := keeper.GetPool(ctx)
validator, found := keeper.GetValidator(ctx, validators[0].OperatorAddr)
require.True(t, found)
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(1))
keeper.SetPool(ctx, pool)
validators[0] = keeper.UpdateValidator(ctx, validator)
// verify initial Tendermint updates are correct
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
// create a series of events that will bond and unbond the validator with
// lowest power in a single block context (height)
ctx = ctx.WithBlockHeight(2)
pool = keeper.GetPool(ctx)
validator, found = keeper.GetValidator(ctx, validators[1].OperatorAddr)
require.True(t, found)
validator, pool, _ = validator.RemoveDelShares(pool, validator.DelegatorShares)
keeper.SetPool(ctx, pool)
validator = keeper.UpdateValidator(ctx, validator)
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(250))
keeper.SetPool(ctx, pool)
validators[1] = keeper.UpdateValidator(ctx, validator)
// verify initial Tendermint updates are correct
updates = keeper.GetValidTendermintUpdates(ctx)
require.Equal(t, 1, len(updates))
require.Equal(t, validators[1].ABCIValidator(), updates[0])
keeper.ClearTendermintUpdates(ctx)
require.Equal(t, 0, len(keeper.GetValidTendermintUpdates(ctx)))
}