Skip to content

Commit

Permalink
add unbonded check to oracle slashing
Browse files Browse the repository at this point in the history
  • Loading branch information
Yun committed Apr 25, 2020
1 parent a5262c3 commit 7a3d01c
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 10 deletions.
6 changes: 6 additions & 0 deletions x/oracle/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,12 @@ func (k Keeper) SetMissCounter(ctx sdk.Context, operator sdk.ValAddress, missCou
store.Set(types.GetMissCounterKey(operator), bz)
}

// DeleteMissCounter removes miss counter for the validator
func (k Keeper) DeleteMissCounter(ctx sdk.Context, operator sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.GetMissCounterKey(operator))
}

// IterateMissCounters iterates over the miss counters and performs a callback function.
func (k Keeper) IterateMissCounters(ctx sdk.Context,
handler func(operator sdk.ValAddress, missCounter int64) (stop bool)) {
Expand Down
4 changes: 4 additions & 0 deletions x/oracle/internal/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ func TestMissCounter(t *testing.T) {
input.OracleKeeper.SetMissCounter(input.Ctx, ValAddrs[0], missCounter)
counter = input.OracleKeeper.GetMissCounter(input.Ctx, ValAddrs[0])
require.Equal(t, missCounter, counter)

input.OracleKeeper.DeleteMissCounter(input.Ctx, ValAddrs[0])
counter = input.OracleKeeper.GetMissCounter(input.Ctx, ValAddrs[0])
require.Equal(t, int64(0), counter)
}

func TestIterateMissCounters(t *testing.T) {
Expand Down
31 changes: 28 additions & 3 deletions x/oracle/slash_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,46 @@ import (
func TestSlashAndResetMissCounters(t *testing.T) {
input, _ := setup(t)

votePeriodsPerWindow := sdk.NewDec(input.OracleKeeper.SlashWindow(input.Ctx)).QuoInt64(input.OracleKeeper.VotePeriod(input.Ctx)).TruncateInt64()
votePeriodsPerWindow := input.OracleKeeper.SlashWindow(input.Ctx)
slashFraction := input.OracleKeeper.SlashFraction(input.Ctx)
minValidVotes := input.OracleKeeper.MinValidPerWindow(input.Ctx).MulInt64(votePeriodsPerWindow).TruncateInt64()
// Case 1, no slash
input.OracleKeeper.SetMissCounter(input.Ctx, keeper.ValAddrs[0], votePeriodsPerWindow-minValidVotes)
SlashAndResetMissCounters(input.Ctx, input.OracleKeeper)
staking.EndBlocker(input.Ctx, input.StakingKeeper)

validator := input.StakingKeeper.Validator(input.Ctx, keeper.ValAddrs[0])
validator, _ := input.StakingKeeper.GetValidator(input.Ctx, keeper.ValAddrs[0])
require.Equal(t, stakingAmt, validator.GetBondedTokens())

// Case 2, slash
input.OracleKeeper.SetMissCounter(input.Ctx, keeper.ValAddrs[0], votePeriodsPerWindow-minValidVotes+1)
SlashAndResetMissCounters(input.Ctx, input.OracleKeeper)
validator = input.StakingKeeper.Validator(input.Ctx, keeper.ValAddrs[0])
validator, _ = input.StakingKeeper.GetValidator(input.Ctx, keeper.ValAddrs[0])
require.Equal(t, stakingAmt.Sub(slashFraction.MulInt(stakingAmt).TruncateInt()), validator.GetBondedTokens())
require.True(t, validator.IsJailed())

// Case 3, slash unbonded validator
validator, _ = input.StakingKeeper.GetValidator(input.Ctx, keeper.ValAddrs[0])
validator.Status = sdk.Unbonded
validator.Jailed = false
validator.Tokens = stakingAmt
input.StakingKeeper.SetValidator(input.Ctx, validator)

input.OracleKeeper.SetMissCounter(input.Ctx, keeper.ValAddrs[0], votePeriodsPerWindow-minValidVotes+1)
SlashAndResetMissCounters(input.Ctx, input.OracleKeeper)
validator, _ = input.StakingKeeper.GetValidator(input.Ctx, keeper.ValAddrs[0])
require.Equal(t, stakingAmt, validator.Tokens)
require.False(t, validator.IsJailed())

// Case 4, slash jailed validator
validator, _ = input.StakingKeeper.GetValidator(input.Ctx, keeper.ValAddrs[0])
validator.Status = sdk.Bonded
validator.Jailed = true
validator.Tokens = stakingAmt
input.StakingKeeper.SetValidator(input.Ctx, validator)

input.OracleKeeper.SetMissCounter(input.Ctx, keeper.ValAddrs[0], votePeriodsPerWindow-minValidVotes+1)
SlashAndResetMissCounters(input.Ctx, input.OracleKeeper)
validator, _ = input.StakingKeeper.GetValidator(input.Ctx, keeper.ValAddrs[0])
require.Equal(t, stakingAmt, validator.Tokens)
}
16 changes: 9 additions & 7 deletions x/oracle/slashing.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ func SlashAndResetMissCounters(ctx sdk.Context, k Keeper) {
height := ctx.BlockHeight()
distributionHeight := height - sdk.ValidatorUpdateDelay - 1

votePeriodsPerWindow := sdk.NewDec(k.SlashWindow(ctx)).QuoInt64(k.VotePeriod(ctx)).TruncateInt64()
votePeriodsPerWindow := k.SlashWindow(ctx)
minValidPerWindow := k.MinValidPerWindow(ctx)
slashFraction := k.SlashFraction(ctx)
k.IterateMissCounters(ctx, func(operator sdk.ValAddress, missCounter int64) bool {
Expand All @@ -22,14 +22,16 @@ func SlashAndResetMissCounters(ctx sdk.Context, k Keeper) {
// Penalize the validator whoes the valid vote rate is smaller than min threshold
if validVoteRate.LT(minValidPerWindow) {
validator := k.StakingKeeper.Validator(ctx, operator)
k.StakingKeeper.Slash(
ctx, validator.GetConsAddr(),
distributionHeight, validator.GetConsensusPower(), slashFraction,
)
k.StakingKeeper.Jail(ctx, validator.GetConsAddr())
if validator.IsBonded() && !validator.IsJailed() {
k.StakingKeeper.Slash(
ctx, validator.GetConsAddr(),
distributionHeight, validator.GetConsensusPower(), slashFraction,
)
k.StakingKeeper.Jail(ctx, validator.GetConsAddr())
}
}

k.SetMissCounter(ctx, operator, 0)
k.DeleteMissCounter(ctx, operator)
return false
})
}

0 comments on commit 7a3d01c

Please sign in to comment.