diff --git a/x/staking/keeper/old_slash_test.go b/x/staking/keeper/old_slash_test.go index f6b442dc3c..66023db24d 100644 --- a/x/staking/keeper/old_slash_test.go +++ b/x/staking/keeper/old_slash_test.go @@ -39,49 +39,6 @@ func setupHelper(t *testing.T, power int64) (sdk.Context, Keeper, types.Params) //_________________________________________________________________________________ -// tests slashUnbondingDelegation -func TestSlashUnbondingDelegation(t *testing.T) { - ctx, keeper, _ := setupHelper(t, 10) - fraction := sdk.NewDecWithPrec(5, 1) - - // set an unbonding delegation with expiration timestamp (beyond which the - // unbonding delegation shouldn't be slashed) - ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, - time.Unix(5, 0), sdk.NewInt(10)) - - keeper.SetUnbondingDelegation(ctx, ubd) - - // unbonding started prior to the infraction height, stakw didn't contribute - slashAmount := keeper.slashUnbondingDelegation(ctx, ubd, 1, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // after the expiration time, no longer eligible for slashing - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) - keeper.SetUnbondingDelegation(ctx, ubd) - slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(0), slashAmount.Int64()) - - // test valid slash, before expiration timestamp and to which stake contributed - notBondedPool := keeper.GetNotBondedPool(ctx) - oldUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) - keeper.SetUnbondingDelegation(ctx, ubd) - slashAmount = keeper.slashUnbondingDelegation(ctx, ubd, 0, fraction) - require.Equal(t, int64(5), slashAmount.Int64()) - ubd, found := keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) - require.True(t, found) - require.Len(t, ubd.Entries, 1) - - // initial balance unchanged - require.Equal(t, sdk.NewInt(10), ubd.Entries[0].InitialBalance) - - // balance decreased - require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) - newUnbondedPoolBalances := keeper.bankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) - diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) - require.Equal(t, int64(5), diffTokens.AmountOf(keeper.BondDenom(ctx)).Int64()) -} - // tests slashRedelegation func TestSlashRedelegation(t *testing.T) { ctx, keeper, _ := setupHelper(t, 10) diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index 76db0c8e99..7f1bf5bba6 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -82,7 +82,7 @@ func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeigh // Iterate through unbonding delegations from slashed validator unbondingDelegations := k.GetUnbondingDelegationsFromValidator(ctx, operatorAddress) for _, unbondingDelegation := range unbondingDelegations { - amountSlashed := k.slashUnbondingDelegation(ctx, unbondingDelegation, infractionHeight, slashFactor) + amountSlashed := k.SlashUnbondingDelegation(ctx, unbondingDelegation, infractionHeight, slashFactor) if amountSlashed.IsZero() { continue } @@ -160,7 +160,7 @@ func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) { // the unbonding delegation had enough stake to slash // (the amount actually slashed may be less if there's // insufficient stake remaining) -func (k Keeper) slashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, +func (k Keeper) SlashUnbondingDelegation(ctx sdk.Context, unbondingDelegation types.UnbondingDelegation, infractionHeight int64, slashFactor sdk.Dec) (totalSlashAmount sdk.Int) { now := ctx.BlockHeader().Time diff --git a/x/staking/keeper/slash_test.go b/x/staking/keeper/slash_test.go index 3f88942a5c..37c5c4ee2b 100644 --- a/x/staking/keeper/slash_test.go +++ b/x/staking/keeper/slash_test.go @@ -2,6 +2,9 @@ package keeper_test import ( "testing" + "time" + + abci "github.com/tendermint/tendermint/abci/types" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,21 +14,22 @@ import ( ) // initConfig creates 3 validators and bootstrap the app. -func initConfig(t *testing.T) (*simapp.SimApp, sdk.Context, []sdk.ValAddress) { +func initConfig(t *testing.T, power int64) (*simapp.SimApp, sdk.Context, []sdk.AccAddress, []sdk.ValAddress) { _, app, ctx := getBaseSimappWithCustomKeeper() - addrDels := simapp.AddTestAddrsIncremental(app, ctx, 3, sdk.NewInt(10000)) + addrDels := simapp.AddTestAddrsIncremental(app, ctx, 100, sdk.NewInt(10000)) addrVals := simapp.ConvertAddrsToValAddrs(addrDels) - numVals := int64(3) - amt := sdk.TokensFromConsensusPower(10) - bondedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(numVals))) + amt := sdk.TokensFromConsensusPower(power) + totalSupply := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(int64(len(addrDels))))) notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) - err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), bondedCoins) + err := app.BankKeeper.SetBalances(ctx, notBondedPool.GetAddress(), totalSupply) require.NoError(t, err) app.SupplyKeeper.SetModuleAccount(ctx, notBondedPool) + numVals := int64(3) + bondedCoins := sdk.NewCoins(sdk.NewCoin(app.StakingKeeper.BondDenom(ctx), amt.MulRaw(numVals))) bondedPool := app.StakingKeeper.GetBondedPool(ctx) err = app.BankKeeper.SetBalances(ctx, bondedPool.GetAddress(), bondedCoins) require.NoError(t, err) @@ -38,12 +42,12 @@ func initConfig(t *testing.T) (*simapp.SimApp, sdk.Context, []sdk.ValAddress) { app.StakingKeeper.SetValidatorByConsAddr(ctx, validator) } - return app, ctx, addrVals + return app, ctx, addrDels, addrVals } // tests Jail, Unjail func TestRevocation(t *testing.T) { - app, ctx, addrVals := initConfig(t) + app, ctx, _, addrVals := initConfig(t, 5) consAddr := sdk.ConsAddress(PKs[0].Address()) @@ -64,3 +68,47 @@ func TestRevocation(t *testing.T) { require.True(t, found) require.False(t, val.IsJailed()) } + +// tests slashUnbondingDelegation +func TestSlashUnbondingDelegation(t *testing.T) { + app, ctx, addrDels, addrVals := initConfig(t, 10) + + fraction := sdk.NewDecWithPrec(5, 1) + + // set an unbonding delegation with expiration timestamp (beyond which the + // unbonding delegation shouldn't be slashed) + ubd := types.NewUnbondingDelegation(addrDels[0], addrVals[0], 0, + time.Unix(5, 0), sdk.NewInt(10)) + + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + + // unbonding started prior to the infraction height, stakw didn't contribute + slashAmount := app.StakingKeeper.SlashUnbondingDelegation(ctx, ubd, 1, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // after the expiration time, no longer eligible for slashing + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(10, 0)}) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = app.StakingKeeper.SlashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(0), slashAmount.Int64()) + + // test valid slash, before expiration timestamp and to which stake contributed + notBondedPool := app.StakingKeeper.GetNotBondedPool(ctx) + oldUnbondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + ctx = ctx.WithBlockHeader(abci.Header{Time: time.Unix(0, 0)}) + app.StakingKeeper.SetUnbondingDelegation(ctx, ubd) + slashAmount = app.StakingKeeper.SlashUnbondingDelegation(ctx, ubd, 0, fraction) + require.Equal(t, int64(5), slashAmount.Int64()) + ubd, found := app.StakingKeeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0]) + require.True(t, found) + require.Len(t, ubd.Entries, 1) + + // initial balance unchanged + require.Equal(t, sdk.NewInt(10), ubd.Entries[0].InitialBalance) + + // balance decreased + require.Equal(t, sdk.NewInt(5), ubd.Entries[0].Balance) + newUnbondedPoolBalances := app.BankKeeper.GetAllBalances(ctx, notBondedPool.GetAddress()) + diffTokens := oldUnbondedPoolBalances.Sub(newUnbondedPoolBalances) + require.Equal(t, int64(5), diffTokens.AmountOf(app.StakingKeeper.BondDenom(ctx)).Int64()) +}