Merge PR #2238: Ensure Tendermint Validator Update Invariants
This commit is contained in:
parent
55b7c6adf1
commit
854aca2f7d
|
@ -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)
|
||||
|
|
|
@ -12,7 +12,7 @@ the changes cleared
|
|||
|
||||
```golang
|
||||
EndBlock() ValidatorSetChanges
|
||||
vsc = GetTendermintUpdates()
|
||||
vsc = GetValidTendermintUpdates()
|
||||
ClearTendermintUpdates()
|
||||
return vsc
|
||||
```
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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)))
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue