Skip to content

Commit

Permalink
Merge PR #3507: Results from x/staking & x/slashing peer review
Browse files Browse the repository at this point in the history
  • Loading branch information
cwgoes authored and jackzampolin committed Feb 8, 2019
1 parent a5c1c7e commit 38068a5
Show file tree
Hide file tree
Showing 47 changed files with 296 additions and 404 deletions.
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ IMPROVEMENTS
for tx size in the ante handler.
* [\#3454](https://github.com/cosmos/cosmos-sdk/pull/3454) Add `--jail-whitelist` to `gaiad export` to enable testing of complex exports
* [\#3424](https://github.com/cosmos/cosmos-sdk/issues/3424) Allow generation of gentxs with empty memo field.
* \#3507 General cleanup, removal of unnecessary struct fields, undelegation bugfix, and comment clarification in x/staking and x/slashing

* SDK
* [\#2605] x/params add subkey accessing
Expand Down
3 changes: 0 additions & 3 deletions client/lcd/lcd_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,6 @@ func TestBonding(t *testing.T) {
redelegation := getRedelegations(t, port, addr, operAddrs[0], operAddrs[1])
require.Len(t, redelegation, 1)
require.Len(t, redelegation[0].Entries, 1)
require.Equal(t, rdTokens, redelegation[0].Entries[0].Balance.Amount)

delegatorUbds := getDelegatorUnbondingDelegations(t, port, addr)
require.Len(t, delegatorUbds, 1)
Expand All @@ -656,7 +655,6 @@ func TestBonding(t *testing.T) {
delegatorReds := getRedelegations(t, port, addr, nil, nil)
require.Len(t, delegatorReds, 1)
require.Len(t, delegatorReds[0].Entries, 1)
require.Equal(t, rdTokens, delegatorReds[0].Entries[0].Balance.Amount)

validatorUbds := getValidatorUnbondingDelegations(t, port, operAddrs[0])
require.Len(t, validatorUbds, 1)
Expand All @@ -666,7 +664,6 @@ func TestBonding(t *testing.T) {
validatorReds := getRedelegations(t, port, nil, operAddrs[0], nil)
require.Len(t, validatorReds, 1)
require.Len(t, validatorReds[0].Entries, 1)
require.Equal(t, rdTokens, validatorReds[0].Entries[0].Balance.Amount)

// TODO Undonding status not currently implemented
// require.Equal(t, sdk.Unbonding, bondedValidators[0].Status)
Expand Down
4 changes: 0 additions & 4 deletions cmd/gaia/app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -355,10 +355,6 @@ func (h StakingHooks) AfterValidatorBonded(ctx sdk.Context, consAddr sdk.ConsAdd
h.dh.AfterValidatorBonded(ctx, consAddr, valAddr)
h.sh.AfterValidatorBonded(ctx, consAddr, valAddr)
}
func (h StakingHooks) AfterValidatorPowerDidChange(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorPowerDidChange(ctx, consAddr, valAddr)
h.sh.AfterValidatorPowerDidChange(ctx, consAddr, valAddr)
}
func (h StakingHooks) AfterValidatorBeginUnbonding(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
h.dh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
h.sh.AfterValidatorBeginUnbonding(ctx, consAddr, valAddr)
Expand Down
1 change: 0 additions & 1 deletion cmd/gaia/app/export.go
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,6 @@ func (app *GaiaApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []st
panic("expected validator, not found")
}

validator.BondHeight = 0
validator.UnbondingHeight = 0
valConsAddrs = append(valConsAddrs, validator.ConsAddress())
if applyWhiteList && !whiteListMap[addr.String()] {
Expand Down
2 changes: 0 additions & 2 deletions docs/spec/staking/hooks.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,6 @@ following hooks can registered with staking:
- called when a validator is bonded
- `AfterValidatorBeginUnbonding(Context, ConsAddress, ValAddress)`
- called when a validator begins unbonding
- `AfterValidatorPowerDidChange(Context, ConsAddress, ValAddress)`
- called at EndBlock when a validator's power is changed
- `BeforeDelegationCreated(Context, AccAddress, ValAddress)`
- called when a delegation is created
- `BeforeDelegationSharesModified(Context, AccAddress, ValAddress)`
Expand Down
1 change: 0 additions & 1 deletion docs/spec/staking/state.md
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,6 @@ type RedelegationEntry struct {
CompletionTime time.Time // unix time for redelegation completion
InitialBalance sdk.Coin // initial balance when redelegation started
Balance sdk.Coin // current balance (current value held in destination validator)
SharesSrc sdk.Dec // amount of source-validator shares removed by redelegation
SharesDst sdk.Dec // amount of destination-validator shares created by redelegation
}
```
7 changes: 7 additions & 0 deletions types/int.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ func gt(i *big.Int, i2 *big.Int) bool { return i.Cmp(i2) == 1 }

func lt(i *big.Int, i2 *big.Int) bool { return i.Cmp(i2) == -1 }

func lte(i *big.Int, i2 *big.Int) bool { return i.Cmp(i2) <= 0 }

func add(i *big.Int, i2 *big.Int) *big.Int { return new(big.Int).Add(i, i2) }

func sub(i *big.Int, i2 *big.Int) *big.Int { return new(big.Int).Sub(i, i2) }
Expand Down Expand Up @@ -191,6 +193,11 @@ func (i Int) LT(i2 Int) bool {
return lt(i.i, i2.i)
}

// LTE returns true if first Int is less than or equal to second
func (i Int) LTE(i2 Int) bool {
return lte(i.i, i2.i)
}

// Add adds Int from another
func (i Int) Add(i2 Int) (res Int) {
res = Int{add(i.i, i2.i)}
Expand Down
2 changes: 0 additions & 2 deletions types/stake.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,6 @@ type Validator interface {
GetTendermintPower() int64 // validation power in tendermint
GetCommission() Dec // validator commission rate
GetDelegatorShares() Dec // total outstanding delegator shares
GetBondHeight() int64 // height in which the validator became active
GetDelegatorShareExRate() Dec // tokens per delegator share exchange rate
}

Expand Down Expand Up @@ -123,7 +122,6 @@ type StakingHooks interface {

AfterValidatorBonded(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator is bonded
AfterValidatorBeginUnbonding(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Must be called when a validator begins unbonding
AfterValidatorPowerDidChange(ctx Context, consAddr ConsAddress, valAddr ValAddress) // Called at EndBlock when a validator's power did change

BeforeDelegationCreated(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation is created
BeforeDelegationSharesModified(ctx Context, delAddr AccAddress, valAddr ValAddress) // Must be called when a delegation's shares are modified
Expand Down
2 changes: 0 additions & 2 deletions x/distribution/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,6 @@ func (h Hooks) AfterValidatorBeginUnbonding(ctx sdk.Context, _ sdk.ConsAddress,
}
func (h Hooks) AfterValidatorBonded(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) {
}
func (h Hooks) AfterValidatorPowerDidChange(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) {
}
func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, fraction sdk.Dec) {
// record the slash event
h.k.updateValidatorSlashFraction(ctx, valAddr, fraction)
Expand Down
5 changes: 3 additions & 2 deletions x/slashing/client/module_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
amino "github.com/tendermint/go-amino"

"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/slashing"
"github.com/cosmos/cosmos-sdk/x/slashing/client/cli"
)

Expand All @@ -22,7 +23,7 @@ func NewModuleClient(storeKey string, cdc *amino.Codec) ModuleClient {
func (mc ModuleClient) GetQueryCmd() *cobra.Command {
// Group slashing queries under a subcommand
slashingQueryCmd := &cobra.Command{
Use: "slashing",
Use: slashing.ModuleName,
Short: "Querying commands for the slashing module",
}

Expand All @@ -40,7 +41,7 @@ func (mc ModuleClient) GetQueryCmd() *cobra.Command {
// GetTxCmd returns the transaction commands for this module
func (mc ModuleClient) GetTxCmd() *cobra.Command {
slashingTxCmd := &cobra.Command{
Use: "slashing",
Use: slashing.ModuleName,
Short: "Slashing transactions subcommands",
}

Expand Down
2 changes: 1 addition & 1 deletion x/slashing/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ type CodeType = sdk.CodeType

const (
// Default slashing codespace
DefaultCodespace sdk.CodespaceType = "SLASH"
DefaultCodespace sdk.CodespaceType = ModuleName

CodeInvalidValidator CodeType = 101
CodeValidatorJailed CodeType = 102
Expand Down
2 changes: 1 addition & 1 deletion x/slashing/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ type MissedBlock struct {
Missed bool `json:"missed"`
}

// HubDefaultGenesisState - default GenesisState used by Cosmos Hub
// DefaultGenesisState - default GenesisState used by Cosmos Hub
func DefaultGenesisState() GenesisState {
return GenesisState{
Params: DefaultParams(),
Expand Down
2 changes: 2 additions & 0 deletions x/slashing/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
return ErrMissingSelfDelegation(k.codespace).Result()
}

// cannot be unjailed if not jailed
if !validator.GetJailed() {
return ErrValidatorNotJailed(k.codespace).Result()
}
Expand All @@ -42,6 +43,7 @@ func handleMsgUnjail(ctx sdk.Context, msg MsgUnjail, k Keeper) sdk.Result {
return ErrNoValidatorForAddress(k.codespace).Result()
}

// cannot be unjailed if tombstoned
if info.Tombstoned {
return ErrValidatorJailed(k.codespace).Result()
}
Expand Down
1 change: 0 additions & 1 deletion x/slashing/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,6 @@ func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {

// nolint - unused hooks
func (h Hooks) AfterValidatorBeginUnbonding(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) {}
func (h Hooks) AfterValidatorPowerDidChange(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) {}
func (h Hooks) BeforeValidatorModified(_ sdk.Context, _ sdk.ValAddress) {}
func (h Hooks) BeforeDelegationCreated(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
func (h Hooks) BeforeDelegationSharesModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.ValAddress) {}
Expand Down
27 changes: 21 additions & 6 deletions x/slashing/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,15 +39,19 @@ func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, vs sdk.ValidatorSet, paramspa
// power: power of the double-signing validator at the height of infraction
func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractionHeight int64, timestamp time.Time, power int64) {
logger := ctx.Logger().With("module", "x/slashing")

// calculate the age of the evidence
time := ctx.BlockHeader().Time
age := time.Sub(timestamp)

// fetch the validator public key
consAddr := sdk.ConsAddress(addr)
pubkey, err := k.getPubkey(ctx, addr)
if err != nil {
panic(fmt.Sprintf("Validator consensus-address %v not found", consAddr))
}

// Reject evidence if the double is too old
// Reject evidence if the double-sign is too old
if age > k.MaxEvidenceAge(ctx) {
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, age of %d past max age of %d",
pubkey.Address(), infractionHeight, age, k.MaxEvidenceAge(ctx)))
Expand All @@ -62,18 +66,20 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
// Tendermint might break this assumption at some point.
return
}

// fetch the validator signing info
signInfo, found := k.getValidatorSigningInfo(ctx, consAddr)
if !found {
panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr))
}

// Validator is already tombstoned
// validator is already tombstoned
if signInfo.Tombstoned {
logger.Info(fmt.Sprintf("Ignored double sign from %s at height %d, validator already tombstoned", pubkey.Address(), infractionHeight))
return
}

// Double sign confirmed
// double sign confirmed
logger.Info(fmt.Sprintf("Confirmed double sign from %s at height %d, age of %d", pubkey.Address(), infractionHeight, age))

// We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height.
Expand All @@ -98,7 +104,7 @@ func (k Keeper) handleDoubleSign(ctx sdk.Context, addr crypto.Address, infractio
k.validatorSet.Jail(ctx, consAddr)
}

// Set slashed so far to total slash
// Set tombstoned to be true
signInfo.Tombstoned = true

// Set jailed until to be forever (max time)
Expand All @@ -118,12 +124,15 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
if err != nil {
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

// fetch signing info
signInfo, found := k.getValidatorSigningInfo(ctx, consAddr)
if !found {
panic(fmt.Sprintf("Expected signing info for validator %s but not found", consAddr))
}

// this is a relative index, so it counts blocks the validator *should* have signed
// will use the 0-value default signing info if not present, except for start height
index := signInfo.IndexOffset % k.SignedBlocksWindow(ctx)
signInfo.IndexOffset++

Expand All @@ -148,14 +157,19 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
if missed {
logger.Info(fmt.Sprintf("Absent validator %s at height %d, %d missed, threshold %d", addr, height, signInfo.MissedBlocksCounter, k.MinSignedPerWindow(ctx)))
}

minHeight := signInfo.StartHeight + k.SignedBlocksWindow(ctx)
maxMissed := k.SignedBlocksWindow(ctx) - k.MinSignedPerWindow(ctx)

// if we are past the minimum height and the validator has missed too many blocks, punish them
if height > minHeight && signInfo.MissedBlocksCounter > maxMissed {
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)))

// We need to retrieve the stake distribution which signed the block, so we subtract ValidatorUpdateDelay from the evidence height,
// and subtract an additional 1 since this is the LastCommit.
// Note that this *can* result in a negative "distributionHeight" up to -ValidatorUpdateDelay-1,
Expand All @@ -165,6 +179,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
k.validatorSet.Slash(ctx, consAddr, distributionHeight, power, k.SlashFractionDowntime(ctx))
k.validatorSet.Jail(ctx, consAddr)
signInfo.JailedUntil = ctx.BlockHeader().Time.Add(k.DowntimeJailDuration(ctx))

// We need to reset the counter & array so that the validator won't be immediately slashed for downtime upon rebonding.
signInfo.MissedBlocksCounter = 0
signInfo.IndexOffset = 0
Expand Down
9 changes: 6 additions & 3 deletions x/slashing/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,17 @@ import (
)

const (
// ModuleName is the name of the module
ModuleName = "slashing"

// StoreKey is the store key string for slashing
StoreKey = "slashing"
StoreKey = ModuleName

// RouterKey is the message route for slashing
RouterKey = "slashing"
RouterKey = ModuleName

// QuerierRoute is the querier route for slashing
QuerierRoute = "slashing"
QuerierRoute = ModuleName
)

// key prefix bytes
Expand Down
Loading

0 comments on commit 38068a5

Please sign in to comment.