diff --git a/x/ccv/provider/keeper/double_vote.go b/x/ccv/provider/keeper/double_vote.go index 1cf7e0fc56..d3813f8da4 100644 --- a/x/ccv/provider/keeper/double_vote.go +++ b/x/ccv/provider/keeper/double_vote.go @@ -32,8 +32,12 @@ func (k Keeper) HandleConsumerDoubleVoting( types.NewConsumerConsAddress(sdk.ConsAddress(evidence.VoteA.ValidatorAddress.Bytes())), ) - k.SlashValidator(ctx, providerAddr) - k.JailAndTombstoneValidator(ctx, providerAddr) + if err := k.SlashValidator(ctx, providerAddr); err != nil { + return err + } + if err := k.JailAndTombstoneValidator(ctx, providerAddr); err != nil { + return err + } k.Logger(ctx).Info( "confirmed equivocation", diff --git a/x/ccv/provider/keeper/misbehaviour.go b/x/ccv/provider/keeper/misbehaviour.go index 980562be44..e35e04db1d 100644 --- a/x/ccv/provider/keeper/misbehaviour.go +++ b/x/ccv/provider/keeper/misbehaviour.go @@ -1,6 +1,7 @@ package keeper import ( + "fmt" "github.com/cosmos/interchain-security/v2/x/ccv/provider/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -34,6 +35,7 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty provAddrs := make([]types.ProviderConsAddress, len(byzantineValidators)) + var errors []error // slash, jail, and tombstone the Byzantine validators for _, v := range byzantineValidators { providerAddr := k.GetProviderAddrFromConsumerAddr( @@ -41,8 +43,14 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty misbehaviour.Header1.Header.ChainID, types.NewConsumerConsAddress(sdk.ConsAddress(v.Address.Bytes())), ) - k.SlashValidator(ctx, providerAddr) - k.JailAndTombstoneValidator(ctx, providerAddr) + err := k.SlashValidator(ctx, providerAddr) + if err != nil { + errors = append(errors, err) + } + err = k.JailAndTombstoneValidator(ctx, providerAddr) + if err != nil { + errors = append(errors, err) + } provAddrs = append(provAddrs, providerAddr) } @@ -51,6 +59,9 @@ func (k Keeper) HandleConsumerMisbehaviour(ctx sdk.Context, misbehaviour ibctmty "byzantine validators", provAddrs, ) + if len(errors) > 0 { + return fmt.Errorf("failed to slash, jail, or tombstone validators: %v", errors) + } return nil } diff --git a/x/ccv/provider/keeper/punish_validator.go b/x/ccv/provider/keeper/punish_validator.go index 3fc67afecb..06a7a30da2 100644 --- a/x/ccv/provider/keeper/punish_validator.go +++ b/x/ccv/provider/keeper/punish_validator.go @@ -1,32 +1,32 @@ package keeper import ( + errorsmod "cosmossdk.io/errors" + "fmt" sdk "github.com/cosmos/cosmos-sdk/types" evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types" - + slashingtypes "github.com/cosmos/cosmos-sdk/x/slashing/types" stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types" "github.com/cosmos/interchain-security/v2/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) { - logger := k.Logger(ctx) - - // get validator - val, ok := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr()) - if !ok || val.IsUnbonded() { - logger.Error("validator not found or is unbonded", "provider consensus address", providerAddr.String()) - return +func (k Keeper) JailAndTombstoneValidator(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()) + } + + if validator.IsUnbonded() { + return fmt.Errorf("validator is unbonded. provider consensus address: %s", providerAddr.String()) } - // check that the validator isn't tombstoned if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) { - logger.Info("validator is already tombstoned", "provider consensus address", providerAddr.String()) - return + return fmt.Errorf("validator is tombstoned. provider consensus address: %s", providerAddr.String()) } // jail validator if not already - if !val.IsJailed() { + if !validator.IsJailed() { k.stakingKeeper.Jail(ctx, providerAddr.ToSdkConsAddr()) } @@ -40,6 +40,8 @@ func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.Pr // 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()) + + return nil } // ComputePowerToSlash computes the power to be slashed based on the tokens in non-matured `undelegations` and @@ -72,23 +74,18 @@ func (k Keeper) ComputePowerToSlash(ctx sdk.Context, validator stakingtypes.Vali } // SlashValidator slashes validator with `providerAddr` -func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) { - logger := k.Logger(ctx) - +func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) error { validator, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr()) if !found { - logger.Error("validator not found", "provider consensus address", providerAddr.String()) - return + return errorsmod.Wrapf(slashingtypes.ErrNoValidatorForAddress, "provider consensus address: %s", providerAddr.String()) } if validator.IsUnbonded() { - logger.Info("validator is unbonded", "provider consensus address", providerAddr.String()) - return + return fmt.Errorf("validator is unbonded. provider consensus address: %s", providerAddr.String()) } if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) { - logger.Info("validator is already tombstoned", "provider consensus address", providerAddr.String()) - return + return fmt.Errorf("validator is tombstoned. provider consensus address: %s", providerAddr.String()) } undelegations := k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, validator.GetOperator()) @@ -99,4 +96,5 @@ func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsA slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx) k.stakingKeeper.Slash(ctx, providerAddr.ToSdkConsAddr(), 0, totalPower, slashFraction, stakingtypes.DoubleSign) + return nil }