Skip to content

Commit

Permalink
move slashing to other file and check tombstoning
Browse files Browse the repository at this point in the history
  • Loading branch information
insumity committed Sep 8, 2023
1 parent b681112 commit 584fec2
Show file tree
Hide file tree
Showing 7 changed files with 93 additions and 62 deletions.
3 changes: 2 additions & 1 deletion tests/integration/double_vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,8 @@ func (s *CCVTestSuite) TestHandleConsumerDoubleVoting() {
if tc.expPass {
s.Require().NoError(err)

// verifies that the jailing has occurred
// verifies that the tombstoning and jailing has occurred
s.Require().True(s.providerApp.GetTestSlashingKeeper().IsTombstoned(provCtx, provAddr.ToSdkConsAddr()))
s.Require().True(s.providerApp.GetTestStakingKeeper().IsValidatorJailed(provCtx, provAddr.ToSdkConsAddr()))
} else {
s.Require().Error(err)
Expand Down
1 change: 1 addition & 0 deletions tests/integration/misbehaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ func (s *CCVTestSuite) TestHandleConsumerMisbehaviour() {
val, ok := s.providerApp.GetTestStakingKeeper().GetValidatorByConsAddr(s.providerCtx(), provAddr.Address)
s.Require().True(ok)
s.Require().True(val.Jailed)
s.Require().True(s.providerApp.GetTestSlashingKeeper().IsTombstoned(s.providerCtx(), provAddr.ToSdkConsAddr()))
}
}

Expand Down
41 changes: 27 additions & 14 deletions testutil/keeper/mocks.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 1 addition & 38 deletions x/ccv/provider/keeper/double_vote.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@ package keeper
import (
"bytes"
"fmt"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -14,41 +12,6 @@ import (
tmtypes "github.com/tendermint/tendermint/types"
)

func (k Keeper) slashValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) {
val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr())

if !found {
//logger.Error("validator not found or is unbonded", providerAddr.String())
return
}
valOperatorAddress := val.GetOperator()

undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, valOperatorAddress) {
for _, entry := range v.Entries {
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, valOperatorAddress) {
for _, entry := range v.Entries {
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

powerReduction := k.stakingKeeper.PowerReduction(ctx)
undelegationsAndRedelegationsInPower := sdk.TokensToConsensusPower(
undelegationsInTokens.Add(redelegationsInTokens), powerReduction)

power := k.stakingKeeper.GetLastValidatorPower(ctx, valOperatorAddress)
totalPower := power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

// TODO: what if it's another key ????
k.stakingKeeper.Slash(ctx, providerAddr.ToSdkConsAddr(), 0, totalPower, slashFraction, stakingtypes.DoubleSign)
}

// HandleConsumerDoubleVoting verifies a double voting evidence for a given a consumer chain ID
// and a public key and, if successful, executes the jailing of the malicious validator.
func (k Keeper) HandleConsumerDoubleVoting(
Expand All @@ -70,7 +33,7 @@ func (k Keeper) HandleConsumerDoubleVoting(
)

// execute the jailing
k.slashValidator(ctx, providerAddr)
k.SlashValidator(ctx, providerAddr)
k.JailAndTombstoneValidator(ctx, providerAddr)

k.Logger(ctx).Info(
Expand Down
2 changes: 1 addition & 1 deletion x/ccv/provider/keeper/misbehaviour.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ 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.SlashValidator(ctx, providerAddr)
k.JailAndTombstoneValidator(ctx, providerAddr)
provAddrs = append(provAddrs, providerAddr)
}
Expand Down
67 changes: 59 additions & 8 deletions x/ccv/provider/keeper/punish_validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,24 @@ package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
evidencetypes "github.com/cosmos/cosmos-sdk/x/evidence/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
"github.com/cosmos/interchain-security/v2/x/ccv/provider/types"
)

// JailAndTombstoneValidator jails the validator with the given provider consensus address
// Note that the tombstoning is temporarily removed until we slash validator
// for double signing on a consumer chain, see comment
// https://github.com/cosmos/interchain-security/pull/1232#issuecomment-1693127641.
// 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", providerAddr.String())
logger.Error("validator not found or is unbonded", "provider consensus address", providerAddr.String())
return
}

// check that the validator isn't tombstoned
if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) {
logger.Info("validator is already tombstoned", "provider cons addr", providerAddr.String())
logger.Info("validator is already tombstoned", "provider consensus address", providerAddr.String())
return
}

Expand All @@ -31,9 +29,62 @@ func (k Keeper) JailAndTombstoneValidator(ctx sdk.Context, providerAddr types.Pr
k.stakingKeeper.Jail(ctx, providerAddr.ToSdkConsAddr())
}

// update jail time to end after double sign jail duration
// Jail the validator to trigger the unbonding of the validator
// (see cosmos/cosmos-sdk/blob/v0.47.0/x/staking/keeper/val_state_change.go#L194).
k.slashingKeeper.JailUntil(ctx, providerAddr.ToSdkConsAddr(), evidencetypes.DoubleSignJailEndTime)

// TODO: do we need to jail if we tombstone, that's what cosmos-sdk does
// Tombstone the validator so that we cannot slash the validator more than once
// (see cosmos/cosmos-sdk/blob/v0.47.0/x/evidence/keeper/infraction.go#L94).
// 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 calling `SlashValidator`.
k.slashingKeeper.Tombstone(ctx, providerAddr.ToSdkConsAddr())

//k.evidenceKeeper.SetEvidence(ctx)
}

// Slash validator based on the `providerAddr`
func (k Keeper) SlashValidator(ctx sdk.Context, providerAddr types.ProviderConsAddress) {
logger := k.Logger(ctx)

val, found := k.stakingKeeper.GetValidatorByConsAddr(ctx, providerAddr.ToSdkConsAddr())
if !found {
logger.Error("validator not found", "provider consensus address", providerAddr.String())
return
}

if k.slashingKeeper.IsTombstoned(ctx, providerAddr.ToSdkConsAddr()) {
logger.Info("validator is already tombstoned", "provider consensus address", providerAddr.String())
return
}

valOperatorAddress := val.GetOperator()

// compute the total numbers of tokens currently being undelegated
undelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetUnbondingDelegationsFromValidator(ctx, valOperatorAddress) {
for _, entry := range v.Entries {
undelegationsInTokens = undelegationsInTokens.Add(entry.InitialBalance)
}
}

// compute the total numbers of tokens currently being redelegated
redelegationsInTokens := sdk.NewInt(0)
for _, v := range k.stakingKeeper.GetRedelegationsFromSrcValidator(ctx, valOperatorAddress) {
for _, entry := range v.Entries {
redelegationsInTokens = redelegationsInTokens.Add(entry.InitialBalance)
}
}

// The power we pass to staking's keeper `Slash` method is the current power of the validator together with the total
// power of all the currently undelegated and redelegated tokens (see docs/docs/adrs/adr-013-equivocation-slashing.md).
powerReduction := k.stakingKeeper.PowerReduction(ctx)
undelegationsAndRedelegationsInPower := sdk.TokensToConsensusPower(
undelegationsInTokens.Add(redelegationsInTokens), powerReduction)

power := k.stakingKeeper.GetLastValidatorPower(ctx, valOperatorAddress)
totalPower := power + undelegationsAndRedelegationsInPower
slashFraction := k.slashingKeeper.SlashFractionDoubleSign(ctx)

k.stakingKeeper.Slash(ctx, providerAddr.ToSdkConsAddr(), 0, totalPower, slashFraction, stakingtypes.DoubleSign)
}
2 changes: 2 additions & 0 deletions x/ccv/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
context "context"
"github.com/cosmos/cosmos-sdk/x/evidence/exported"
"time"

sdk "github.com/cosmos/cosmos-sdk/types"
Expand Down Expand Up @@ -50,6 +51,7 @@ type StakingKeeper interface {

type EvidenceKeeper interface {
HandleEquivocationEvidence(ctx sdk.Context, evidence *evidencetypes.Equivocation)
SetEvidence(ctx sdk.Context, evidence exported.Evidence)
}

// SlashingKeeper defines the contract expected to perform ccv slashing
Expand Down

0 comments on commit 584fec2

Please sign in to comment.