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

Consensus key rotation #2

Open
wants to merge 24 commits into
base: latest_sdk
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e9515c3
update protobuf for msg
icafa Apr 21, 2022
d8af2bb
Merge branch 'latest_sdk' of github.com:iqlusioninc/cosmos-sdk into c…
icafa May 18, 2022
5eec48c
add pseudo code for consensus key rotation flow
icafa May 18, 2022
acbc3e9
add hook flow for consensus pubkey updates to make following changes …
icafa May 18, 2022
5d341dd
slashing module PerformConsensusPubKeyUpdate
icafa May 19, 2022
b705acc
generate updated proto
0xdbkey May 19, 2022
4abd99e
resolve build errors on ConsPubKeyRotationHistory and AfterConsensusP…
icafa May 19, 2022
9509af4
resolve few build errors for historical info store/load
icafa May 20, 2022
b77c92d
push generated proto code
0xdbkey May 20, 2022
8ee352d
implement further logic for msg server
icafa May 20, 2022
16391fd
add generated proto code
0xdbkey May 20, 2022
b612dce
add hook for community pool increase
icafa May 31, 2022
168ba30
implement hook for community pool increase & resolve build errors
icafa May 31, 2022
729f08a
add cli command for rotate cons-pubkey, message utility functions add…
icafa Jun 7, 2022
a404bc3
resolve panics for unpack interfaces of pubkey, invalid use of nil va…
icafa Jun 10, 2022
ec7ea58
disable DeleteValidatorByConsAddr and RemoveValidatorSigningInfo
icafa Jun 16, 2022
0a2854d
add todo tests
icafa Jun 17, 2022
e3c172e
resolve MissedBlocks moving on consensus pubkey rotation & add test f…
icafa Jun 21, 2022
be8b314
add CLI test for consensus pubkey rotation command
icafa Jun 23, 2022
0258ef1
add test for ConsPubKeyRotationHistory set/get
icafa Jun 23, 2022
bca6ef0
add test for AfterConsensusPubKeyUpdate
icafa Jun 23, 2022
a7f18c4
add more test for validateParams
icafa Jun 27, 2022
45d5884
add test for RotateConsPubKey and resolve issues on implementation
icafa Jun 27, 2022
3eef35c
add test for validator set updates on tendermint power on consensus k…
icafa Jun 28, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,627 changes: 1,251 additions & 376 deletions api/cosmos/staking/v1beta1/staking.pulsar.go

Large diffs are not rendered by default.

1,150 changes: 1,099 additions & 51 deletions api/cosmos/staking/v1beta1/tx.pulsar.go

Large diffs are not rendered by default.

36 changes: 36 additions & 0 deletions api/cosmos/staking/v1beta1/tx_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 11 additions & 0 deletions proto/cosmos/staking/v1beta1/staking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,13 @@ message HistoricalInfo {
repeated Validator valset = 2 [(gogoproto.nullable) = false];
}

message ConsPubKeyRotationHistory {
string operator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
google.protobuf.Any old_cons_pubkey = 2 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"];
google.protobuf.Any new_cons_pubkey = 3 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"];
int64 rotated_height = 4;
}

// CommissionRates defines the initial commission rates to be used for creating
// a validator.
message CommissionRates {
Expand Down Expand Up @@ -303,6 +310,10 @@ message Params {
(gogoproto.customtype) = "github.com/cosmos/cosmos-sdk/types.Dec",
(gogoproto.nullable) = false
];
// max_cons_pub_key_rotations is maximum number of consensus pubkey rotations
uint64 max_cons_pub_key_rotations = 7;
// cons_pubkey_rotation_fee is fee to be spent when rotating validator's consensus pubkey
cosmos.base.v1beta1.Coin cons_pubkey_rotation_fee = 8 [(gogoproto.nullable) = false];
}

// DelegationResponse is equivalent to Delegation except that it contains a
Expand Down
20 changes: 15 additions & 5 deletions proto/cosmos/staking/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ service Msg {
//
// Since: cosmos-sdk 0.46
rpc CancelUnbondingDelegation(MsgCancelUnbondingDelegation) returns (MsgCancelUnbondingDelegationResponse);

rpc RotateConsPubKey(MsgRotateConsPubKey) returns (MsgRotateConsPubKeyResponse);
}

// MsgCreateValidator defines a SDK message for creating a new validator.
Expand Down Expand Up @@ -151,15 +153,23 @@ message MsgCancelUnbondingDelegation{
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// amount is always less than or equal to unbonding delegation entry balance
cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
string delegator_address = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
// amount is always less than or equal to unbonding delegation entry balance
cosmos.base.v1beta1.Coin amount = 3 [(gogoproto.nullable) = false];
// creation_height is the height which the unbonding took place.
int64 creation_height = 4;
}

// MsgCancelUnbondingDelegationResponse
//
// Since: cosmos-sdk 0.46
message MsgCancelUnbondingDelegationResponse{}
message MsgCancelUnbondingDelegationResponse {}

message MsgRotateConsPubKey {
string sender = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
google.protobuf.Any new_pub_key = 3 [(cosmos_proto.accepts_interface) = "cosmos.crypto.PubKey"];
}

message MsgRotateConsPubKeyResponse {}
16 changes: 16 additions & 0 deletions startnode.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
#!/bin/sh

rm -rf $HOME/.simd

set -o errexit -o nounset

simd init --chain-id test test --home=$HOME/.simd
simd keys add validator --keyring-backend="test" --home=$HOME/.simd
simd add-genesis-account $(simd keys show validator -a --keyring-backend="test" --home=$HOME/.simd) 100000000000000stake --home=$HOME/.simd
simd gentx validator 100000000stake --keyring-backend="test" --chain-id test --home=$HOME/.simd
simd collect-gentxs --home=$HOME/.simd

# Start node
simd start --pruning=nothing --home=$HOME/.simd --mode=validator

# simd tx staking rotate-cons-pubkey --home=$HOME/.simd --chain-id=test --keyring-backend=test --from=validator --pubkey='{"@type":"/cosmos.crypto.ed25519.PubKey","key":"/bjz9vxsyxzyTiGjG289dBn/4G4Bu6U1pI1dL17MbIY="}' -y --broadcast-mode=block
1 change: 1 addition & 0 deletions validator/node_key.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"id":"fa8cc8ac4f99accdb0c8a7b6245cbe1aa4721425","priv_key":{"type":"tendermint/PrivKeyEd25519","value":"Gzrgsin0NNXi8aeE5mmPs7agxIli3IBkRRCMRZMANlZEQFv/5HW36SrNyz+VKYODqq2PijruXiEPPLpJUpAPgw=="}}
11 changes: 11 additions & 0 deletions validator/priv_validator_key.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"address": "51CCD98D491829A4F0C9DA2DC38030BC72954FEA",
"pub_key": {
"type": "tendermint/PubKeyEd25519",
"value": "/bjz9vxsyxzyTiGjG289dBn/4G4Bu6U1pI1dL17MbIY="
},
"priv_key": {
"type": "tendermint/PrivKeyEd25519",
"value": "aGpgq75JHCIEBYCTFKULAijfu8YT8E5gLZQRI/upAf79uPP2/GzLHPJOIaMbbz10Gf/gbgG7pTWkjV0vXsxshg=="
}
}
1 change: 1 addition & 0 deletions validator/pubKey.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"@type":"/cosmos.crypto.ed25519.PubKey","key":"/bjz9vxsyxzyTiGjG289dBn/4G4Bu6U1pI1dL17MbIY="}
8 changes: 8 additions & 0 deletions x/distribution/keeper/hooks.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package keeper

import (
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/distribution/types"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
Expand Down Expand Up @@ -109,6 +110,13 @@ func (h Hooks) BeforeValidatorSlashed(ctx sdk.Context, valAddr sdk.ValAddress, f
return nil
}

func (h Hooks) AfterConsensusPubKeyUpdate(ctx sdk.Context, oldPubKey cryptotypes.PubKey, newPubKey cryptotypes.PubKey, rotationFee sdk.Coin) error {
feePool := h.k.GetFeePool(ctx)
feePool.CommunityPool = feePool.CommunityPool.Add(sdk.NewDecCoinsFromCoins(rotationFee)...)
h.k.SetFeePool(ctx, feePool)
return nil
}

func (h Hooks) BeforeValidatorModified(_ sdk.Context, _ sdk.ValAddress) error { return nil }
func (h Hooks) AfterValidatorBonded(_ sdk.Context, _ sdk.ConsAddress, _ sdk.ValAddress) error {
return nil
Expand Down
4 changes: 4 additions & 0 deletions x/slashing/keeper/hooks.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/tendermint/tendermint/crypto"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/slashing/types"
)
Expand Down Expand Up @@ -88,3 +89,6 @@ func (h Hooks) AfterDelegationModified(_ sdk.Context, _ sdk.AccAddress, _ sdk.Va
return nil
}
func (h Hooks) BeforeValidatorSlashed(_ sdk.Context, _ sdk.ValAddress, _ sdk.Dec) error { return nil }
func (h Hooks) AfterConsensusPubKeyUpdate(ctx sdk.Context, oldPubKey cryptotypes.PubKey, newPubKey cryptotypes.PubKey, rotationFee sdk.Coin) error {
return h.k.PerformConsensusPubKeyUpdate(ctx, oldPubKey, newPubKey)
}
29 changes: 29 additions & 0 deletions x/slashing/keeper/signing_info.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (

gogotypes "github.com/gogo/protobuf/types"

cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/slashing/types"
)
Expand Down Expand Up @@ -37,6 +38,12 @@ func (k Keeper) SetValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress
store.Set(types.ValidatorSigningInfoKey(address), bz)
}

// RemoveValidatorSigningInfo removes the validator signing info from a consensus address key
func (k Keeper) RemoveValidatorSigningInfo(ctx sdk.Context, address sdk.ConsAddress) {
store := ctx.KVStore(k.storeKey)
store.Delete(types.ValidatorSigningInfoKey(address))
}

// IterateValidatorSigningInfos iterates over the stored ValidatorSigningInfo
func (k Keeper) IterateValidatorSigningInfos(ctx sdk.Context,
handler func(address sdk.ConsAddress, info types.ValidatorSigningInfo) (stop bool)) {
Expand Down Expand Up @@ -156,3 +163,25 @@ func (k Keeper) clearValidatorMissedBlockBitArray(ctx sdk.Context, address sdk.C
store.Delete(iter.Key())
}
}

func (k Keeper) PerformConsensusPubKeyUpdate(ctx sdk.Context, oldPubKey cryptotypes.PubKey, newPubKey cryptotypes.PubKey) error {
// Connect new consensus address with PubKey
k.AddPubkey(ctx, newPubKey)

// Migrate ValidatorSigningInfo from oldPubKey to newPubKey
signingInfo, found := k.GetValidatorSigningInfo(ctx, sdk.ConsAddress(oldPubKey.Address()))
if !found {
return nil
}
// k.RemoveValidatorSigningInfo(ctx, sdk.ConsAddress(oldPubKey.Address()))
k.SetValidatorSigningInfo(ctx, sdk.ConsAddress(newPubKey.Address()), signingInfo)

// Migrate ValidatorMissedBlockBitArray from oldPubKey to newPubKey
missedBlocks := k.GetValidatorMissedBlocks(ctx, sdk.ConsAddress(oldPubKey.Address()))
k.clearValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(oldPubKey.Address()))
for _, missed := range missedBlocks {
k.SetValidatorMissedBlockBitArray(ctx, sdk.ConsAddress(newPubKey.Address()), missed.Index, missed.Missed)
}

return nil
}
41 changes: 41 additions & 0 deletions x/slashing/keeper/signing_info_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,3 +94,44 @@ func TestJailUntil(t *testing.T) {
require.True(t, ok)
require.Equal(t, time.Unix(253402300799, 0).UTC(), info.JailedUntil)
}

func TestPerformConsensusPubKeyUpdate(t *testing.T) {
app := simapp.Setup(t, false)
ctx := app.BaseApp.NewContext(false, tmproto.Header{})

pks := simapp.CreateTestPubKeys(2)
simapp.AddTestAddrsFromPubKeys(app, ctx, pks, app.StakingKeeper.TokensFromConsensusPower(ctx, 200))

oldConsAddr := sdk.ConsAddress(pks[0].Address())
newConsAddr := sdk.ConsAddress(pks[1].Address())
newInfo := types.NewValidatorSigningInfo(
sdk.ConsAddress(oldConsAddr),
int64(4),
int64(3),
time.Unix(2, 0).UTC(),
false,
int64(10),
)
app.SlashingKeeper.SetValidatorSigningInfo(ctx, oldConsAddr, newInfo)
app.SlashingKeeper.SetValidatorMissedBlockBitArray(ctx, oldConsAddr, 10, true)
err := app.SlashingKeeper.PerformConsensusPubKeyUpdate(ctx, pks[0], pks[1])
require.NoError(t, err)

// check pubkey relation is set properly
savedPubKey, err := app.SlashingKeeper.GetPubkey(ctx, newConsAddr.Bytes())
require.NoError(t, err)
require.Equal(t, savedPubKey, pks[1])

// check validator SigningInfo is set properly to new consensus pubkey
signingInfo, found := app.SlashingKeeper.GetValidatorSigningInfo(ctx, newConsAddr)
require.True(t, found)
require.Equal(t, signingInfo, newInfo)

// check missed blocks array is removed on old consensus pubkey
missedBlocks := app.SlashingKeeper.GetValidatorMissedBlocks(ctx, oldConsAddr)
require.Len(t, missedBlocks, 0)

// check missed blocks are set correctly for new pubkey
missedBlocks = app.SlashingKeeper.GetValidatorMissedBlocks(ctx, newConsAddr)
require.Len(t, missedBlocks, 1)
}
58 changes: 58 additions & 0 deletions x/staking/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ func NewTxCmd() *cobra.Command {
stakingTxCmd.AddCommand(
NewCreateValidatorCmd(),
NewEditValidatorCmd(),
NewRotateConsensusKeyCmd(),
NewDelegateCmd(),
NewRedelegateCmd(),
NewUnbondCmd(),
Expand Down Expand Up @@ -145,6 +146,37 @@ func NewEditValidatorCmd() *cobra.Command {
return cmd
}

func NewRotateConsensusKeyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "rotate-cons-pubkey",
Short: "rotate validator consensus pub key",
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

txf := tx.NewFactoryCLI(clientCtx, cmd.Flags()).
WithTxConfig(clientCtx.TxConfig).WithAccountRetriever(clientCtx.AccountRetriever)
txf, msg, err := newBuildRotateConsPubKeyMsg(clientCtx, txf, cmd.Flags())
if err != nil {
return err
}

return tx.GenerateOrBroadcastTxWithFactory(clientCtx, txf, msg)
},
}

cmd.Flags().AddFlagSet(FlagSetPublicKey())

flags.AddTxFlagsToCmd(cmd)

_ = cmd.MarkFlagRequired(flags.FlagFrom)
_ = cmd.MarkFlagRequired(FlagPubKey)

return cmd
}

func NewDelegateCmd() *cobra.Command {
bech32PrefixValAddr := sdk.GetConfig().GetBech32ValidatorAddrPrefix()

Expand Down Expand Up @@ -401,6 +433,32 @@ func newBuildCreateValidatorMsg(clientCtx client.Context, txf tx.Factory, fs *fl
return txf, msg, nil
}

func newBuildRotateConsPubKeyMsg(clientCtx client.Context, txf tx.Factory, fs *flag.FlagSet) (tx.Factory, *types.MsgRotateConsPubKey, error) {

valAddr := clientCtx.GetFromAddress()
pkStr, err := fs.GetString(FlagPubKey)
if err != nil {
return txf, nil, err
}

var pk cryptotypes.PubKey
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(pkStr), &pk); err != nil {
return txf, nil, err
}

msg, err := types.NewMsgRotateConsPubKey(
valAddr, sdk.ValAddress(valAddr), pk,
)
if err != nil {
return txf, nil, err
}
if err := msg.ValidateBasic(); err != nil {
return txf, nil, err
}

return txf, msg, nil
}

// Return the flagset, particular flags, and a description of defaults
// this is anticipated to be used with the gen-tx
func CreateValidatorMsgFlagSet(ipDefault string) (fs *flag.FlagSet, defaultsDesc string) {
Expand Down
Loading