pulling in stuff from fee-distr PR

This commit is contained in:
rigelrozanski 2018-09-20 20:30:18 -04:00
parent 8721dd6ff8
commit 4e4749da9d
23 changed files with 341 additions and 185 deletions

View File

@ -34,9 +34,9 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
return ErrValidatorNotJailed(k.codespace).Result()
}
addr := sdk.ConsAddress(validator.GetPubKey().Address())
consAddr := sdk.ConsAddress(validator.GetPubKey().Address())
info, found := k.getValidatorSigningInfo(ctx, addr)
info, found := k.getValidatorSigningInfo(ctx, consAddr)
if !found {
return ErrNoValidatorForAddress(k.codespace).Result()
}
@ -49,9 +49,9 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
// update the starting height so the validator can't be immediately jailed
// again
info.StartHeight = ctx.BlockHeight()
k.setValidatorSigningInfo(ctx, addr, info)
k.setValidatorSigningInfo(ctx, consAddr, info)
k.validatorSet.Unjail(ctx, validator.GetPubKey())
k.validatorSet.Unjail(ctx, consAddr)
tags := sdk.NewTags("action", []byte("unjail"), "validator", []byte(msg.ValidatorAddr.String()))

View File

@ -22,25 +22,34 @@ func (k Keeper) onValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddre
k.addOrUpdateValidatorSlashingPeriod(ctx, slashingPeriod)
}
// Wrapper struct for sdk.ValidatorHooks
type ValidatorHooks struct {
//_________________________________________________________________________________________
// Wrapper struct
type Hooks struct {
k Keeper
}
// Assert implementation
var _ sdk.ValidatorHooks = ValidatorHooks{}
var _ sdk.StakingHooks = Hooks{}
// Return a sdk.ValidatorHooks interface over the wrapper struct
func (k Keeper) ValidatorHooks() sdk.ValidatorHooks {
return ValidatorHooks{k}
// Return the wrapper struct
func (k Keeper) Hooks() Hooks {
return Hooks{k}
}
// Implements sdk.ValidatorHooks
func (v ValidatorHooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
v.k.onValidatorBonded(ctx, address)
func (h Hooks) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
h.k.onValidatorBonded(ctx, address)
}
// Implements sdk.ValidatorHooks
func (v ValidatorHooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) {
v.k.onValidatorBeginUnbonding(ctx, address)
func (h Hooks) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) {
h.k.onValidatorBeginUnbonding(ctx, address)
}
// nolint - unused hooks
func (h Hooks) OnValidatorCreated(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnValidatorCommissionChange(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnValidatorRemoved(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) OnDelegationRemoved(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}

View File

@ -40,10 +40,10 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
logger := ctx.Logger().With("module", "x/slashing")
time := ctx.BlockHeader().Time
age := time.Sub(timestamp)
address := sdk.ConsAddress(addr)
consAddr := sdk.ConsAddress(addr)
pubkey, err := k.getPubkey(ctx, addr)
if err != nil {
panic(fmt.Sprintf("Validator address %v not found", addr))
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))
}
// Double sign too old
@ -59,37 +59,38 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
// Cap the amount slashed to the penalty for the worst infraction
// within the slashing period when this infraction was committed
fraction := k.SlashFractionDoubleSign(ctx)
revisedFraction := k.capBySlashingPeriod(ctx, address, fraction, infractionHeight)
revisedFraction := k.capBySlashingPeriod(ctx, consAddr, fraction, infractionHeight)
logger.Info(fmt.Sprintf("Fraction slashed capped by slashing period from %v to %v", fraction, revisedFraction))
// Slash validator
k.validatorSet.Slash(ctx, pubkey, infractionHeight, power, revisedFraction)
k.validatorSet.Slash(ctx, consAddr, infractionHeight, power, revisedFraction)
// Jail validator
k.validatorSet.Jail(ctx, pubkey)
k.validatorSet.Jail(ctx, consAddr)
// Set validator jail duration
signInfo, found := k.getValidatorSigningInfo(ctx, address)
signInfo, found := k.getValidatorSigningInfo(ctx, consAddr)
if !found {
panic(fmt.Sprintf("Expected signing info for validator %s but not found", address))
panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr))
}
signInfo.JailedUntil = time.Add(k.DoubleSignUnbondDuration(ctx))
k.setValidatorSigningInfo(ctx, address, signInfo)
k.setValidatorSigningInfo(ctx, consAddr, signInfo)
}
// handle a validator signature, must be called once per validator per block
// TODO refactor to take in a consensus address, additionally should maybe just take in the pubkey too
// nolint gocyclo
func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, power int64, signed bool) {
logger := ctx.Logger().With("module", "x/slashing")
height := ctx.BlockHeight()
address := sdk.ConsAddress(addr)
consAddr := sdk.ConsAddress(addr)
pubkey, err := k.getPubkey(ctx, addr)
if err != nil {
panic(fmt.Sprintf("Validator address %v not found", addr))
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))
}
// Local index, so counts blocks validator *should* have signed
// Will use the 0-value default signing info if not present, except for start height
signInfo, found := k.getValidatorSigningInfo(ctx, address)
signInfo, found := k.getValidatorSigningInfo(ctx, consAddr)
if !found {
// If this validator has never been seen before, construct a new SigningInfo with the correct start height
signInfo = NewValidatorSigningInfo(height, 0, time.Unix(0, 0), 0)
@ -100,16 +101,16 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
// Update signed block bit array & counter
// This counter just tracks the sum of the bit array
// That way we avoid needing to read/write the whole array each time
previous := k.getValidatorSigningBitArray(ctx, address, index)
previous := k.getValidatorSigningBitArray(ctx, consAddr, index)
if previous == signed {
// Array value at this index has not changed, no need to update counter
} else if previous && !signed {
// Array value has changed from signed to unsigned, decrement counter
k.setValidatorSigningBitArray(ctx, address, index, false)
k.setValidatorSigningBitArray(ctx, consAddr, index, false)
signInfo.SignedBlocksCounter--
} else if !previous && signed {
// Array value has changed from unsigned to signed, increment counter
k.setValidatorSigningBitArray(ctx, address, index, true)
k.setValidatorSigningBitArray(ctx, consAddr, index, true)
signInfo.SignedBlocksCounter++
}
@ -118,13 +119,13 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
}
minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
if height > minHeight && signInfo.SignedBlocksCounter < k.MinSignedPerWindow(ctx) {
validator := k.validatorSet.ValidatorByPubKey(ctx, pubkey)
validator := k.validatorSet.ValidatorByConsAddr(ctx, consAddr)
if validator != nil && !validator.GetJailed() {
// Downtime confirmed: slash and jail the validator
logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d",
pubkey.Address(), minHeight, k.MinSignedPerWindow(ctx)))
k.validatorSet.Slash(ctx, pubkey, height, power, k.SlashFractionDowntime(ctx))
k.validatorSet.Jail(ctx, pubkey)
k.validatorSet.Slash(ctx, consAddr, height, power, k.SlashFractionDowntime(ctx))
k.validatorSet.Jail(ctx, consAddr)
signInfo.JailedUntil = ctx.BlockHeader().Time.Add(k.DowntimeUnbondDuration(ctx))
} else {
// Validator was (a) not found or (b) already jailed, don't slash
@ -134,7 +135,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
}
// Set the updated signing info
k.setValidatorSigningInfo(ctx, address, signInfo)
k.setValidatorSigningInfo(ctx, consAddr, signInfo)
}
// AddValidators adds the validators to the keepers validator addr to pubkey mapping.

View File

@ -18,13 +18,16 @@ func init() {
defaultDoubleSignUnbondDuration = 60 * 60
}
// ______________________________________________________________
// Test that a validator is slashed correctly
// when we discover evidence of infraction
// TODO fix this test to not be using the same pubkey/address for signing and operating, it's confusing
func TestHandleDoubleSign(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
@ -43,7 +46,7 @@ func TestHandleDoubleSign(t *testing.T) {
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// unjail to measure power
sk.Unjail(ctx, val)
sk.Unjail(ctx, sdk.ConsAddress(addr)) // TODO distinguish cons address
// power should be reduced
require.Equal(
t, sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20))),
@ -61,14 +64,16 @@ func TestHandleDoubleSign(t *testing.T) {
// Test that the amount a validator is slashed for multiple double signs
// is correctly capped by the slashing period in which they were committed
// TODO properly distinguish between consensus and operator address is variable names
func TestSlashingPeriodCap(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, val, amt))
addr, amt := addrs[0], sdk.NewInt(amtInt)
valConsPubKey, valConsAddr := pks[0], sdk.ConsAddress(pks[0].Address())
got := stake.NewHandler(sk)(ctx, newTestMsgCreateValidator(addr, valConsPubKey, amt))
require.True(t, got.IsOK())
validatorUpdates := stake.EndBlocker(ctx, sk)
keeper.AddValidators(ctx, validatorUpdates)
@ -76,39 +81,39 @@ func TestSlashingPeriodCap(t *testing.T) {
require.True(t, sdk.NewDecFromInt(amt).Equal(sk.Validator(ctx, addr).GetPower()))
// handle a signature to set signing info
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, true)
keeper.handleValidatorSignature(ctx, valConsPubKey.Address(), amtInt, true)
// double sign less than max age
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt)
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// update block height
ctx = ctx.WithBlockHeight(int64(1))
// unjail to measure power
sk.Unjail(ctx, val)
sk.Unjail(ctx, valConsAddr)
// power should be reduced
expectedPower := sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20)))
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
// double sign again, same slashing period
keeper.handleDoubleSign(ctx, val.Address(), 0, time.Unix(0, 0), amtInt)
keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 0, time.Unix(0, 0), amtInt)
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// update block height
ctx = ctx.WithBlockHeight(int64(2))
// unjail to measure power
sk.Unjail(ctx, val)
sk.Unjail(ctx, valConsAddr)
// power should be equal, no more should have been slashed
expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(19).Quo(sdk.NewDec(20)))
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
// double sign again, new slashing period
keeper.handleDoubleSign(ctx, val.Address(), 2, time.Unix(0, 0), amtInt)
keeper.handleDoubleSign(ctx, valConsPubKey.Address(), 2, time.Unix(0, 0), amtInt)
// should be jailed
require.True(t, sk.Validator(ctx, addr).GetJailed())
// unjail to measure power
sk.Unjail(ctx, val)
sk.Unjail(ctx, valConsAddr)
// power should be reduced
expectedPower = sdk.NewDecFromInt(amt).Mul(sdk.NewDec(18).Quo(sdk.NewDec(20)))
require.Equal(t, expectedPower, sk.Validator(ctx, addr).GetPower())
@ -120,7 +125,7 @@ func TestHandleAbsentValidator(t *testing.T) {
// initial setup
ctx, ck, sk, _, keeper := createTestInput(t)
sk = sk.WithValidatorHooks(keeper.ValidatorHooks())
sk = sk.WithHooks(keeper.Hooks())
amtInt := int64(100)
addr, val, amt := addrs[0], pks[0], sdk.NewInt(amtInt)
sh := stake.NewHandler(sk)
@ -162,7 +167,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx), info.SignedBlocksCounter)
// validator should be bonded still
validator, _ := sk.GetValidatorByPubKey(ctx, val)
validator, _ := sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Bonded, validator.GetStatus())
pool := sk.GetPool(ctx)
require.Equal(t, amtInt, pool.BondedTokens.RoundInt64())
@ -176,7 +181,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.Equal(t, keeper.SignedBlocksWindow(ctx)-keeper.MinSignedPerWindow(ctx)-1, info.SignedBlocksCounter)
// validator should have been jailed
validator, _ = sk.GetValidatorByPubKey(ctx, val)
validator, _ = sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Unbonding, validator.GetStatus())
// unrevocation should fail prior to jail expiration
@ -189,7 +194,7 @@ func TestHandleAbsentValidator(t *testing.T) {
require.True(t, got.IsOK())
// validator should be rebonded now
validator, _ = sk.GetValidatorByPubKey(ctx, val)
validator, _ = sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Bonded, validator.GetStatus())
// validator should have been slashed
@ -207,7 +212,7 @@ func TestHandleAbsentValidator(t *testing.T) {
height++
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
validator, _ = sk.GetValidatorByPubKey(ctx, val)
validator, _ = sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Bonded, validator.GetStatus())
// 500 signed blocks
@ -223,7 +228,7 @@ func TestHandleAbsentValidator(t *testing.T) {
ctx = ctx.WithBlockHeight(height)
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
}
validator, _ = sk.GetValidatorByPubKey(ctx, val)
validator, _ = sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Unbonding, validator.GetStatus())
}
@ -258,7 +263,7 @@ func TestHandleNewValidator(t *testing.T) {
require.Equal(t, time.Unix(0, 0).UTC(), info.JailedUntil)
// validator should be bonded still, should not have been jailed or slashed
validator, _ := sk.GetValidatorByPubKey(ctx, val)
validator, _ := sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Bonded, validator.GetStatus())
pool := sk.GetPool(ctx)
require.Equal(t, int64(100), pool.BondedTokens.RoundInt64())
@ -292,7 +297,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
}
// validator should have been jailed and slashed
validator, _ := sk.GetValidatorByPubKey(ctx, val)
validator, _ := sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, sdk.Unbonding, validator.GetStatus())
// validator should have been slashed
@ -303,7 +308,7 @@ func TestHandleAlreadyJailed(t *testing.T) {
keeper.handleValidatorSignature(ctx, val.Address(), amtInt, false)
// validator should not have been slashed twice
validator, _ = sk.GetValidatorByPubKey(ctx, val)
validator, _ = sk.GetValidatorByConsPubKey(ctx, val)
require.Equal(t, amtInt-1, validator.GetTokens().RoundInt64())
}

View File

@ -78,7 +78,7 @@ func TestBeginBlocker(t *testing.T) {
}
// validator should be jailed
validator, found := sk.GetValidatorByPubKey(ctx, pk)
validator, found := sk.GetValidatorByConsPubKey(ctx, pk)
require.True(t, found)
require.Equal(t, sdk.Unbonding, validator.GetStatus())
}

View File

@ -48,8 +48,8 @@ func init() {
fsDescriptionEdit.String(FlagIdentity, types.DoNotModifyDesc, "optional identity signature (ex. UPort or Keybase)")
fsDescriptionEdit.String(FlagWebsite, types.DoNotModifyDesc, "optional website")
fsDescriptionEdit.String(FlagDetails, types.DoNotModifyDesc, "optional details")
fsValidator.String(FlagAddressValidator, "", "hex address of the validator")
fsDelegator.String(FlagAddressDelegator, "", "hex address of the delegator")
fsRedelegation.String(FlagAddressValidatorSrc, "", "hex address of the source validator")
fsRedelegation.String(FlagAddressValidatorDst, "", "hex address of the destination validator")
fsValidator.String(FlagAddressValidator, "", "bech address of the validator")
fsDelegator.String(FlagAddressDelegator, "", "bech address of the delegator")
fsRedelegation.String(FlagAddressValidatorSrc, "", "bech address of the source validator")
fsRedelegation.String(FlagAddressValidatorDst, "", "bech address of the destination validator")
}

View File

@ -32,7 +32,7 @@ func InitGenesis(ctx sdk.Context, keeper Keeper, data types.GenesisState) (res [
}
// Manually set indexes for the first time
keeper.SetValidatorByPubKeyIndex(ctx, validator)
keeper.SetValidatorByConsAddr(ctx, validator)
keeper.SetValidatorByPowerIndex(ctx, validator, data.Pool)
if validator.Status == sdk.Bonded {

View File

@ -68,7 +68,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
if found {
return ErrValidatorOwnerExists(k.Codespace()).Result()
}
_, found = k.GetValidatorByPubKey(ctx, msg.PubKey)
_, found = k.GetValidatorByConsPubKey(ctx, msg.PubKey)
if found {
return ErrValidatorPubKeyExists(k.Codespace()).Result()
}
@ -78,7 +78,7 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
validator := NewValidator(msg.ValidatorAddr, msg.PubKey, msg.Description)
k.SetValidator(ctx, validator)
k.SetValidatorByPubKeyIndex(ctx, validator)
k.SetValidatorByConsAddr(ctx, validator)
// move coins from the msg.Address account to a (self-delegation) delegator account
// the validator account and global shares are updated within here
@ -87,6 +87,11 @@ func handleMsgCreateValidator(ctx sdk.Context, msg types.MsgCreateValidator, k k
return err.Result()
}
// call the hook if present
k.OnValidatorCreated(ctx, validator.OperatorAddr)
accAddr := sdk.AccAddress(validator.OperatorAddr)
k.OnDelegationCreated(ctx, accAddr, validator.OperatorAddr)
tags := sdk.NewTags(
tags.Action, tags.ActionCreateValidator,
tags.DstValidator, []byte(msg.ValidatorAddr.String()),
@ -146,6 +151,9 @@ func handleMsgDelegate(ctx sdk.Context, msg types.MsgDelegate, k keeper.Keeper)
return err.Result()
}
// call the hook if present
k.OnDelegationCreated(ctx, msg.DelegatorAddr, validator.OperatorAddr)
tags := sdk.NewTags(
tags.Action, tags.ActionDelegate,
tags.Delegator, []byte(msg.DelegatorAddr.String()),

View File

@ -81,8 +81,9 @@ func TestValidatorByPowerIndex(t *testing.T) {
require.True(t, got.IsOK(), "expected create-validator to be ok, got %v", got)
// slash and jail the first validator
keeper.Slash(ctx, keep.PKs[0], 0, initBond, sdk.NewDecWithPrec(5, 1))
keeper.Jail(ctx, keep.PKs[0])
consAddr0 := sdk.ConsAddress(keep.PKs[0].Address())
keeper.Slash(ctx, consAddr0, 0, initBond, sdk.NewDecWithPrec(5, 1))
keeper.Jail(ctx, consAddr0)
validator, found = keeper.GetValidator(ctx, validatorAddr)
require.True(t, found)
require.Equal(t, sdk.Unbonding, validator.Status) // ensure is unbonding
@ -198,11 +199,12 @@ func TestLegacyValidatorDelegations(t *testing.T) {
setInstantUnbondPeriod(keeper, ctx)
bondAmount := int64(10)
valAddr, valPubKey := sdk.ValAddress(keep.Addrs[0]), keep.PKs[0]
valAddr := sdk.ValAddress(keep.Addrs[0])
valConsPubKey, valConsAddr := keep.PKs[0], sdk.ConsAddress(keep.PKs[0].Address())
delAddr := keep.Addrs[1]
// create validator
msgCreateVal := newTestMsgCreateValidator(valAddr, valPubKey, bondAmount)
msgCreateVal := newTestMsgCreateValidator(valAddr, valConsPubKey, bondAmount)
got := handleMsgCreateValidator(ctx, msgCreateVal, keeper)
require.True(t, got.IsOK(), "expected create validator msg to be ok, got %v", got)
@ -264,7 +266,7 @@ func TestLegacyValidatorDelegations(t *testing.T) {
require.Equal(t, bondAmount*2, validator.Tokens.RoundInt64())
// unjail the validator now that is has non-zero self-delegated shares
keeper.Unjail(ctx, valPubKey)
keeper.Unjail(ctx, valConsAddr)
// verify the validator can now accept delegations
msgDelegate = newTestMsgDelegate(delAddr, valAddr, bondAmount)
@ -911,6 +913,7 @@ func TestCliffValidator(t *testing.T) {
func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
ctx, _, keeper := keep.CreateTestInput(t, false, 1000)
valA, valB, del := sdk.ValAddress(keep.Addrs[0]), sdk.ValAddress(keep.Addrs[1]), keep.Addrs[2]
consAddr0 := sdk.ConsAddress(keep.PKs[0].Address())
msgCreateValidator := newTestMsgCreateValidator(valA, keep.PKs[0], 10)
got := handleMsgCreateValidator(ctx, msgCreateValidator, keeper)
@ -944,7 +947,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
require.Equal(t, sdk.NewDec(6), delegation.Shares)
// slash the validator by half
keeper.Slash(ctx, keep.PKs[0], 0, 20, sdk.NewDecWithPrec(5, 1))
keeper.Slash(ctx, consAddr0, 0, 20, sdk.NewDecWithPrec(5, 1))
// unbonding delegation should have been slashed by half
unbonding, found := keeper.GetUnbondingDelegation(ctx, del, valA)
@ -968,7 +971,7 @@ func TestBondUnbondRedelegateSlashTwice(t *testing.T) {
// slash the validator for an infraction committed after the unbonding and redelegation begin
ctx = ctx.WithBlockHeight(3)
keeper.Slash(ctx, keep.PKs[0], 2, 10, sdk.NewDecWithPrec(5, 1))
keeper.Slash(ctx, consAddr0, 2, 10, sdk.NewDecWithPrec(5, 1))
// unbonding delegation should be unchanged
unbonding, found = keeper.GetUnbondingDelegation(ctx, del, valA)

View File

@ -66,6 +66,12 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
// remove a delegation from store
func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) {
// call the hook if present
if k.hooks != nil {
k.hooks.OnDelegationRemoved(ctx, delegation.DelegatorAddr, delegation.ValidatorAddr)
}
store := ctx.KVStore(k.storeKey)
store.Delete(GetDelegationKey(delegation.DelegatorAddr, delegation.ValidatorAddr))
}
@ -275,6 +281,11 @@ func (k Keeper) Delegate(ctx sdk.Context, delAddr sdk.AccAddress, bondAmt sdk.Co
k.SetDelegation(ctx, delegation)
k.UpdateValidator(ctx, validator)
// call the hook if present
if k.hooks != nil {
k.hooks.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr)
}
return
}
@ -333,6 +344,11 @@ func (k Keeper) unbond(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValA
k.RemoveValidator(ctx, validator.OperatorAddr)
}
// call the hook if present
if k.hooks != nil {
k.hooks.OnDelegationSharesModified(ctx, delegation.DelegatorAddr, validator.OperatorAddr)
}
return amount, nil
}

54
x/stake/keeper/hooks.go Normal file
View File

@ -0,0 +1,54 @@
//nolint
package keeper
import (
sdk "github.com/cosmos/cosmos-sdk/types"
)
// Expose the hooks if present
func (k Keeper) OnValidatorCreated(ctx sdk.Context, address sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnValidatorCreated(ctx, address)
}
}
func (k Keeper) OnValidatorCommissionChange(ctx sdk.Context, address sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnValidatorCommissionChange(ctx, address)
}
}
func (k Keeper) OnValidatorRemoved(ctx sdk.Context, address sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnValidatorRemoved(ctx, address)
}
}
func (k Keeper) OnValidatorBonded(ctx sdk.Context, address sdk.ConsAddress) {
if k.hooks != nil {
k.hooks.OnValidatorBonded(ctx, address)
}
}
func (k Keeper) OnValidatorBeginUnbonding(ctx sdk.Context, address sdk.ConsAddress) {
if k.hooks != nil {
k.hooks.OnValidatorBeginUnbonding(ctx, address)
}
}
func (k Keeper) OnDelegationCreated(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnDelegationCreated(ctx, delAddr, valAddr)
}
}
func (k Keeper) OnDelegationSharesModified(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnDelegationSharesModified(ctx, delAddr, valAddr)
}
}
func (k Keeper) OnDelegationRemoved(ctx sdk.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) {
if k.hooks != nil {
k.hooks.OnDelegationRemoved(ctx, delAddr, valAddr)
}
}

View File

@ -10,11 +10,11 @@ import (
// keeper of the stake store
type Keeper struct {
storeKey sdk.StoreKey
storeTKey sdk.StoreKey
cdc *codec.Codec
bankKeeper bank.Keeper
validatorHooks sdk.ValidatorHooks
storeKey sdk.StoreKey
storeTKey sdk.StoreKey
cdc *codec.Codec
bankKeeper bank.Keeper
hooks sdk.StakingHooks
// codespace
codespace sdk.CodespaceType
@ -22,22 +22,22 @@ type Keeper struct {
func NewKeeper(cdc *codec.Codec, key, tkey sdk.StoreKey, ck bank.Keeper, codespace sdk.CodespaceType) Keeper {
keeper := Keeper{
storeKey: key,
storeTKey: tkey,
cdc: cdc,
bankKeeper: ck,
validatorHooks: nil,
codespace: codespace,
storeKey: key,
storeTKey: tkey,
cdc: cdc,
bankKeeper: ck,
hooks: nil,
codespace: codespace,
}
return keeper
}
// Set the validator hooks
func (k Keeper) WithValidatorHooks(v sdk.ValidatorHooks) Keeper {
if k.validatorHooks != nil {
func (k Keeper) WithHooks(sh sdk.StakingHooks) Keeper {
if k.hooks != nil {
panic("cannot set validator hooks twice")
}
k.validatorHooks = v
k.hooks = sh
return k
}

View File

@ -3,8 +3,6 @@ package keeper
import (
"encoding/binary"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types"
)
@ -17,7 +15,7 @@ var (
ParamKey = []byte{0x00} // key for parameters relating to staking
PoolKey = []byte{0x01} // key for the staking pools
ValidatorsKey = []byte{0x02} // prefix for each key to a validator
ValidatorsByPubKeyIndexKey = []byte{0x03} // prefix for each key to a validator index, by pubkey
ValidatorsByConsAddrKey = []byte{0x03} // prefix for each key to a validator index, by pubkey
ValidatorsBondedIndexKey = []byte{0x04} // prefix for each key to a validator index, for bonded validators
ValidatorsByPowerIndexKey = []byte{0x05} // prefix for each key to a validator index, sorted by power
ValidatorCliffIndexKey = []byte{0x06} // key for the validator index of the cliff validator
@ -44,8 +42,8 @@ func GetValidatorKey(operatorAddr sdk.ValAddress) []byte {
// gets the key for the validator with pubkey
// VALUE: validator operator address ([]byte)
func GetValidatorByPubKeyIndexKey(pubkey crypto.PubKey) []byte {
return append(ValidatorsByPubKeyIndexKey, pubkey.Bytes()...)
func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte {
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
}
// gets the key for the current validator group

View File

@ -3,10 +3,9 @@ package keeper
import (
"fmt"
"github.com/tendermint/tendermint/crypto"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/tendermint/tendermint/crypto"
)
// Implements ValidatorSet
@ -60,8 +59,17 @@ func (k Keeper) Validator(ctx sdk.Context, address sdk.ValAddress) sdk.Validator
}
// get the sdk.validator for a particular pubkey
func (k Keeper) ValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) sdk.Validator {
val, found := k.GetValidatorByPubKey(ctx, pubkey)
func (k Keeper) ValidatorByConsAddr(ctx sdk.Context, addr sdk.ConsAddress) sdk.Validator {
val, found := k.GetValidatorByConsAddr(ctx, addr)
if !found {
return nil
}
return val
}
// get the sdk.validator for a particular pubkey
func (k Keeper) ValidatorByConsPubKey(ctx sdk.Context, consPubKey crypto.PubKey) sdk.Validator {
val, found := k.GetValidatorByConsPubKey(ctx, consPubKey)
if !found {
return nil
}
@ -95,15 +103,16 @@ func (k Keeper) Delegation(ctx sdk.Context, addrDel sdk.AccAddress, addrVal sdk.
return bond
}
// iterate through the active validator set and perform the provided function
func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress, fn func(index int64, delegation sdk.Delegation) (stop bool)) {
// iterate through all of the delegations from a delegator
func (k Keeper) IterateDelegations(ctx sdk.Context, delAddr sdk.AccAddress,
fn func(index int64, del sdk.Delegation) (stop bool)) {
store := ctx.KVStore(k.storeKey)
key := GetDelegationsKey(delAddr)
iterator := sdk.KVStorePrefixIterator(store, key)
i := int64(0)
for ; iterator.Valid(); iterator.Next() {
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
stop := fn(i, delegation) // XXX is this safe will the fields be able to get written to?
delegatorPrefixKey := GetDelegationsKey(delAddr)
iterator := sdk.KVStorePrefixIterator(store, delegatorPrefixKey) //smallest to largest
for i := int64(0); iterator.Valid(); iterator.Next() {
del := types.MustUnmarshalDelegation(k.cdc, iterator.Key(), iterator.Value())
stop := fn(i, del)
if stop {
break
}

View File

@ -5,7 +5,6 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
types "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/tendermint/tendermint/crypto"
)
// Slash a validator for an infraction committed at a known height
@ -24,7 +23,7 @@ import (
// not at a height in the future
//
// nolint: gocyclo
func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight int64, power int64, slashFactor sdk.Dec) {
func (k Keeper) Slash(ctx sdk.Context, consAddr sdk.ConsAddress, infractionHeight int64, power int64, slashFactor sdk.Dec) {
logger := ctx.Logger().With("module", "x/stake")
if slashFactor.LT(sdk.ZeroDec()) {
@ -36,7 +35,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
// ref https://github.com/cosmos/cosmos-sdk/issues/1348
// ref https://github.com/cosmos/cosmos-sdk/issues/1471
validator, found := k.GetValidatorByPubKey(ctx, pubkey)
validator, found := k.GetValidatorByConsAddr(ctx, consAddr)
if !found {
// If not found, the validator must have been overslashed and removed - so we don't need to do anything
// NOTE: Correctness dependent on invariant that unbonding delegations / redelegations must also have been completely
@ -44,7 +43,7 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
// Log the slash attempt for future reference (maybe we should tag it too)
logger.Error(fmt.Sprintf(
"WARNING: Ignored attempt to slash a nonexistent validator with address %s, we recommend you investigate immediately",
pubkey.Address()))
consAddr))
return
}
@ -125,36 +124,28 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, infractionHeight in
}
// jail a validator
func (k Keeper) Jail(ctx sdk.Context, pubkey crypto.PubKey) {
k.setJailed(ctx, pubkey, true)
validatorAddr, err := sdk.ValAddressFromHex(pubkey.Address().String())
if err != nil {
panic(err.Error())
}
func (k Keeper) Jail(ctx sdk.Context, consAddr sdk.ConsAddress) {
k.setJailed(ctx, consAddr, true)
logger := ctx.Logger().With("module", "x/stake")
logger.Info(fmt.Sprintf("validator %s jailed", validatorAddr))
logger.Info(fmt.Sprintf("validator %s jailed", consAddr))
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
return
}
// unjail a validator
func (k Keeper) Unjail(ctx sdk.Context, pubkey crypto.PubKey) {
k.setJailed(ctx, pubkey, false)
validatorAddr, err := sdk.ValAddressFromHex(pubkey.Address().String())
if err != nil {
panic(err.Error())
}
func (k Keeper) Unjail(ctx sdk.Context, consAddr sdk.ConsAddress) {
k.setJailed(ctx, consAddr, false)
logger := ctx.Logger().With("module", "x/stake")
logger.Info(fmt.Sprintf("validator %s unjailed", validatorAddr))
logger.Info(fmt.Sprintf("validator %s unjailed", consAddr))
// TODO Return event(s), blocked on https://github.com/tendermint/tendermint/pull/1803
return
}
// set the jailed flag on a validator
func (k Keeper) setJailed(ctx sdk.Context, pubkey crypto.PubKey, isJailed bool) {
validator, found := k.GetValidatorByPubKey(ctx, pubkey)
func (k Keeper) setJailed(ctx sdk.Context, consAddr sdk.ConsAddress, isJailed bool) {
validator, found := k.GetValidatorByConsAddr(ctx, sdk.ConsAddress(consAddr))
if !found {
panic(fmt.Errorf("validator with pubkey %s not found, cannot set jailed to %v", pubkey, isJailed))
panic(fmt.Errorf("validator with consensus-Address %s not found, cannot set jailed to %v", consAddr, isJailed))
}
validator.Jailed = isJailed
k.UpdateValidator(ctx, validator) // update validator, possibly unbonding or bonding it

View File

@ -27,7 +27,7 @@ func setupHelper(t *testing.T, amt int64) (sdk.Context, Keeper, types.Params) {
validator, pool, _ = validator.AddTokensFromDel(pool, sdk.NewInt(amt))
keeper.SetPool(ctx, pool)
validator = keeper.UpdateValidator(ctx, validator)
keeper.SetValidatorByPubKeyIndex(ctx, validator)
keeper.SetValidatorByConsAddr(ctx, validator)
}
pool = keeper.GetPool(ctx)
@ -42,7 +42,7 @@ func TestRevocation(t *testing.T) {
// setup
ctx, keeper, _ := setupHelper(t, 10)
addr := addrVals[0]
pk := PKs[0]
consAddr := sdk.ConsAddress(PKs[0].Address())
// initial state
val, found := keeper.GetValidator(ctx, addr)
@ -50,13 +50,13 @@ func TestRevocation(t *testing.T) {
require.False(t, val.GetJailed())
// test jail
keeper.Jail(ctx, pk)
keeper.Jail(ctx, consAddr)
val, found = keeper.GetValidator(ctx, addr)
require.True(t, found)
require.True(t, val.GetJailed())
// test unjail
keeper.Unjail(ctx, pk)
keeper.Unjail(ctx, consAddr)
val, found = keeper.GetValidator(ctx, addr)
require.True(t, found)
require.False(t, val.GetJailed())
@ -179,24 +179,24 @@ func TestSlashRedelegation(t *testing.T) {
// tests Slash at a future height (must panic)
func TestSlashAtFutureHeight(t *testing.T) {
ctx, keeper, _ := setupHelper(t, 10)
pk := PKs[0]
consAddr := sdk.ConsAddress(PKs[0].Address())
fraction := sdk.NewDecWithPrec(5, 1)
require.Panics(t, func() { keeper.Slash(ctx, pk, 1, 10, fraction) })
require.Panics(t, func() { keeper.Slash(ctx, consAddr, 1, 10, fraction) })
}
// tests Slash at the current height
func TestSlashValidatorAtCurrentHeight(t *testing.T) {
ctx, keeper, _ := setupHelper(t, 10)
pk := PKs[0]
consAddr := sdk.ConsAddress(PKs[0].Address())
fraction := sdk.NewDecWithPrec(5, 1)
oldPool := keeper.GetPool(ctx)
validator, found := keeper.GetValidatorByPubKey(ctx, pk)
validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
keeper.Slash(ctx, pk, ctx.BlockHeight(), 10, fraction)
keeper.Slash(ctx, consAddr, ctx.BlockHeight(), 10, fraction)
// read updated state
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
newPool := keeper.GetPool(ctx)
@ -209,7 +209,7 @@ func TestSlashValidatorAtCurrentHeight(t *testing.T) {
// tests Slash at a previous height with an unbonding delegation
func TestSlashWithUnbondingDelegation(t *testing.T) {
ctx, keeper, params := setupHelper(t, 10)
pk := PKs[0]
consAddr := sdk.ConsAddress(PKs[0].Address())
fraction := sdk.NewDecWithPrec(5, 1)
// set an unbonding delegation
@ -227,9 +227,9 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// slash validator for the first time
ctx = ctx.WithBlockHeight(12)
oldPool := keeper.GetPool(ctx)
validator, found := keeper.GetValidatorByPubKey(ctx, pk)
validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
keeper.Slash(ctx, pk, 10, 10, fraction)
keeper.Slash(ctx, consAddr, 10, 10, fraction)
// read updating unbonding delegation
ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
@ -241,7 +241,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// bonded tokens burned
require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
// power decreased by 3 - 6 stake originally bonded at the time of infraction
// was still bonded at the time of discovery and was slashed by half, 4 stake
@ -251,7 +251,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// slash validator again
ctx = ctx.WithBlockHeight(13)
keeper.Slash(ctx, pk, 9, 10, fraction)
keeper.Slash(ctx, consAddr, 9, 10, fraction)
ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
require.True(t, found)
// balance decreased again
@ -261,7 +261,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// bonded tokens burned again
require.Equal(t, int64(6), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
// power decreased by 3 again
require.Equal(t, sdk.NewDec(4), validator.GetPower())
@ -271,7 +271,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// on the unbonding delegation, but it will slash stake bonded since the infraction
// this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440
ctx = ctx.WithBlockHeight(13)
keeper.Slash(ctx, pk, 9, 10, fraction)
keeper.Slash(ctx, consAddr, 9, 10, fraction)
ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
require.True(t, found)
// balance unchanged
@ -281,7 +281,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// bonded tokens burned again
require.Equal(t, int64(9), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
// power decreased by 3 again
require.Equal(t, sdk.NewDec(1), validator.GetPower())
@ -291,7 +291,7 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// on the unbonding delegation, but it will slash stake bonded since the infraction
// this may not be the desirable behaviour, ref https://github.com/cosmos/cosmos-sdk/issues/1440
ctx = ctx.WithBlockHeight(13)
keeper.Slash(ctx, pk, 9, 10, fraction)
keeper.Slash(ctx, consAddr, 9, 10, fraction)
ubd, found = keeper.GetUnbondingDelegation(ctx, addrDels[0], addrVals[0])
require.True(t, found)
// balance unchanged
@ -303,14 +303,14 @@ func TestSlashWithUnbondingDelegation(t *testing.T) {
// read updated validator
// power decreased by 1 again, validator is out of stake
// ergo validator should have been removed from the store
_, found = keeper.GetValidatorByPubKey(ctx, pk)
_, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.False(t, found)
}
// tests Slash at a previous height with a redelegation
func TestSlashWithRedelegation(t *testing.T) {
ctx, keeper, params := setupHelper(t, 10)
pk := PKs[0]
consAddr := sdk.ConsAddress(PKs[0].Address())
fraction := sdk.NewDecWithPrec(5, 1)
// set a redelegation
@ -343,9 +343,9 @@ func TestSlashWithRedelegation(t *testing.T) {
// slash validator
ctx = ctx.WithBlockHeight(12)
oldPool := keeper.GetPool(ctx)
validator, found := keeper.GetValidatorByPubKey(ctx, pk)
validator, found := keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
keeper.Slash(ctx, pk, 10, 10, fraction)
keeper.Slash(ctx, consAddr, 10, 10, fraction)
// read updating redelegation
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
@ -357,7 +357,7 @@ func TestSlashWithRedelegation(t *testing.T) {
// bonded tokens burned
require.Equal(t, int64(5), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
// power decreased by 2 - 4 stake originally bonded at the time of infraction
// was still bonded at the time of discovery and was slashed by half, 4 stake
@ -367,9 +367,9 @@ func TestSlashWithRedelegation(t *testing.T) {
// slash the validator again
ctx = ctx.WithBlockHeight(12)
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
require.NotPanics(t, func() { keeper.Slash(ctx, pk, 10, 10, sdk.OneDec()) })
require.NotPanics(t, func() { keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec()) })
// read updating redelegation
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
@ -381,16 +381,16 @@ func TestSlashWithRedelegation(t *testing.T) {
// seven bonded tokens burned
require.Equal(t, int64(12), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
// power decreased by 4
require.Equal(t, sdk.NewDec(4), validator.GetPower())
// slash the validator again, by 100%
ctx = ctx.WithBlockHeight(12)
validator, found = keeper.GetValidatorByPubKey(ctx, pk)
validator, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.True(t, found)
keeper.Slash(ctx, pk, 10, 10, sdk.OneDec())
keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec())
// read updating redelegation
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
@ -403,16 +403,16 @@ func TestSlashWithRedelegation(t *testing.T) {
require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
// validator decreased to zero power, should have been removed from the store
_, found = keeper.GetValidatorByPubKey(ctx, pk)
_, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.False(t, found)
// slash the validator again, by 100%
// no stake remains to be slashed
ctx = ctx.WithBlockHeight(12)
// validator no longer in the store
_, found = keeper.GetValidatorByPubKey(ctx, pk)
_, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.False(t, found)
keeper.Slash(ctx, pk, 10, 10, sdk.OneDec())
keeper.Slash(ctx, consAddr, 10, 10, sdk.OneDec())
// read updating redelegation
rd, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
@ -425,7 +425,7 @@ func TestSlashWithRedelegation(t *testing.T) {
require.Equal(t, int64(16), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
// power still zero, still not in the store
_, found = keeper.GetValidatorByPubKey(ctx, pk)
_, found = keeper.GetValidatorByConsAddr(ctx, consAddr)
require.False(t, found)
}
@ -472,9 +472,10 @@ func TestSlashBoth(t *testing.T) {
// slash validator
ctx = ctx.WithBlockHeight(12)
oldPool := keeper.GetPool(ctx)
validator, found := keeper.GetValidatorByPubKey(ctx, PKs[0])
validator, found := keeper.GetValidatorByConsPubKey(ctx, PKs[0])
require.True(t, found)
keeper.Slash(ctx, PKs[0], 10, 10, fraction)
consAddr0 := sdk.ConsAddress(PKs[0].Address())
keeper.Slash(ctx, consAddr0, 10, 10, fraction)
// read updating redelegation
rdA, found = keeper.GetRedelegation(ctx, addrDels[0], addrVals[0], addrVals[1])
@ -488,7 +489,7 @@ func TestSlashBoth(t *testing.T) {
// bonded tokens burned
require.Equal(t, int64(3), oldPool.BondedTokens.Sub(newPool.BondedTokens).RoundInt64())
// read updated validator
validator, found = keeper.GetValidatorByPubKey(ctx, PKs[0])
validator, found = keeper.GetValidatorByConsPubKey(ctx, PKs[0])
require.True(t, found)
// power not decreased, all stake was bonded since
require.Equal(t, sdk.NewDec(10), validator.GetPower())

View File

@ -58,14 +58,25 @@ func (k Keeper) GetValidator(ctx sdk.Context, addr sdk.ValAddress) (validator ty
return validator, true
}
// get a single validator by pubkey
func (k Keeper) GetValidatorByPubKey(ctx sdk.Context, pubkey crypto.PubKey) (validator types.Validator, found bool) {
// get a single validator by consensus address
func (k Keeper) GetValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) (validator types.Validator, found bool) {
store := ctx.KVStore(k.storeKey)
addr := store.Get(GetValidatorByPubKeyIndexKey(pubkey))
if addr == nil {
opAddr := store.Get(GetValidatorByConsAddrKey(consAddr))
if opAddr == nil {
return validator, false
}
return k.GetValidator(ctx, addr)
return k.GetValidator(ctx, opAddr)
}
// get a single validator by pubkey
func (k Keeper) GetValidatorByConsPubKey(ctx sdk.Context, consPubKey crypto.PubKey) (validator types.Validator, found bool) {
store := ctx.KVStore(k.storeKey)
consAddr := sdk.ConsAddress(consPubKey.Address())
opAddr := store.Get(GetValidatorByConsAddrKey(consAddr))
if opAddr == nil {
return validator, false
}
return k.GetValidator(ctx, opAddr)
}
// set the main record holding validator details
@ -76,9 +87,11 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
}
// validator index
func (k Keeper) SetValidatorByPubKeyIndex(ctx sdk.Context, validator types.Validator) {
// TODO change to SetValidatorByConsAddr? used for retrieving from ConsPubkey as well- kinda confusing
func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey)
store.Set(GetValidatorByPubKeyIndexKey(validator.ConsPubKey), validator.OperatorAddr)
consAddr := sdk.ConsAddress(validator.OperatorAddr.Bytes())
store.Set(GetValidatorByConsAddrKey(consAddr), validator.OperatorAddr)
}
// validator index
@ -622,8 +635,8 @@ func (k Keeper) beginUnbondingValidator(ctx sdk.Context, validator types.Validat
store.Delete(GetValidatorsBondedIndexKey(validator.OperatorAddr))
// call the unbond hook if present
if k.validatorHooks != nil {
k.validatorHooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
if k.hooks != nil {
k.hooks.OnValidatorBeginUnbonding(ctx, validator.ConsAddress())
}
// return updated validator
@ -657,8 +670,8 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
tstore.Set(GetTendermintUpdatesTKey(validator.OperatorAddr), bzABCI)
// call the bond hook if present
if k.validatorHooks != nil {
k.validatorHooks.OnValidatorBonded(ctx, validator.ConsAddress())
if k.hooks != nil {
k.hooks.OnValidatorBonded(ctx, validator.ConsAddress())
}
// return updated validator
@ -668,6 +681,11 @@ func (k Keeper) bondValidator(ctx sdk.Context, validator types.Validator) types.
// remove the validator record and associated indexes
func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
// call the hook if present
if k.hooks != nil {
k.hooks.OnValidatorRemoved(ctx, address)
}
// first retrieve the old validator record
validator, found := k.GetValidator(ctx, address)
if !found {
@ -678,7 +696,7 @@ func (k Keeper) RemoveValidator(ctx sdk.Context, address sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
pool := k.GetPool(ctx)
store.Delete(GetValidatorKey(address))
store.Delete(GetValidatorByPubKeyIndexKey(validator.ConsPubKey))
store.Delete(GetValidatorByConsAddrKey(sdk.ConsAddress(validator.ConsPubKey.Address())))
store.Delete(GetValidatorsByPowerIndexKey(validator, pool))
// delete from the current and power weighted validator groups if the validator
@ -727,3 +745,36 @@ func ensureValidatorFound(found bool, ownerAddr []byte) {
panic(fmt.Sprintf("validator record not found for address: %X\n", ownerAddr))
}
}
//__________________________________________________________________________
// XXX remove this code - this is should be superceded by commission work that bez is doing
// get a single validator
func (k Keeper) UpdateValidatorCommission(ctx sdk.Context, addr sdk.ValAddress, newCommission sdk.Dec) sdk.Error {
// call the hook if present
if k.hooks != nil {
k.hooks.OnValidatorCommissionChange(ctx, addr)
}
validator, found := k.GetValidator(ctx, addr)
// check for errors
switch {
case !found:
return types.ErrNoValidatorFound(k.Codespace())
case newCommission.LT(sdk.ZeroDec()):
return types.ErrCommissionNegative(k.Codespace())
case newCommission.GT(validator.CommissionMax):
return types.ErrCommissionBeyondMax(k.Codespace())
//case rateChange(Commission) > CommissionMaxChange: // XXX XXX XXX TODO implementation
//return types.ErrCommissionPastRate(k.Codespace())
}
// TODO adjust all the commission terms appropriately
validator.Commission = newCommission
k.SetValidator(ctx, validator)
return nil
}

View File

@ -260,12 +260,13 @@ func TestSlashToZeroPowerRemoved(t *testing.T) {
require.Equal(t, sdk.Unbonded, validator.Status)
require.Equal(t, int64(100), validator.Tokens.RoundInt64())
keeper.SetPool(ctx, pool)
keeper.SetValidatorByPubKeyIndex(ctx, validator)
keeper.SetValidatorByConsAddr(ctx, validator)
validator = keeper.UpdateValidator(ctx, validator)
require.Equal(t, int64(100), validator.Tokens.RoundInt64(), "\nvalidator %v\npool %v", validator, pool)
// slash the validator by 100%
keeper.Slash(ctx, PKs[0], 0, 100, sdk.OneDec())
consAddr0 := sdk.ConsAddress(PKs[0].Address())
keeper.Slash(ctx, consAddr0, 0, 100, sdk.OneDec())
// validator should have been deleted
_, found := keeper.GetValidator(ctx, addrVals[0])
require.False(t, found)

View File

@ -35,7 +35,7 @@ var (
NewKeeper = keeper.NewKeeper
GetValidatorKey = keeper.GetValidatorKey
GetValidatorByPubKeyIndexKey = keeper.GetValidatorByPubKeyIndexKey
GetValidatorByConsAddrKey = keeper.GetValidatorByConsAddrKey
GetValidatorsBondedIndexKey = keeper.GetValidatorsBondedIndexKey
GetValidatorsByPowerIndexKey = keeper.GetValidatorsByPowerIndexKey
GetTendermintUpdatesTKey = keeper.GetTendermintUpdatesTKey
@ -44,7 +44,7 @@ var (
ParamKey = keeper.ParamKey
PoolKey = keeper.PoolKey
ValidatorsKey = keeper.ValidatorsKey
ValidatorsByPubKeyIndexKey = keeper.ValidatorsByPubKeyIndexKey
ValidatorsByConsAddrKey = keeper.ValidatorsByConsAddrKey
ValidatorsBondedIndexKey = keeper.ValidatorsBondedIndexKey
ValidatorsByPowerIndexKey = keeper.ValidatorsByPowerIndexKey
ValidatorCliffIndexKey = keeper.ValidatorCliffIndexKey

View File

@ -22,6 +22,5 @@ func init() {
cdc := codec.New()
RegisterCodec(cdc)
codec.RegisterCrypto(cdc)
MsgCdc = cdc
//MsgCdc = cdc.Seal() //TODO use when upgraded to go-amino 0.9.10
MsgCdc = cdc.Seal()
}

View File

@ -89,7 +89,7 @@ var _ sdk.Delegation = Delegation{}
// nolint - for sdk.Delegation
func (d Delegation) GetDelegator() sdk.AccAddress { return d.DelegatorAddr }
func (d Delegation) GetValidator() sdk.ValAddress { return d.ValidatorAddr }
func (d Delegation) GetBondShares() sdk.Dec { return d.Shares }
func (d Delegation) GetShares() sdk.Dec { return d.Shares }
// HumanReadableString returns a human readable string representation of a
// Delegation. An error is returned if the Delegation's delegator or validator

View File

@ -65,6 +65,14 @@ func ErrCommissionHuge(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than 100%")
}
func ErrCommissionBeyondMax(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission cannot be more than preset commission maximum")
}
func ErrCommissionPastRate(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidValidator, "commission change is greater than the commission rate, please wait before changing your commission more")
}
func ErrNilDelegatorAddr(codespace sdk.CodespaceType) sdk.Error {
return sdk.NewError(codespace, CodeInvalidInput, "delegator address is nil")
}

View File

@ -470,12 +470,14 @@ func (v Validator) IsUnbonded(ctx sdk.Context) bool {
var _ sdk.Validator = Validator{}
// nolint - for sdk.Validator
func (v Validator) GetJailed() bool { return v.Jailed }
func (v Validator) GetMoniker() string { return v.Description.Moniker }
func (v Validator) GetStatus() sdk.BondStatus { return v.Status }
func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddr }
func (v Validator) GetPubKey() crypto.PubKey { return v.ConsPubKey }
func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() }
func (v Validator) GetTokens() sdk.Dec { return v.Tokens }
func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares }
func (v Validator) GetBondHeight() int64 { return v.BondHeight }
func (v Validator) GetJailed() bool { return v.Jailed }
func (v Validator) GetMoniker() string { return v.Description.Moniker }
func (v Validator) GetStatus() sdk.BondStatus { return v.Status }
func (v Validator) GetOperator() sdk.ValAddress { return v.OperatorAddr }
func (v Validator) GetPubKey() crypto.PubKey { return v.ConsPubKey }
func (v Validator) GetConsAddr() sdk.ConsAddress { return sdk.ConsAddress(v.ConsPubKey.Address()) }
func (v Validator) GetPower() sdk.Dec { return v.BondedTokens() }
func (v Validator) GetTokens() sdk.Dec { return v.Tokens }
func (v Validator) GetCommission() sdk.Dec { return v.Commission }
func (v Validator) GetDelegatorShares() sdk.Dec { return v.DelegatorShares }
func (v Validator) GetBondHeight() int64 { return v.BondHeight }