Skip to content

Commit

Permalink
add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
sainoe committed Oct 13, 2023
1 parent 9f23165 commit 7092914
Show file tree
Hide file tree
Showing 5 changed files with 212 additions and 163 deletions.
63 changes: 63 additions & 0 deletions testutil/keeper/expectations.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
time "time"

math "cosmossdk.io/math"
clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
conntypes "github.com/cosmos/ibc-go/v7/modules/core/03-connection/types"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
Expand Down Expand Up @@ -156,3 +157,65 @@ func GetMocksForSendIBCPacket(ctx sdk.Context, mocks MockedKeepers, channelID st
).Return(uint64(888), nil).Times(times),
}
}

func GetMocksForSlashValidator(
ctx sdk.Context,
mocks MockedKeepers,
validator stakingtypes.Validator,
consAddr sdk.ConsAddress,
undelegations []stakingtypes.UnbondingDelegation,
redelegations []stakingtypes.Redelegation,
powerReduction math.Int,
slashFraction math.LegacyDec,
currentPower,
expectedInfractionHeight,
expectedSlashPower int64,
) []*gomock.Call {
return []*gomock.Call{
mocks.MockStakingKeeper.EXPECT().
GetUnbondingDelegationsFromValidator(ctx, validator.GetOperator()).
Return(undelegations),
mocks.MockStakingKeeper.EXPECT().
GetRedelegationsFromSrcValidator(ctx, validator.GetOperator()).
Return(redelegations),
mocks.MockStakingKeeper.EXPECT().
GetLastValidatorPower(ctx, validator.GetOperator()).
Return(currentPower),
mocks.MockStakingKeeper.EXPECT().
PowerReduction(ctx).
Return(powerReduction),
mocks.MockStakingKeeper.EXPECT().
SlashUnbondingDelegation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
DoAndReturn(
func(_ sdk.Context, undelegation stakingtypes.UnbondingDelegation, _ int64, _ sdk.Dec) math.Int {
sum := sdk.NewInt(0)
for _, r := range undelegation.Entries {
if r.IsMature(ctx.BlockTime()) {
continue
}
sum = sum.Add(sdk.NewInt(r.InitialBalance.Int64()))
}
return sum
}).AnyTimes(),
mocks.MockStakingKeeper.EXPECT().
SlashRedelegation(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).
DoAndReturn(
func(_ sdk.Context, _ stakingtypes.Validator, redelegation stakingtypes.Redelegation, _ int64, _ sdk.Dec) math.Int {
sum := sdk.NewInt(0)
for _, r := range redelegation.Entries {
if r.IsMature(ctx.BlockTime()) {
continue
}
sum = sum.Add(sdk.NewInt(r.InitialBalance.Int64()))
}
return sum
}).AnyTimes(),
mocks.MockSlashingKeeper.EXPECT().
SlashFractionDoubleSign(ctx).
Return(slashFraction),
mocks.MockStakingKeeper.EXPECT().
SlashWithInfractionReason(ctx, consAddr, expectedInfractionHeight, expectedSlashPower, slashFraction, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN).
Times(1),
}

}
5 changes: 1 addition & 4 deletions x/ccv/provider/keeper/double_vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,7 @@ func (k Keeper) HandleConsumerDoubleVoting(
types.NewConsumerConsAddress(sdk.ConsAddress(evidence.VoteA.ValidatorAddress.Bytes())),
)

if err := k.SlashValidator(ctx, providerAddr); err != nil {
return err
}
if err := k.JailAndTombstoneValidator(ctx, providerAddr); err != nil {
if err := k.PunishValidator(ctx, providerAddr); err != nil {
return err
}

Expand Down
7 changes: 2 additions & 5 deletions x/ccv/provider/keeper/misbehaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,11 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty
misbehaviour.Header1.Header.ChainID,
types.NewConsumerConsAddress(sdk.ConsAddress(v.Address.Bytes())),
)
err := k.SlashValidator(ctx, providerAddr)
if err != nil {
errors = append(errors, err)
}
err = k.JailAndTombstoneValidator(ctx, providerAddr)
err := k.PunishValidator(ctx, providerAddr)
if err != nil {
errors = append(errors, err)
}

provAddrs = append(provAddrs, providerAddr)
}

Expand Down
67 changes: 33 additions & 34 deletions x/ccv/provider/keeper/punish_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import (
"github.com/cosmos/interchain-security/v3/x/ccv/provider/types"
)

// JailAndTombstoneValidator jails and tombstones the validator with the given provider consensus address
func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) error {
func (k Keeper) PunishValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) error {
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr())
if !found {
return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String())
Expand All @@ -29,20 +28,48 @@ func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.Pr
return fmt.Errorf("validator is tombstoned. provider consensus address: %s", providerAddr.String())
}

k.SlashValidator(ctx, validator)
k.JailAndTombstoneValidator(ctx, validator)

return nil
}

// JailAndTombstoneValidator jails and tombstones the validator with the given provider consensus address
func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, validator stakingtypes.Validator) {
consAdrr, err := validator.GetConsAddr()
if err != nil {
panic(err)
}

// jail validator if not already
if !validator.IsJailed() {
k.stakingKeeper.Jail(ctx, providerAddr.ToSdkConsAddr())
k.stakingKeeper.Jail(ctx, consAdrr)
}

k.slashingKeeper.JailUntil(ctx, providerAddr.ToSdkConsAddr(), evidencetypes.DoubleSignJailEndTime)
k.slashingKeeper.JailUntil(ctx, consAdrr, evidencetypes.DoubleSignJailEndTime)

// Tombstone the validator so that we cannot slash the validator more than once
// Note that we cannot simply use the fact that a validator is jailed to avoid slashing more than once
// because then a validator could i) perform an equivocation, ii) get jailed (e.g., through downtime)
// and in such a case the validator would not get slashed when we call `SlashValidator`.
k.slashingKeeper.Tombstone(ctx, providerAddr.ToSdkConsAddr())
k.slashingKeeper.Tombstone(ctx, consAdrr)
}

return nil
// SlashValidator slashes the given validator
func (k Keeper) SlashValidator(ctx sdk.Context, validator stakingtypes.Validator) {
undelegations := k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validator.GetOperator())
redelegations := k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validator.GetOperator())
lastPower := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator())
powerReduction := k.stakingKeeper.PowerReduction(ctx)
totalPower := k.ComputePowerToSlash(ctx, validator, undelegations, redelegations, lastPower, powerReduction)
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

consAdrr, err := validator.GetConsAddr()
if err != nil {
panic(err)
}

k.stakingKeeper.SlashWithInfractionReason(ctx, consAdrr, 0, totalPower, slashFraction, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN)
}

// ComputePowerToSlash computes the power to be slashed based on the tokens in non-matured `undelegations` and
Expand Down Expand Up @@ -75,31 +102,3 @@ func (k Keeper) ComputePowerToSlash(ctx sdk.Context, validator stakingtypes.Vali

return power + undelegationsAndRedelegationsInPower
}

// SlashValidator slashes validator with `providerAddr`
func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) error {
validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr())
if !found {
return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String())
}

// check if the validator is unbonded to prevent panicking when slashing (see cosmos/cosmos-sdk/blob/v0.47.5/x/staking/keeper/slash.go#L61)
if validator.IsUnbonded() {
return fmt.Errorf("validator is unbonded. provider consensus address: %s", providerAddr.String())
}

// check if the validator is already tombstoned to avoid slashing a validator more than once
if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) {
return fmt.Errorf("validator is tombstoned. provider consensus address: %s", providerAddr.String())
}

undelegations := k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validator.GetOperator())
redelegations := k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, validator.GetOperator())
lastPower := k.stakingKeeper.GetLastValidatorPower(ctx, validator.GetOperator())
powerReduction := k.stakingKeeper.PowerReduction(ctx)
totalPower := k.ComputePowerToSlash(ctx, validator, undelegations, redelegations, lastPower, powerReduction)
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.SlashWithInfractionReason(ctx, providerAddr.ToSdkConsAddr(), 0, totalPower, slashFraction, stakingtypes.Infraction_INFRACTION_DOUBLE_SIGN)
return nil
}
Loading

0 comments on commit 7092914

Please sign in to comment.