From e4b0d0a618524d3040788b1d9cb8b3c33753a4c4 Mon Sep 17 00:00:00 2001 From: Christopher Goes Date: Mon, 28 May 2018 21:38:02 +0200 Subject: [PATCH] Reorganization in progress --- cmd/gaia/app/app.go | 1 + types/stake.go | 3 ++- x/slashing/errors.go | 19 +++++++++++++++++ x/slashing/handler.go | 42 ++++++++++++++++++++++++++++++++++++ x/slashing/keeper.go | 2 +- x/slashing/keeper_test.go | 5 +++-- x/slashing/msg.go | 45 +++++++++++++++++++++++++++++++++++++++ x/slashing/wire.go | 12 +++++++++++ x/stake/errors.go | 5 ----- x/stake/handler.go | 25 ---------------------- x/stake/keeper.go | 22 ++++++++++++++----- x/stake/msg.go | 34 ----------------------------- x/stake/validator.go | 8 +++---- x/stake/wire.go | 1 - 14 files changed, 145 insertions(+), 79 deletions(-) create mode 100644 x/slashing/handler.go create mode 100644 x/slashing/msg.go create mode 100644 x/slashing/wire.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 28904e1ac9..4fdb6a6c92 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -103,6 +103,7 @@ func MakeCodec() *wire.Codec { ibc.RegisterWire(cdc) bank.RegisterWire(cdc) stake.RegisterWire(cdc) + slashing.RegisterWire(cdc) auth.RegisterWire(cdc) sdk.RegisterWire(cdc) wire.RegisterCrypto(cdc) diff --git a/types/stake.go b/types/stake.go index fed241d014..a52dc9b071 100644 --- a/types/stake.go +++ b/types/stake.go @@ -46,7 +46,8 @@ type ValidatorSet interface { ValidatorByPubKey(Context, crypto.PubKey) Validator // get a particular validator by public key TotalPower(Context) Rat // total power of the validator set Slash(Context, crypto.PubKey, int64, Rat) // slash the validator and delegators of the validator, specifying offence height & slash fraction - ForceUnbond(Context, crypto.PubKey, int64) // force unbond the validator, including a duration which must pass before they can rebond + Revoke(Context, crypto.PubKey) // revoke a validator + Unrevoke(Context, crypto.PubKey) // unrevoke a validator } //_______________________________________________________________________________ diff --git a/x/slashing/errors.go b/x/slashing/errors.go index bf57c337d7..f61eff17e5 100644 --- a/x/slashing/errors.go +++ b/x/slashing/errors.go @@ -10,10 +10,29 @@ type CodeType = sdk.CodeType const ( // Default slashing codespace DefaultCodespace sdk.CodespaceType = 10 + + // Invalid validator + CodeInvalidValidator CodeType = 201 + // Validator jailed + CodeValidatorJailed CodeType = 202 ) +func ErrNoValidatorForAddress(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "That address is not associated with any known validator") +} +func ErrBadValidatorAddr(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeInvalidValidator, "Validator does not exist for that address") +} +func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { + return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") +} + func codeToDefaultMsg(code CodeType) string { switch code { + case CodeInvalidValidator: + return "Invalid Validator" + case CodeValidatorJailed: + return "Validator Jailed" default: return sdk.CodeToDefaultMsg(code) } diff --git a/x/slashing/handler.go b/x/slashing/handler.go new file mode 100644 index 0000000000..931ef58465 --- /dev/null +++ b/x/slashing/handler.go @@ -0,0 +1,42 @@ +package slashing + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +func NewHandler(k Keeper) sdk.Handler { + return func(ctx sdk.Context, msg sdk.Msg) sdk.Result { + // NOTE msg already has validate basic run + switch msg := msg.(type) { + case MsgUnrevoke: + return handleMsgUnrevoke(ctx, msg, k) + default: + return sdk.ErrTxDecode("invalid message parse in staking module").Result() + } + } +} + +func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { + validator := k.stakeKeeper.Validator(ctx, msg.ValidatorAddr) + if validator == nil { + return ErrNoValidatorForAddress(k.codespace).Result() + } + + // TODO + /* + if ctx.BlockHeader().Time < validator.RevokedUntilTime { + return ErrValidatorJailed(k.codespace).Result() + } + */ + + if ctx.IsCheckTx() { + return sdk.Result{} + } + + k.stakeKeeper.Unrevoke(ctx, validator.GetPubKey()) + + tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) + return sdk.Result{ + Tags: tags, + } +} diff --git a/x/slashing/keeper.go b/x/slashing/keeper.go index 87016b18f2..918e85c2a3 100644 --- a/x/slashing/keeper.go +++ b/x/slashing/keeper.go @@ -99,7 +99,7 @@ func (k Keeper) handleValidatorSignature(ctx sdk.Context, pubkey crypto.PubKey, if height > minHeight && signInfo.SignedBlocksCounter < MinSignedPerWindow { logger.Info(fmt.Sprintf("Validator %s past min height of %d and below signed blocks threshold of %d", pubkey.Address(), minHeight, MinSignedPerWindow)) k.stakeKeeper.Slash(ctx, pubkey, height, SlashFractionDowntime) - k.stakeKeeper.ForceUnbond(ctx, pubkey, DowntimeUnbondDuration) // TODO + k.stakeKeeper.Revoke(ctx, pubkey) // , DowntimeUnbondDuration) // TODO } } diff --git a/x/slashing/keeper_test.go b/x/slashing/keeper_test.go index 895be24e1b..9598b24f3c 100644 --- a/x/slashing/keeper_test.go +++ b/x/slashing/keeper_test.go @@ -89,6 +89,7 @@ func TestHandleAbsentValidator(t *testing.T) { ctx, ck, sk, keeper := createTestInput(t) addr, val, amt := addrs[0], pks[0], int64(100) sh := stake.NewHandler(sk) + slh := NewHandler(keeper) got := sh(ctx, newTestMsgDeclareCandidacy(addr, val, amt)) require.True(t, got.IsOK()) _ = sk.Tick(ctx) @@ -133,10 +134,10 @@ func TestHandleAbsentValidator(t *testing.T) { // should have been revoked validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Unbonded, validator.GetStatus()) - got = sh(ctx, stake.NewMsgUnrevoke(addr)) + got = slh(ctx, NewMsgUnrevoke(addr)) require.False(t, got.IsOK()) // should fail prior to jail expiration ctx = ctx.WithBlockHeader(abci.Header{Time: int64(86400 * 2)}) - got = sh(ctx, stake.NewMsgUnrevoke(addr)) + got = slh(ctx, NewMsgUnrevoke(addr)) require.True(t, got.IsOK()) // should succeed after jail expiration validator = sk.ValidatorByPubKey(ctx, val) require.Equal(t, sdk.Bonded, validator.GetStatus()) diff --git a/x/slashing/msg.go b/x/slashing/msg.go new file mode 100644 index 0000000000..d67ddf70df --- /dev/null +++ b/x/slashing/msg.go @@ -0,0 +1,45 @@ +package slashing + +import ( + "encoding/json" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// name to identify transaction types +const MsgType = "slashing" + +// verify interface at compile time +var _ sdk.Msg = &MsgUnrevoke{} + +// MsgUnrevoke - struct for unrevoking revoked validator +type MsgUnrevoke struct { + ValidatorAddr sdk.Address `json:"address"` +} + +func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { + return MsgUnrevoke{ + ValidatorAddr: validatorAddr, + } +} + +//nolint +func (msg MsgUnrevoke) Type() string { return MsgType } +func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } + +// get the bytes for the message signer to sign on +func (msg MsgUnrevoke) GetSignBytes() []byte { + b, err := json.Marshal(msg) + if err != nil { + panic(err) + } + return b +} + +// quick validity check +func (msg MsgUnrevoke) ValidateBasic() sdk.Error { + if msg.ValidatorAddr == nil { + return ErrBadValidatorAddr(DefaultCodespace) + } + return nil +} diff --git a/x/slashing/wire.go b/x/slashing/wire.go new file mode 100644 index 0000000000..465a06587e --- /dev/null +++ b/x/slashing/wire.go @@ -0,0 +1,12 @@ +package slashing + +import ( + "github.com/cosmos/cosmos-sdk/wire" +) + +// Register concrete types on wire codec +func RegisterWire(cdc *wire.Codec) { + cdc.RegisterConcrete(MsgUnrevoke{}, "cosmos-sdk/MsgUnrevoke", nil) +} + +var cdcEmpty = wire.NewCodec() diff --git a/x/stake/errors.go b/x/stake/errors.go index 2664a56cad..77090d9dc3 100644 --- a/x/stake/errors.go +++ b/x/stake/errors.go @@ -31,8 +31,6 @@ func codeToDefaultMsg(code CodeType) string { return "Invalid Bond" case CodeInvalidInput: return "Invalid Input" - case CodeValidatorJailed: - return "Validator Jailed" case CodeUnauthorized: return "Unauthorized" case CodeInternal: @@ -101,9 +99,6 @@ func ErrBadShares(codespace sdk.CodespaceType) sdk.Error { func ErrBadRemoveValidator(codespace sdk.CodespaceType) sdk.Error { return newError(codespace, CodeInvalidValidator, "Error removing validator") } -func ErrValidatorJailed(codespace sdk.CodespaceType) sdk.Error { - return newError(codespace, CodeValidatorJailed, "Validator jailed, cannot yet be unrevoked") -} //---------------------------------------- diff --git a/x/stake/handler.go b/x/stake/handler.go index 62c4f27df4..53653557cc 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -19,8 +19,6 @@ func NewHandler(k Keeper) sdk.Handler { return handleMsgDelegate(ctx, msg, k) case MsgUnbond: return handleMsgUnbond(ctx, msg, k) - case MsgUnrevoke: - return handleMsgUnrevoke(ctx, msg, k) default: return sdk.ErrTxDecode("invalid message parse in staking module").Result() } @@ -249,26 +247,3 @@ func handleMsgUnbond(ctx sdk.Context, msg MsgUnbond, k Keeper) sdk.Result { Tags: tags, } } - -func handleMsgUnrevoke(ctx sdk.Context, msg MsgUnrevoke, k Keeper) sdk.Result { - validator, found := k.GetValidator(ctx, msg.ValidatorAddr) - if !found { - return ErrNoValidatorForAddress(k.codespace).Result() - } - - if ctx.BlockHeader().Time < validator.RevokedUntilTime { - return ErrValidatorJailed(k.codespace).Result() - } - - if ctx.IsCheckTx() { - return sdk.Result{} - } - - validator.Revoked = false - k.updateValidator(ctx, validator) - - tags := sdk.NewTags("action", []byte("unrevoke"), "validator", msg.ValidatorAddr.Bytes()) - return sdk.Result{ - Tags: tags, - } -} diff --git a/x/stake/keeper.go b/x/stake/keeper.go index e8ac6947c8..aba118ed5a 100644 --- a/x/stake/keeper.go +++ b/x/stake/keeper.go @@ -794,8 +794,8 @@ func (k Keeper) Slash(ctx sdk.Context, pubkey crypto.PubKey, height int64, fract return } -// force unbond a validator -func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration int64) { +// revoke a validator +func (k Keeper) Revoke(ctx sdk.Context, pubkey crypto.PubKey) { logger := ctx.Logger().With("module", "x/stake") val, found := k.GetValidatorByPubKey(ctx, pubkey) if !found { @@ -803,9 +803,21 @@ func (k Keeper) ForceUnbond(ctx sdk.Context, pubkey crypto.PubKey, jailDuration return } val.Revoked = true - val.RevokedUntilTime = ctx.BlockHeader().Time + jailDuration k.updateValidator(ctx, val) // update the validator, now revoked - val, _ = k.GetValidatorByPubKey(ctx, pubkey) - logger.Info(fmt.Sprintf("Validator %s revoked for minimum duration %d", pubkey.Address(), jailDuration)) + logger.Info(fmt.Sprintf("Validator %s revoked", pubkey.Address())) + return +} + +// unrevoke a validator +func (k Keeper) Unrevoke(ctx sdk.Context, pubkey crypto.PubKey) { + logger := ctx.Logger().With("module", "x/stake") + val, found := k.GetValidatorByPubKey(ctx, pubkey) + if !found { + ctx.Logger().Info("Validator with pubkey %s not found, cannot force unbond", pubkey) + return + } + val.Revoked = false + k.updateValidator(ctx, val) // update the validator, now unrevoked + logger.Info(fmt.Sprintf("Validator %s unrevoked", pubkey.Address())) return } diff --git a/x/stake/msg.go b/x/stake/msg.go index c0fdb4e5a1..0adff84d9b 100644 --- a/x/stake/msg.go +++ b/x/stake/msg.go @@ -209,37 +209,3 @@ func (msg MsgUnbond) ValidateBasic() sdk.Error { } return nil } - -//______________________________________________________________________ - -// MsgUnrevoke - struct for unrevoking revoked validator -type MsgUnrevoke struct { - ValidatorAddr sdk.Address `json:"address"` -} - -func NewMsgUnrevoke(validatorAddr sdk.Address) MsgUnrevoke { - return MsgUnrevoke{ - ValidatorAddr: validatorAddr, - } -} - -//nolint -func (msg MsgUnrevoke) Type() string { return MsgType } -func (msg MsgUnrevoke) GetSigners() []sdk.Address { return []sdk.Address{msg.ValidatorAddr} } - -// get the bytes for the message signer to sign on -func (msg MsgUnrevoke) GetSignBytes() []byte { - b, err := json.Marshal(msg) - if err != nil { - panic(err) - } - return b -} - -// quick validity check -func (msg MsgUnrevoke) ValidateBasic() sdk.Error { - if msg.ValidatorAddr == nil { - return ErrBadValidatorAddr(DefaultCodespace) - } - return nil -} diff --git a/x/stake/validator.go b/x/stake/validator.go index 76905212f1..20f5710569 100644 --- a/x/stake/validator.go +++ b/x/stake/validator.go @@ -17,10 +17,9 @@ import ( // exchange rate. Voting power can be calculated as total bonds multiplied by // exchange rate. type Validator struct { - Owner sdk.Address `json:"owner"` // sender of BondTx - UnbondTx returns here - PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator - Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? - RevokedUntilTime int64 `json:"revoked_until_time"` // timestamp before which the validator cannot unrevoke + Owner sdk.Address `json:"owner"` // sender of BondTx - UnbondTx returns here + PubKey crypto.PubKey `json:"pub_key"` // pubkey of validator + Revoked bool `json:"revoked"` // has the validator been revoked from bonded status? PoolShares PoolShares `json:"pool_shares"` // total shares for tokens held in the pool DelegatorShares sdk.Rat `json:"delegator_shares"` // total shares issued to a validator's delegators @@ -48,7 +47,6 @@ func NewValidator(owner sdk.Address, pubKey crypto.PubKey, description Descripti Owner: owner, PubKey: pubKey, Revoked: false, - RevokedUntilTime: int64(0), PoolShares: NewUnbondedShares(sdk.ZeroRat()), DelegatorShares: sdk.ZeroRat(), Description: description, diff --git a/x/stake/wire.go b/x/stake/wire.go index ac382ff14d..6e6e382606 100644 --- a/x/stake/wire.go +++ b/x/stake/wire.go @@ -10,7 +10,6 @@ func RegisterWire(cdc *wire.Codec) { cdc.RegisterConcrete(MsgEditCandidacy{}, "cosmos-sdk/MsgEditCandidacy", nil) cdc.RegisterConcrete(MsgDelegate{}, "cosmos-sdk/MsgDelegate", nil) cdc.RegisterConcrete(MsgUnbond{}, "cosmos-sdk/MsgUnbond", nil) - cdc.RegisterConcrete(MsgUnrevoke{}, "cosmos-sdk/MsgUnrevoke", nil) } var cdcEmpty = wire.NewCodec()