diff --git a/x/staking/keeper/old_validator_test.go b/x/staking/keeper/old_validator_test.go deleted file mode 100644 index fa0884733..000000000 --- a/x/staking/keeper/old_validator_test.go +++ /dev/null @@ -1,472 +0,0 @@ -package keeper - -import ( - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - abci "github.com/tendermint/tendermint/abci/types" - - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/x/staking/types" -) - -func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - } - - // test from nothing to something - // tendermintUpdate set: {} -> {c1, c3} - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidatorByPowerIndex(ctx, validators[1]) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - assert.Equal(t, 2, len(updates)) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test identical, - // tendermintUpdate set: {} -> {} - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) -} - -func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test single value change - // tendermintUpdate set: {} -> {c1'} - validators[0].Status = sdk.Bonded - validators[0].Tokens = sdk.TokensFromConsensusPower(600) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test multiple value change - // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(190) - delTokens2 := sdk.TokensFromConsensusPower(80) - validators[0], _ = validators[0].AddTokensFromDel(delTokens1) - validators[1], _ = validators[1].AddTokensFromDel(delTokens2) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) -} - -func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{10, 20, 5, 15, 25} - var validators [5]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test validtor added at the beginning - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[2]) - keeper.SetValidatorByPowerIndex(ctx, validators[2]) - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - - // test validtor added at the beginning - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[3]) - keeper.SetValidatorByPowerIndex(ctx, validators[3]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[3], _ = keeper.GetValidator(ctx, validators[3].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) - - // test validtor added at the end - // tendermintUpdate set: {} -> {c0} - keeper.SetValidator(ctx, validators[4]) - keeper.SetValidatorByPowerIndex(ctx, validators[4]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[4], _ = keeper.GetValidator(ctx, validators[4].OperatorAddress) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := types.DefaultParams() - params.MaxValidators = 2 - keeper.SetParams(ctx, params) - - powers := []int64{10, 20, 5} - var validators [5]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // test validator added at the end but not inserted in the valset - // tendermintUpdate set: {} -> {} - TestingUpdateValidator(keeper, ctx, validators[2], false) - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 0, len(updates)) - - // test validator change its power and become a gotValidator (pushing out an existing) - // tendermintUpdate set: {} -> {c0, c4} - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - tokens := sdk.TokensFromConsensusPower(10) - validators[2], _ = validators[2].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[2]) - keeper.SetValidatorByPowerIndex(ctx, validators[2]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - require.Equal(t, 2, len(updates), "%v", updates) - require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) -} - -func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - - powers := []int64{100, 100} - var validators [2]types.Validator - for i, power := range powers { - - validators[i] = types.NewValidator(sdk.ValAddress(Addrs[i]), PKs[i], types.Description{}) - - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - } - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - require.Equal(t, 2, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // check initial power - require.Equal(t, int64(100), validators[0].GetConsensusPower()) - require.Equal(t, int64(100), validators[1].GetConsensusPower()) - - // test multiple value change - // tendermintUpdate set: {c1, c3} -> {c1', c3'} - delTokens1 := sdk.TokensFromConsensusPower(20) - delTokens2 := sdk.TokensFromConsensusPower(30) - validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) - validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) - validators[0] = TestingUpdateValidator(keeper, ctx, validators[0], false) - validators[1] = TestingUpdateValidator(keeper, ctx, validators[1], false) - - // power has changed - require.Equal(t, int64(80), validators[0].GetConsensusPower()) - require.Equal(t, int64(70), validators[1].GetConsensusPower()) - - // Tendermint updates should reflect power change - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) -} - -func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(3) - - keeper.SetParams(ctx, params) - - powers := []int64{100, 100} - var validators [2]types.Validator - - // initialize some validators into the state - for i, power := range powers { - - valPubKey := PKs[i+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - - validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // verify initial Tendermint updates are correct - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, len(validators), len(updates)) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // update initial validator set - for i, power := range powers { - - keeper.DeleteValidatorByPowerIndex(ctx, validators[i]) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // add a new validator that goes from zero power, to non-zero power, back to - // zero power - valPubKey := PKs[len(validators)+1] - valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) - amt := sdk.NewInt(100) - - validator := types.NewValidator(valAddr, valPubKey, types.Description{}) - validator, _ = validator.AddTokensFromDel(amt) - - keeper.SetValidator(ctx, validator) - - validator, _ = validator.RemoveDelShares(amt.ToDec()) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(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{}) - tokens := sdk.TokensFromConsensusPower(500) - validator, _ = validator.AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validator) - keeper.SetValidatorByPowerIndex(ctx, validator) - - // verify initial Tendermint updates are correct - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - validator, _ = keeper.GetValidator(ctx, validator.OperatorAddress) - validators[0], _ = keeper.GetValidator(ctx, validators[0].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, len(validators)+1, len(updates)) - require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) -} - -func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - params := keeper.GetParams(ctx) - params.MaxValidators = uint32(2) - - keeper.SetParams(ctx, params) - - powers := []int64{100, 200, 300} - var validators [3]types.Validator - - // initialize some validators into the state - for i, power := range powers { - 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}) - tokens := sdk.TokensFromConsensusPower(power) - validators[i], _ = validators[i].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[i]) - keeper.SetValidatorByPowerIndex(ctx, validators[i]) - } - - // verify initial Tendermint updates are correct - updates := keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 2, len(updates)) - validators[2], _ = keeper.GetValidator(ctx, validators[2].OperatorAddress) - validators[1], _ = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) - - // delegate to validator with lowest power but not enough to bond - ctx = ctx.WithBlockHeight(1) - - var found bool - validators[0], found = keeper.GetValidator(ctx, validators[0].OperatorAddress) - require.True(t, found) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - tokens := sdk.TokensFromConsensusPower(1) - validators[0], _ = validators[0].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - - // verify initial Tendermint updates are correct - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(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) - - validators[1], found = keeper.GetValidator(ctx, validators[1].OperatorAddress) - require.True(t, found) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[0]) - validators[0], _ = validators[0].RemoveDelShares(validators[0].DelegatorShares) - keeper.SetValidator(ctx, validators[0]) - keeper.SetValidatorByPowerIndex(ctx, validators[0]) - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 0, len(updates)) - - keeper.DeleteValidatorByPowerIndex(ctx, validators[1]) - tokens = sdk.TokensFromConsensusPower(250) - validators[1], _ = validators[1].AddTokensFromDel(tokens) - keeper.SetValidator(ctx, validators[1]) - keeper.SetValidatorByPowerIndex(ctx, validators[1]) - - // verify initial Tendermint updates are correct - updates = keeper.ApplyAndReturnValidatorSetUpdates(ctx) - require.Equal(t, 1, len(updates)) - require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) - - require.Equal(t, 0, len(keeper.ApplyAndReturnValidatorSetUpdates(ctx))) -} - -func TestUpdateValidatorCommission(t *testing.T) { - ctx, _, _, keeper, _ := CreateTestInput(t, false, 1000) - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) - - commission1 := types.NewCommissionWithTime( - sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), - sdk.NewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour), - ) - commission2 := types.NewCommission(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), sdk.NewDecWithPrec(1, 1)) - - val1 := types.NewValidator(addrVals[0], PKs[0], types.Description{}) - val2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) - - val1, _ = val1.SetInitialCommission(commission1) - val2, _ = val2.SetInitialCommission(commission2) - - keeper.SetValidator(ctx, val1) - keeper.SetValidator(ctx, val2) - - testCases := []struct { - validator types.Validator - newRate sdk.Dec - expectedErr bool - }{ - {val1, sdk.ZeroDec(), true}, - {val2, sdk.NewDecWithPrec(-1, 1), true}, - {val2, sdk.NewDecWithPrec(4, 1), true}, - {val2, sdk.NewDecWithPrec(3, 1), true}, - {val2, sdk.NewDecWithPrec(2, 1), false}, - } - - for i, tc := range testCases { - commission, err := keeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) - - if tc.expectedErr { - require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) - } else { - tc.validator.Commission = commission - keeper.SetValidator(ctx, tc.validator) - val, found := keeper.GetValidator(ctx, tc.validator.OperatorAddress) - - require.True(t, found, - "expected to find validator for test case #%d with rate: %s", i, tc.newRate, - ) - require.NoError(t, err, - "unexpected error for test case #%d with rate: %s", i, tc.newRate, - ) - require.Equal(t, tc.newRate, val.Commission.Rate, - "expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate, - ) - require.Equal(t, ctx.BlockHeader().Time, val.Commission.UpdateTime, - "expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate, - ) - } - } -} diff --git a/x/staking/keeper/validator_test.go b/x/staking/keeper/validator_test.go index 2d87b5497..6f2be5472 100644 --- a/x/staking/keeper/validator_test.go +++ b/x/staking/keeper/validator_test.go @@ -3,18 +3,18 @@ package keeper_test import ( "fmt" "testing" - - "github.com/cosmos/cosmos-sdk/x/supply" - - "github.com/cosmos/cosmos-sdk/x/staking/keeper" - - "github.com/cosmos/cosmos-sdk/simapp" + "time" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + abci "github.com/tendermint/tendermint/abci/types" + + "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/staking/keeper" "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/cosmos/cosmos-sdk/x/supply" ) func bootstrapValidatorTest(t *testing.T, power int64, numAddrs int) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { @@ -657,3 +657,460 @@ func TestFullValidatorSetPowerChange(t *testing.T) { assert.True(ValEq(t, validators[0], resValidators[0])) assert.True(ValEq(t, validators[2], resValidators[1])) } + +func TestApplyAndReturnValidatorSetUpdatesAllNone(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + } + + // test from nothing to something + // tendermintUpdate set: {} -> {c1, c3} + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) + app.StakingKeeper.SetValidator(ctx, validators[1]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[1]) + + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + assert.Equal(t, 2, len(updates)) + validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + assert.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + assert.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesIdentical(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test identical, + // tendermintUpdate set: {} -> {} + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) +} + +func TestApplyAndReturnValidatorSetUpdatesSingleValueChange(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test single value change + // tendermintUpdate set: {} -> {c1'} + validators[0].Status = sdk.Bonded + validators[0].Tokens = sdk.TokensFromConsensusPower(600) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesMultipleValueChange(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + delTokens1 := sdk.TokensFromConsensusPower(190) + delTokens2 := sdk.TokensFromConsensusPower(80) + validators[0], _ = validators[0].AddTokensFromDel(delTokens1) + validators[1], _ = validators[1].AddTokensFromDel(delTokens2) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) +} + +func TestApplyAndReturnValidatorSetUpdatesInserted(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{10, 20, 5, 15, 25} + var validators [5]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test validtor added at the beginning + // tendermintUpdate set: {} -> {c0} + app.StakingKeeper.SetValidator(ctx, validators[2]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[2]) + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + + // test validtor added at the beginning + // tendermintUpdate set: {} -> {c0} + app.StakingKeeper.SetValidator(ctx, validators[3]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[3]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[3], _ = app.StakingKeeper.GetValidator(ctx, validators[3].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[3].ABCIValidatorUpdate(), updates[0]) + + // test validtor added at the end + // tendermintUpdate set: {} -> {c0} + app.StakingKeeper.SetValidator(ctx, validators[4]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[4]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[4], _ = app.StakingKeeper.GetValidator(ctx, validators[4].OperatorAddress) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[4].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesWithCliffValidator(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + params := types.DefaultParams() + params.MaxValidators = 2 + app.StakingKeeper.SetParams(ctx, params) + + powers := []int64{10, 20, 5} + var validators [5]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // test validator added at the end but not inserted in the valset + // tendermintUpdate set: {} -> {} + keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[2], false) + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 0, len(updates)) + + // test validator change its power and become a gotValidator (pushing out an existing) + // tendermintUpdate set: {} -> {c0, c4} + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + tokens := sdk.TokensFromConsensusPower(10) + validators[2], _ = validators[2].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[2]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[2]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].OperatorAddress) + require.Equal(t, 2, len(updates), "%v", updates) + require.Equal(t, validators[0].ABCIValidatorUpdateZero(), updates[1]) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) +} + +func TestApplyAndReturnValidatorSetUpdatesPowerDecrease(t *testing.T) { + app, ctx, addrs, _ := bootstrapValidatorTest(t, 1000, 20) + + powers := []int64{100, 100} + var validators [2]types.Validator + for i, power := range powers { + + validators[i] = types.NewValidator(sdk.ValAddress(addrs[i]), PKs[i], types.Description{}) + + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + } + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + require.Equal(t, 2, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // check initial power + require.Equal(t, int64(100), validators[0].GetConsensusPower()) + require.Equal(t, int64(100), validators[1].GetConsensusPower()) + + // test multiple value change + // tendermintUpdate set: {c1, c3} -> {c1', c3'} + delTokens1 := sdk.TokensFromConsensusPower(20) + delTokens2 := sdk.TokensFromConsensusPower(30) + validators[0], _ = validators[0].RemoveDelShares(delTokens1.ToDec()) + validators[1], _ = validators[1].RemoveDelShares(delTokens2.ToDec()) + validators[0] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[0], false) + validators[1] = keeper.TestingUpdateValidator(app.StakingKeeper, ctx, validators[1], false) + + // power has changed + require.Equal(t, int64(80), validators[0].GetConsensusPower()) + require.Equal(t, int64(70), validators[1].GetConsensusPower()) + + // Tendermint updates should reflect power change + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) +} + +func TestApplyAndReturnValidatorSetUpdatesNewValidator(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 1000, 20) + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = uint32(3) + + app.StakingKeeper.SetParams(ctx, params) + + powers := []int64{100, 100} + var validators [2]types.Validator + + // initialize some validators into the state + for i, power := range powers { + + valPubKey := PKs[i+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + + validators[i] = types.NewValidator(valAddr, valPubKey, types.Description{}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // verify initial Tendermint updates are correct + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, len(validators), len(updates)) + validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // update initial validator set + for i, power := range powers { + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[i]) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // add a new validator that goes from zero power, to non-zero power, back to + // zero power + valPubKey := PKs[len(validators)+1] + valAddr := sdk.ValAddress(valPubKey.Address().Bytes()) + amt := sdk.NewInt(100) + + validator := types.NewValidator(valAddr, valPubKey, types.Description{}) + validator, _ = validator.AddTokensFromDel(amt) + + app.StakingKeeper.SetValidator(ctx, validator) + + validator, _ = validator.RemoveDelShares(amt.ToDec()) + app.StakingKeeper.SetValidator(ctx, validator) + app.StakingKeeper.SetValidatorByPowerIndex(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{}) + tokens := sdk.TokensFromConsensusPower(500) + validator, _ = validator.AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validator) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validator) + + // verify initial Tendermint updates are correct + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + validator, _ = app.StakingKeeper.GetValidator(ctx, validator.OperatorAddress) + validators[0], _ = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, len(validators)+1, len(updates)) + require.Equal(t, validator.ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[0].ABCIValidatorUpdate(), updates[1]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[2]) +} + +func TestApplyAndReturnValidatorSetUpdatesBondTransition(t *testing.T) { + app, ctx, _, _ := bootstrapValidatorTest(t, 1000, 20) + params := app.StakingKeeper.GetParams(ctx) + params.MaxValidators = uint32(2) + + app.StakingKeeper.SetParams(ctx, params) + + powers := []int64{100, 200, 300} + var validators [3]types.Validator + + // initialize some validators into the state + for i, power := range powers { + 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}) + tokens := sdk.TokensFromConsensusPower(power) + validators[i], _ = validators[i].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[i]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[i]) + } + + // verify initial Tendermint updates are correct + updates := app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 2, len(updates)) + validators[2], _ = app.StakingKeeper.GetValidator(ctx, validators[2].OperatorAddress) + validators[1], _ = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.Equal(t, validators[2].ABCIValidatorUpdate(), updates[0]) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[1]) + + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) + + // delegate to validator with lowest power but not enough to bond + ctx = ctx.WithBlockHeight(1) + + var found bool + validators[0], found = app.StakingKeeper.GetValidator(ctx, validators[0].OperatorAddress) + require.True(t, found) + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + tokens := sdk.TokensFromConsensusPower(1) + validators[0], _ = validators[0].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) + + // verify initial Tendermint updates are correct + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(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) + + validators[1], found = app.StakingKeeper.GetValidator(ctx, validators[1].OperatorAddress) + require.True(t, found) + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[0]) + validators[0], _ = validators[0].RemoveDelShares(validators[0].DelegatorShares) + app.StakingKeeper.SetValidator(ctx, validators[0]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[0]) + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 0, len(updates)) + + app.StakingKeeper.DeleteValidatorByPowerIndex(ctx, validators[1]) + tokens = sdk.TokensFromConsensusPower(250) + validators[1], _ = validators[1].AddTokensFromDel(tokens) + app.StakingKeeper.SetValidator(ctx, validators[1]) + app.StakingKeeper.SetValidatorByPowerIndex(ctx, validators[1]) + + // verify initial Tendermint updates are correct + updates = app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx) + require.Equal(t, 1, len(updates)) + require.Equal(t, validators[1].ABCIValidatorUpdate(), updates[0]) + + require.Equal(t, 0, len(app.StakingKeeper.ApplyAndReturnValidatorSetUpdates(ctx))) +} + +func TestUpdateValidatorCommission(t *testing.T) { + app, ctx, _, addrVals := bootstrapValidatorTest(t, 1000, 20) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Now().UTC()}) + + commission1 := types.NewCommissionWithTime( + sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), + sdk.NewDecWithPrec(1, 1), time.Now().UTC().Add(time.Duration(-1)*time.Hour), + ) + commission2 := types.NewCommission(sdk.NewDecWithPrec(1, 1), sdk.NewDecWithPrec(3, 1), sdk.NewDecWithPrec(1, 1)) + + val1 := types.NewValidator(addrVals[0], PKs[0], types.Description{}) + val2 := types.NewValidator(addrVals[1], PKs[1], types.Description{}) + + val1, _ = val1.SetInitialCommission(commission1) + val2, _ = val2.SetInitialCommission(commission2) + + app.StakingKeeper.SetValidator(ctx, val1) + app.StakingKeeper.SetValidator(ctx, val2) + + testCases := []struct { + validator types.Validator + newRate sdk.Dec + expectedErr bool + }{ + {val1, sdk.ZeroDec(), true}, + {val2, sdk.NewDecWithPrec(-1, 1), true}, + {val2, sdk.NewDecWithPrec(4, 1), true}, + {val2, sdk.NewDecWithPrec(3, 1), true}, + {val2, sdk.NewDecWithPrec(2, 1), false}, + } + + for i, tc := range testCases { + commission, err := app.StakingKeeper.UpdateValidatorCommission(ctx, tc.validator, tc.newRate) + + if tc.expectedErr { + require.Error(t, err, "expected error for test case #%d with rate: %s", i, tc.newRate) + } else { + tc.validator.Commission = commission + app.StakingKeeper.SetValidator(ctx, tc.validator) + val, found := app.StakingKeeper.GetValidator(ctx, tc.validator.OperatorAddress) + + require.True(t, found, + "expected to find validator for test case #%d with rate: %s", i, tc.newRate, + ) + require.NoError(t, err, + "unexpected error for test case #%d with rate: %s", i, tc.newRate, + ) + require.Equal(t, tc.newRate, val.Commission.Rate, + "expected new validator commission rate for test case #%d with rate: %s", i, tc.newRate, + ) + require.Equal(t, ctx.BlockHeader().Time, val.Commission.UpdateTime, + "expected new validator commission update time for test case #%d with rate: %s", i, tc.newRate, + ) + } + } +}