Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

change val's consensus pubkey #3312

Open
wants to merge 15 commits into
base: dev
Choose a base branch
from
5 changes: 5 additions & 0 deletions x/distribution/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
"github.com/okex/exchain/libs/tendermint/crypto"

"github.com/okex/exchain/x/distribution/types"
stakingtypes "github.com/okex/exchain/x/staking/types"
Expand All @@ -23,6 +24,10 @@ func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.k.initializeValidator(ctx, val)
}

func (h Hooks) AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey) {

}

// AfterValidatorRemoved cleans up for after validator is removed
func (h Hooks) AfterValidatorRemoved(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) {
if h.k.CheckDistributionProposalValid(ctx) {
Expand Down
14 changes: 14 additions & 0 deletions x/slashing/internal/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ func (k Keeper) AfterValidatorRemoved(ctx sdk.Context, address sdk.ConsAddress)
k.modifyValidatorStatus(ctx, address, types.Destroyed)
}

func (k Keeper) AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey) {
k.deleteAddrPubkeyRelation(ctx, crypto.Address(oldAddress))
signingInfo, found := k.GetValidatorSigningInfo(ctx, oldAddress)
k.modifyValidatorStatus(ctx, oldAddress, types.Destroyed)

k.AddPubkey(ctx, newPubkey)
if found {
k.SetValidatorSigningInfo(ctx, newAddress, signingInfo)
}
}

func (k Keeper) AfterValidatorDestroyed(ctx sdk.Context, valAddr sdk.ValAddress) {
validator := k.sk.Validator(ctx, valAddr)
if validator != nil {
Expand Down Expand Up @@ -76,6 +87,9 @@ func (h Hooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
h.k.AfterValidatorCreated(ctx, valAddr)
}

func (h Hooks) AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey) {
h.k.AfterValidatorPubkeyChanged(ctx, oldAddress, newAddress, newPubkey)
}
func (h Hooks) AfterValidatorDestroyed(ctx sdk.Context, _ sdk.ConsAddress, valAddr sdk.ValAddress) {
h.k.AfterValidatorDestroyed(ctx, valAddr)
}
Expand Down
3 changes: 2 additions & 1 deletion x/slashing/internal/keeper/infractions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ func (k Keeper) HandleValidatorSignature(ctx sdk.Context, addr crypto.Address, p
// fetch the validator public key
consAddr := sdk.ConsAddress(addr)
if _, err := k.GetPubkey(ctx, addr); err != nil {
panic(fmt.Sprintf("Validator consensus-address %s not found", consAddr))
// ignore this panic, now we can change the validator's pub key
//panic(fmt.Sprintf("Validator consensus-address %s not found", consAddr))
}

// fetch signing info
Expand Down
1 change: 1 addition & 0 deletions x/staking/alias.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ var (
RegisterCodec = types.RegisterCodec
NewCommission = types.NewCommission
ErrNoValidatorFound = types.ErrNoValidatorFound
ErrPubkeyEqual = types.ErrPubkeyEqual
ErrValidatorOwnerExists = types.ErrValidatorOwnerExists
ErrValidatorPubKeyExists = types.ErrValidatorPubKeyExists
ErrValidatorPubKeyTypeNotSupported = types.ErrValidatorPubKeyTypeNotSupported
Expand Down
23 changes: 17 additions & 6 deletions x/staking/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,16 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
Details: viper.GetString(FlagDetails),
}

pkStr := viper.GetString(FlagPubKey)
var pk crypto.PubKey = nil
var err error
if pkStr != "" {
pk, err = types.GetConsPubKeyBech32(pkStr)
if err != nil {
return err
}
}

// TODO: recover the msd modification later
//var newMinSelfDelegation *sdk.Int
//
Expand All @@ -122,14 +132,15 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
//}
//
//msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate, newMinSelfDelegation)
msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description)
msg := types.NewMsgEditValidator(sdk.ValAddress(valAddr), description, pk)

// build and sign the transaction, then broadcast to Tendermint
return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg})
},
}

cmd.Flags().AddFlagSet(fsDescriptionEdit)
cmd.Flags().String(FlagPubKey, "", "The Bech32 encoded PubKey of the validator")
//cmd.Flags().AddFlagSet(fsCommissionUpdate)

return cmd
Expand All @@ -138,11 +149,11 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
//__________________________________________________________

var (
//defaultTokens = sdk.TokensFromConsensusPower(100)
//defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom
//defaultCommissionRate = "0.1"
//defaultCommissionMaxRate = "0.2"
//defaultCommissionMaxChangeRate = "0.01"
// defaultTokens = sdk.TokensFromConsensusPower(100)
// defaultAmount = defaultTokens.String() + sdk.DefaultBondDenom
// defaultCommissionRate = "0.1"
// defaultCommissionMaxRate = "0.2"
// defaultCommissionMaxChangeRate = "0.01"
)

// CreateValidatorMsgHelpers returns the flagset, particular flags, and a description of defaults
Expand Down
31 changes: 23 additions & 8 deletions x/staking/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -165,15 +165,30 @@ func handleMsgEditValidator(ctx sdk.Context, msg types.MsgEditValidator, k keepe
return nil, ErrNoValidatorFound(msg.ValidatorAddress.String())
}

// replace all editable fields (clients should autofill existing values)
description, err := validator.Description.UpdateDescription(msg.Description)
if err != nil {
return nil, err
}

validator.Description = description
if msg.Description != (Description{}) {
// replace all editable fields (clients should autofill existing values)
description, err := validator.Description.UpdateDescription(msg.Description)
if err != nil {
return nil, err
}

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggest add height to upgrade

k.SetValidator(ctx, validator)
validator.Description = description
k.SetValidator(ctx, validator)
}
if msg.PubKey != nil && len(msg.PubKey.Bytes()) != 0 {
if validator.ConsPubKey.Equals(msg.PubKey) {
return nil, ErrPubkeyEqual(msg.PubKey.Address().String())
}
k.SetChangePubkey(ctx, validator.OperatorAddress, validator.GetConsPubKey())
ylsGit marked this conversation as resolved.
Show resolved Hide resolved
oldConsAddr := validator.GetConsAddr()

validator.ConsPubKey = msg.PubKey
newConsAddr := validator.GetConsAddr()
k.SetValidator(ctx, validator)
k.SetValidatorByConsAddr(ctx, validator)
k.DeleteValidatorByConsAddr(ctx, oldConsAddr)
k.AfterValidatorPubkeyChanged(ctx, oldConsAddr, newConsAddr, msg.PubKey)
}

ctx.EventManager().EmitEvents(sdk.Events{
sdk.NewEvent(types.EventTypeEditValidator,
Expand Down
2 changes: 1 addition & 1 deletion x/staking/handler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func TestEditValidatorDecreaseMinSelfDelegation(t *testing.T) {
SharesFromDefaultMSD, false)

// edit validator
msgEditValidator := NewMsgEditValidator(validatorAddr, Description{Moniker: "moniker"})
msgEditValidator := NewMsgEditValidator(validatorAddr, Description{Moniker: "moniker"}, nil)
require.Nil(t, msgEditValidator.ValidateBasic())

// no one could change msd
Expand Down
7 changes: 7 additions & 0 deletions x/staking/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
"github.com/okex/exchain/libs/tendermint/crypto"
"github.com/okex/exchain/x/staking/types"
)

Expand All @@ -15,6 +16,12 @@ func (k Keeper) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {
}
}

func (k Keeper) AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey) {
if k.hooks != nil {
k.hooks.AfterValidatorPubkeyChanged(ctx, oldAddress, newAddress, newPubkey)
}
}

// BeforeValidatorModified - call hook if registered
func (k Keeper) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
if k.hooks != nil {
Expand Down
6 changes: 4 additions & 2 deletions x/staking/keeper/test_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -315,8 +315,10 @@ func SimpleCheckValidator(t *testing.T, ctx sdk.Context, stkKeeper Keeper, vaAdd
// mockDistributionKeeper is supported to test Hooks
type mockDistributionKeeper struct{}

func (dk mockDistributionKeeper) Hooks() types.StakingHooks { return dk }
func (dk mockDistributionKeeper) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {}
func (dk mockDistributionKeeper) Hooks() types.StakingHooks { return dk }
func (dk mockDistributionKeeper) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress) {}
func (dk mockDistributionKeeper) AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey) {
}
func (dk mockDistributionKeeper) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {}
func (dk mockDistributionKeeper) AfterValidatorRemoved(ctx sdk.Context, consAddr sdk.ConsAddress, valAddr sdk.ValAddress) {
}
Expand Down
10 changes: 10 additions & 0 deletions x/staking/keeper/val_state_change.go
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx sdk.Context) (updates []ab
k.SetLastValidatorPower(ctx, valAddr, newPower)
}

// change val node key
ylsGit marked this conversation as resolved.
Show resolved Hide resolved
if pk, found := k.GetChangePubkey(ctx, validator.OperatorAddress); found {
oldVal := types.Validator{ConsPubKey: pk}
// delete old pubkey
updates = append(updates, oldVal.ABCIValidatorUpdateZero())
// add new pubkey
updates = append(updates, validator.ABCIValidatorUpdateByShares())
k.DeleteChangePubkey(ctx, validator.OperatorAddress)
}

// validator still in the validator set, so delete from the copy
delete(last, valAddrBytes)

Expand Down
30 changes: 30 additions & 0 deletions x/staking/keeper/validator.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package keeper
import (
"bytes"
"fmt"
"github.com/okex/exchain/libs/tendermint/crypto"
cryptoAmino "github.com/okex/exchain/libs/tendermint/crypto/encoding/amino"
"time"

sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
Expand Down Expand Up @@ -54,13 +56,41 @@ func (k Keeper) SetValidator(ctx sdk.Context, validator types.Validator) {
store.Set(types.GetValidatorKey(validator.OperatorAddress), bz)
}

func (k Keeper) SetChangePubkey(ctx sdk.Context, addr sdk.ValAddress, pubkey crypto.PubKey) {
store := ctx.KVStore(k.storeKey)
store.Set(types.GetValidatorChangePubkeyKey(addr), pubkey.Bytes())
}

func (k Keeper) DeleteChangePubkey(ctx sdk.Context, addr sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.GetValidatorChangePubkeyKey(addr))
}

func (k Keeper) GetChangePubkey(ctx sdk.Context, addr sdk.ValAddress) (pubkey crypto.PubKey, found bool) {
store := ctx.KVStore(k.storeKey)
value := store.Get(types.GetValidatorChangePubkeyKey(addr))
if value == nil {
return nil, false
}
pk, err := cryptoAmino.PubKeyFromBytes(value)
if err != nil {
panic(err)
}
return pk, true
}

// SetValidatorByConsAddr sets the operator address with the key of validator consensus pubkey
func (k Keeper) SetValidatorByConsAddr(ctx sdk.Context, validator types.Validator) {
store := ctx.KVStore(k.storeKey)
consAddr := sdk.ConsAddress(validator.ConsPubKey.Address())
store.Set(types.GetValidatorByConsAddrKey(consAddr), validator.OperatorAddress)
}

func (k Keeper) DeleteValidatorByConsAddr(ctx sdk.Context, consAddr sdk.ConsAddress) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.GetValidatorByConsAddrKey(consAddr))
}

// SetValidatorByPowerIndex sets the power index key of an unjailed validator
func (k Keeper) SetValidatorByPowerIndex(ctx sdk.Context, validator types.Validator) {
// jailed validators are not kept in the power index
Expand Down
16 changes: 14 additions & 2 deletions x/staking/types/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,17 +58,29 @@ const (
CodeNoDelegatorExisted uint32 = 67044
CodeTargetValsDuplicate uint32 = 67045
CodeAlreadyBound uint32 = 67046

CodePubkeyEqual uint32 = 67047
CodeDescriptionAndPubkeyIsEmpty uint32 = 67048
)

var (
ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 144, "invalid historical info")
ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 145, "no historical info found")
ErrInvalidHistoricalInfo = sdkerrors.Register(ModuleName, 144, "invalid historical info")
ErrNoHistoricalInfo = sdkerrors.Register(ModuleName, 145, "no historical info found")
)

// ErrNoValidatorFound returns an error when a validator doesn't exist
func ErrNoValidatorFound(valAddr string) sdk.EnvelopedErr {
return sdk.EnvelopedErr{Err: sdkerrors.New(DefaultCodespace, CodeNoValidatorFound, fmt.Sprintf("validator %s does not exist", valAddr))}
}

func ErrPubkeyEqual(pubkey string) sdk.EnvelopedErr {
return sdk.EnvelopedErr{Err: sdkerrors.New(DefaultCodespace, CodePubkeyEqual, fmt.Sprintf("validator pubkey %s does exist", pubkey))}
}

func ErrDescriptionAndPubkeyIsEmpty() sdk.Error {
return sdkerrors.New(DefaultCodespace, CodeDescriptionAndPubkeyIsEmpty, "empty description and pubkey")
}

// ErrInvalidDelegation returns an error when the delegation is invalid
func ErrInvalidDelegation(delegator string) sdk.EnvelopedErr {
return sdk.EnvelopedErr{Err: sdkerrors.New(DefaultCodespace, CodeInvalidDelegation,
Expand Down
2 changes: 2 additions & 0 deletions x/staking/types/expected_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
authexported "github.com/okex/exchain/libs/cosmos-sdk/x/auth/exported"
supplyexported "github.com/okex/exchain/libs/cosmos-sdk/x/supply/exported"
"github.com/okex/exchain/libs/tendermint/crypto"
stakingexported "github.com/okex/exchain/x/staking/exported"
)

Expand Down Expand Up @@ -74,6 +75,7 @@ type ValidatorSet interface {
type StakingHooks interface {
// Must be called when a validator is created
AfterValidatorCreated(ctx sdk.Context, valAddr sdk.ValAddress)
AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey)
// Must be called when a validator's state changes
BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress)
// Must be called when a validator is deleted
Expand Down
7 changes: 7 additions & 0 deletions x/staking/types/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package types

import (
sdk "github.com/okex/exchain/libs/cosmos-sdk/types"
"github.com/okex/exchain/libs/tendermint/crypto"
)

// MultiStakingHooks combines multiple staking hooks, all hook functions are run in array sequence
Expand All @@ -20,6 +21,12 @@ func (h MultiStakingHooks) AfterValidatorCreated(ctx sdk.Context, valAddr sdk.Va
}
}

func (h MultiStakingHooks) AfterValidatorPubkeyChanged(ctx sdk.Context, oldAddress sdk.ConsAddress, newAddress sdk.ConsAddress, newPubkey crypto.PubKey) {
for i := range h {
h[i].AfterValidatorPubkeyChanged(ctx, oldAddress, newAddress, newPubkey)
}
}

// BeforeValidatorModified handles the hooks before the validator modified
func (h MultiStakingHooks) BeforeValidatorModified(ctx sdk.Context, valAddr sdk.ValAddress) {
for i := range h {
Expand Down
7 changes: 6 additions & 1 deletion x/staking/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const (
RouterKey = ModuleName
)

//nolint
// nolint
var (
// Keys for store prefixes
// Last* values are constant during a block.
Expand All @@ -40,6 +40,7 @@ var (
ValidatorsKey = []byte{0x21} // prefix for each key to a validator
ValidatorsByConsAddrKey = []byte{0x22} // prefix for each key to a validator index, by pubkey
ValidatorsByPowerIndexKey = []byte{0x23} // prefix for each key to a validator index, sorted by power
ValChangePubkeyKey = []byte{0x24}

ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue

Expand Down Expand Up @@ -67,6 +68,10 @@ func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte {
return append(ValidatorsByConsAddrKey, addr.Bytes()...)
}

func GetValidatorChangePubkeyKey(operatorAddr sdk.ValAddress) []byte {
return append(ValChangePubkeyKey, operatorAddr.Bytes()...)
}

// AddressFromLastValidatorPowerKey gets the validator operator address from LastValidatorPowerKey
func AddressFromLastValidatorPowerKey(key []byte) []byte {
return key[1:] // remove prefix bytes
Expand Down
8 changes: 5 additions & 3 deletions x/staking/types/msg.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,13 +132,15 @@ func (msg MsgCreateValidator) ValidateBasic() error {
type MsgEditValidator struct {
Description
ValidatorAddress sdk.ValAddress `json:"address" yaml:"address"`
PubKey crypto.PubKey `json:"pubkey" yaml:"pubkey"`
}

// NewMsgEditValidator creates a msg of edit-validator
func NewMsgEditValidator(valAddr sdk.ValAddress, description Description) MsgEditValidator {
func NewMsgEditValidator(valAddr sdk.ValAddress, description Description, pubKey crypto.PubKey) MsgEditValidator {
return MsgEditValidator{
Description: description,
ValidatorAddress: valAddr,
PubKey: pubKey,
}
}

Expand All @@ -161,8 +163,8 @@ func (msg MsgEditValidator) ValidateBasic() error {
return ErrNilValidatorAddr()
}

if msg.Description == (Description{}) {
return ErrNilValidatorAddr()
if msg.Description == (Description{}) && (msg.PubKey == nil || len(msg.PubKey.Bytes()) == 0) {
return ErrDescriptionAndPubkeyIsEmpty()
}

return nil
Expand Down
2 changes: 1 addition & 1 deletion x/staking/types/msg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func TestMsgEditValidator(t *testing.T) {

for _, tc := range tests {
description := NewDescription(tc.moniker, tc.identity, tc.website, tc.details)
msg := NewMsgEditValidator(tc.validatorAddr, description)
msg := NewMsgEditValidator(tc.validatorAddr, description, nil)
if tc.expectPass {
require.Nil(t, msg.ValidateBasic(), "test: %v", tc.name)
checkMsg(t, msg, "edit_validator")
Expand Down
Loading