Implement ValidatorSet.Slash

This commit is contained in:
Christopher Goes 2018-05-25 01:03:26 +02:00
parent 366d8f9323
commit 7da5833b81
No known key found for this signature in database
GPG Key ID: E828D98232D328D3
4 changed files with 39 additions and 5 deletions

View File

@ -72,7 +72,6 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, height int64, timestamp int64,
}
logger.Info(fmt.Sprintf("Confirmed double sign from %v at height %d, age of %d less than max age of %d", pubkey.Address(), height, age, MaxEvidenceAge))
k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDoubleSign)
logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v for double-sign at height %d", pubkey.Address(), SlashFractionDoubleSign, height))
}
// handle a validator signature, must be called once per validator per block
@ -99,8 +98,6 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey,
if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow {
k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime)
k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration)
logger.Info(fmt.Sprintf("Slashed validator %s by fraction %v and unbonded for downtime at height %d, cannot rebond for %ds",
address, SlashFractionDowntime, height, DowntimeUnbondDuration))
}
}

View File

@ -2,6 +2,7 @@ package slashing
import (
"encoding/hex"
"os"
"testing"
"github.com/stretchr/testify/require"
@ -52,7 +53,7 @@ func createTestInput(t *testing.T) (sdk.Context, bank.Keeper, stake.Keeper, Keep
ms.MountStoreWithDB(keySlashing, sdk.StoreTypeIAVL, db)
err := ms.LoadLatestVersion()
require.Nil(t, err)
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewNopLogger(), nil)
ctx := sdk.NewContext(ms, abci.Header{}, false, nil, log.NewTMLogger(os.Stdout), nil)
cdc := createTestCodec()
accountMapper := auth.NewAccountMapper(cdc, keyAcc, &auth.BaseAccount{})
ck := bank.NewKeeper(accountMapper)
@ -74,8 +75,9 @@ func TestHandleDoubleSign(t *testing.T) {
require.True(t, got.IsOK())
_ = sk.Tick(ctx)
require.Equal(t, ck.GetCoins(ctx, addr), sdk.Coins{{sk.GetParams(ctx).BondDenom, initCoins - amt}})
require.Equal(t, sdk.NewRat(amt), sk.Validator(ctx, addr).GetPower())
keeper.handleDoubleSign(ctx, 0, 0, val)
// TODO
require.Equal(t, sdk.NewRat(amt).Mul(sdk.NewRat(19).Quo(sdk.NewRat(20))), sk.Validator(ctx, addr).GetPower())
}
func TestHandleAbsentValidator(t *testing.T) {

View File

@ -779,8 +779,28 @@ func (k Keeper) IterateDelegators(ctx sdk.Context, delAddr sdk.Address, fn func(
// slash a validator
func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fraction sdk.Rat) {
// TODO height ignored for now, see https://github.com/cosmos/cosmos-sdk/pull/1011#issuecomment-390253957
val, found := k.GetValidatorByPubKey(ctx, pubkey)
if !found {
panic(fmt.Errorf("Attempted to slash a nonexistent validator with pubkey %s", pubkey))
}
sharesToRemove := val.PoolShares.Amount.Mul(fraction)
pool := k.GetPool(ctx)
val, pool, burned := val.removePoolShares(pool, sharesToRemove)
k.setPool(ctx, pool) // update the pool
k.updateValidator(ctx, val) // update the validator, possibly kicking it out
ctx.Logger().With("module", "x/stake").Info(fmt.Sprintf("Validator %v slashed by fraction %v, removed %v shares and burned %d tokens", pubkey, fraction, sharesToRemove, burned))
return
}
// force unbond a validator
func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration int64) {
// TODO Implement
/*
val, found := k.GetValidatorByPubKey(ctx, pubkey)
if !found {
ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey)
return
}
*/
}

View File

@ -153,6 +153,21 @@ func (v Validator) UpdateStatus(pool Pool, NewStatus sdk.BondStatus) (Validator,
return v, pool
}
// Remove & burn pool shares, e.g. when slashing a validator
func (v Validator) removePoolShares(pool Pool, amt sdk.Rat) (Validator, Pool, int64) {
var tokens int64
switch v.Status() {
case sdk.Unbonded:
pool, tokens = pool.removeSharesUnbonded(amt)
case sdk.Unbonding:
pool, tokens = pool.removeSharesUnbonding(amt)
case sdk.Bonded:
pool, tokens = pool.removeSharesBonded(amt)
}
v.PoolShares.Amount = v.PoolShares.Amount.Sub(amt)
return v, pool, tokens
}
// XXX TEST
// get the power or potential power for a validator
// if bonded, the power is the BondedShares