Skip to content

Commit

Permalink
change val's consensus pubkey
Browse files Browse the repository at this point in the history
  • Loading branch information
ylsGit committed Jul 7, 2024
1 parent 09bd020 commit a2826ac
Show file tree
Hide file tree
Showing 15 changed files with 147 additions and 23 deletions.
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
}

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())
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
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
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

0 comments on commit a2826ac

Please sign in to comment.