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

feat(WIP) : rotate operator key #15494

Closed
wants to merge 54 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
8f6299f
proto
atheeshp Mar 14, 2023
5f978d8
make proto-gen
atheeshp Mar 14, 2023
a468a05
proto
atheeshp Mar 15, 2023
e2161b5
proto-gen
atheeshp Mar 15, 2023
8dfd0bb
proto
atheeshp Mar 16, 2023
7ec7cac
proto-gen
atheeshp Mar 16, 2023
8fed09a
WIP: operator key
atheeshp Mar 16, 2023
cff75c6
mocks
atheeshp Mar 16, 2023
bcda6c4
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/rotate_op…
atheeshp Mar 17, 2023
eb47ea3
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/rotate_op…
atheeshp Mar 18, 2023
85ab4ad
proto
atheeshp Mar 18, 2023
ed7e3ed
proto-gen
atheeshp Mar 18, 2023
239a358
set waiting period for operator key rotation
atheeshp Mar 18, 2023
9cf2bda
add delegations by validator index
atheeshp Apr 4, 2023
445b722
refactor: add delegations by validator index
atheeshp Apr 5, 2023
9b3c8b4
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 5, 2023
cc1c2ce
nits
atheeshp Apr 5, 2023
71aabc2
update validator delegations query with index
atheeshp Apr 7, 2023
b99b5e8
remove unnecessory tests
atheeshp Apr 7, 2023
dc60199
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 7, 2023
d6a4a0c
fix tests
atheeshp Apr 7, 2023
76bc044
remove unnecessary test
atheeshp Apr 7, 2023
6656c62
remove test code
atheeshp Apr 7, 2023
faa45dc
refactor
atheeshp Apr 7, 2023
f96a4b3
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 11, 2023
d3f0412
review changes
atheeshp Apr 11, 2023
213ea9a
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 12, 2023
58aa3ba
review changes
atheeshp Apr 12, 2023
b03ad16
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 12, 2023
4a1ad7f
register migration
atheeshp Apr 12, 2023
64349dd
review changes
atheeshp Apr 13, 2023
7062b56
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 14, 2023
697ee7b
keys
atheeshp Apr 14, 2023
a04740a
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 17, 2023
07ea2e5
review changes
atheeshp Apr 17, 2023
d07bc41
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 18, 2023
8308684
review changes
atheeshp Apr 18, 2023
d655db3
review changes
atheeshp Apr 18, 2023
727e273
review changes
atheeshp Apr 18, 2023
d5f5fea
fix lint
atheeshp Apr 18, 2023
9ada08c
fix lint
atheeshp Apr 18, 2023
c058798
error handling
atheeshp Apr 18, 2023
cc2ee23
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 18, 2023
0a70b08
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 20, 2023
c3a2c41
review changes
atheeshp Apr 20, 2023
45a84e9
Merge branch 'ap/delegations-by-validator' of github.com:cosmos/cosmo…
atheeshp Apr 20, 2023
be5d46e
Merge branch 'ap/delegations-by-validator' of github.com:cosmos/cosmo…
atheeshp Apr 20, 2023
fed64cc
add key updations
atheeshp Apr 20, 2023
30aa0f1
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/rotate_op…
atheeshp Apr 21, 2023
2596e00
updations
atheeshp Apr 21, 2023
066e672
proto-gen
atheeshp Apr 21, 2023
d316acf
fix
atheeshp Apr 25, 2023
43ea5dd
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/rotate_op…
atheeshp Apr 25, 2023
590d0ca
Merge branch 'ap/rotate_oper_key' of github.com:cosmos/cosmos-sdk int…
atheeshp Apr 25, 2023
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,647 changes: 1,443 additions & 204 deletions api/cosmos/staking/v1beta1/staking.pulsar.go

Large diffs are not rendered by default.

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

Large diffs are not rendered by default.

45 changes: 45 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.

27 changes: 27 additions & 0 deletions proto/cosmos/staking/v1beta1/staking.proto
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,12 @@ message Params {
(amino.dont_omitempty) = true,
(cosmos_proto.scalar) = "cosmos.Dec"
];

// key_rotation_fee is fee to be spent when rotating validator's keys(either pubkey or operator key)
cosmos.base.v1beta1.Coin key_rotation_fee = 7 [
(gogoproto.nullable) = false,
(amino.dont_omitempty) = true
];
}

// DelegationResponse is equivalent to Delegation except that it contains a
Expand Down Expand Up @@ -392,3 +398,24 @@ enum Infraction {
message ValidatorUpdates {
repeated tendermint.abci.ValidatorUpdate updates = 1 [(gogoproto.nullable) = false, (amino.dont_omitempty) = true];
}

// OperatorKeyRotationRecord contains a validator's operator key rotation history.
message OperatorKeyRotationRecord {
option (gogoproto.equal) = false;
option (gogoproto.goproto_getters) = false;

// operator_address defines the address of the validator's operator; bech encoded in JSON.
string operator_address = 1 ;

// old_operator_address defines the previous address of the validator's operator; bech encoded in JSON.
string old_operator_address = 2 ;

// height defines the block height at which the rotation event occured.
uint64 height = 3;
}

// RotatedOperatorAddresses contains the array of addresses which rotated their keys
// This is to block the validator's next rotation till unbonding period.
message RotatedOperatorAddresses {
repeated string addresses = 1 [(cosmos_proto.scalar) = "cosmos.AddressString"];
}
26 changes: 26 additions & 0 deletions proto/cosmos/staking/v1beta1/tx.proto
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,12 @@ service Msg {
// parameters.
// Since: cosmos-sdk 0.47
rpc UpdateParams(MsgUpdateParams) returns (MsgUpdateParamsResponse);

// RotateOperatorKey defines an operation for rotating the operator key
// of a validator.
//
// Since: cosmos-sdk 0.48
rpc RotateOperatorKey(MsgRotateOperatorKey) returns (MsgRotateOperatorKeyResponse);
}

// MsgCreateValidator defines a SDK message for creating a new validator.
Expand Down Expand Up @@ -204,3 +210,23 @@ message MsgUpdateParams {
//
// Since: cosmos-sdk 0.47
message MsgUpdateParamsResponse {};

// MsgRotateOperatorKey is the Msg/RotateOperatorKey request type.
//
// Since: cosmos-sdk 0.48
message MsgRotateOperatorKey {
option (cosmos.msg.v1.signer) = "validator_address";
option (amino.name) = "cosmos-sdk/MsgRotateOperatorKey";

option (gogoproto.goproto_getters) = false;
option (gogoproto.equal) = false;

string validator_address = 2 [(cosmos_proto.scalar) = "cosmos.AddressString"];
string new_operator_key = 3;
}

// MsgRotateOperatorKeyResponse defines the response structure for executing a
// MsgRotateOperatorKey message.
//
// Since: cosmos-sdk 0.48
message MsgRotateOperatorKeyResponse {}
99 changes: 99 additions & 0 deletions x/staking/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,23 @@ func (k Keeper) SetUnbondingDelegationEntry(
return ubd
}

func (k Keeper) updateUBDToNewValAddr(ctx sdk.Context, delAddr sdk.AccAddress, oldValAddr, newValAddr sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
oldKey := types.GetUBDKey(delAddr, oldValAddr)
bz := store.Get(oldKey)

var ubd types.UnbondingDelegation
k.cdc.MustUnmarshal(bz, &ubd)
k.RemoveUnbondingDelegation(ctx, ubd)
ubd.ValidatorAddress = newValAddr.String()
k.SetUnbondingDelegation(ctx, ubd)

// over ride the existing ubd entries with unbonding id
for _, entry := range ubd.Entries {
k.SetUnbondingDelegationByUnbondingID(ctx, ubd, entry.UnbondingId)
}
}

// unbonding delegation queue timeslice operations

// GetUBDQueueTimeSlice gets a specific unbonding queue timeslice. A timeslice
Expand Down Expand Up @@ -422,6 +439,29 @@ func (k Keeper) DequeueAllMatureUBDQueue(ctx sdk.Context, currTime time.Time) (m
return matureUnbonds
}

func (k Keeper) updateAllUBDQueue(ctx sdk.Context, oldValAddr, newValAddr sdk.ValAddress, t time.Time) {
store := ctx.KVStore(k.storeKey)

// gets an iterator for all timeslices from time 0 until the given time
unbondingTimesliceIterator := k.UBDQueueIterator(ctx, t)
defer unbondingTimesliceIterator.Close()

for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() {
timeslice := types.DVPairs{}
value := unbondingTimesliceIterator.Value()
k.cdc.MustUnmarshal(value, &timeslice)

for i := 0; i < len(timeslice.Pairs); i++ {
if timeslice.Pairs[i].ValidatorAddress == oldValAddr.String() {
timeslice.Pairs[i].ValidatorAddress = newValAddr.String()
}
}

bz := k.cdc.MustMarshal(&timeslice)
store.Set(unbondingTimesliceIterator.Key(), bz)
}
}

// GetRedelegations returns a given amount of all the delegator redelegations.
func (k Keeper) GetRedelegations(ctx sdk.Context, delegator sdk.AccAddress, maxRetrieve uint16) (redelegations []types.Redelegation) {
redelegations = make([]types.Redelegation, maxRetrieve)
Expand Down Expand Up @@ -586,6 +626,40 @@ func (k Keeper) RemoveRedelegation(ctx sdk.Context, red types.Redelegation) {
store.Delete(types.GetREDByValDstIndexKey(delegatorAddress, valSrcAddr, valDestAddr))
}

func (k Keeper) updateRedelegationSrcVal(ctx sdk.Context, delAddr sdk.AccAddress, oldSrcVal, newSrcVal, dstVal sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
oldKey := types.GetREDKey(delAddr, oldSrcVal, dstVal)
bz := store.Get(oldKey)

var red types.Redelegation
k.cdc.MustUnmarshal(bz, &red)
k.RemoveRedelegation(ctx, red)
red.ValidatorSrcAddress = newSrcVal.String()
k.SetRedelegation(ctx, red)

// over ride the existing ubd entries with unbonding id
for _, entry := range red.Entries {
k.SetRedelegationByUnbondingID(ctx, red, entry.UnbondingId)
}
}

func (k Keeper) updateRedelegationDstVal(ctx sdk.Context, delAddr sdk.AccAddress, srcVal, oldDstVal, newDstVal sdk.ValAddress) {
store := ctx.KVStore(k.storeKey)
oldKey := types.GetREDKey(delAddr, srcVal, oldDstVal)
bz := store.Get(oldKey)

var red types.Redelegation
k.cdc.MustUnmarshal(bz, &red)
k.RemoveRedelegation(ctx, red)
red.ValidatorDstAddress = newDstVal.String()
k.SetRedelegation(ctx, red)

// over ride the existing ubd entries with unbonding id
for _, entry := range red.Entries {
k.SetRedelegationByUnbondingID(ctx, red, entry.UnbondingId)
}
}

// redelegation queue timeslice operations

// GetRedelegationQueueTimeSlice gets a specific redelegation queue timeslice. A
Expand Down Expand Up @@ -660,6 +734,31 @@ func (k Keeper) DequeueAllMatureRedelegationQueue(ctx sdk.Context, currTime time
return matureRedelegations
}

func (k Keeper) updateRedelegationQueue(ctx sdk.Context, oldValAddr, newValAddr sdk.ValAddress, t time.Time) {
store := ctx.KVStore(k.storeKey)

// gets an iterator for all timeslices from time 0 until the current Blockheader time
redelegationTimesliceIterator := k.RedelegationQueueIterator(ctx, t)
defer redelegationTimesliceIterator.Close()

for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() {
timeslice := types.DVVTriplets{}
value := redelegationTimesliceIterator.Value()
k.cdc.MustUnmarshal(value, &timeslice)

for i := 0; i < len(timeslice.Triplets); i++ {
if timeslice.Triplets[i].ValidatorSrcAddress == oldValAddr.String() {
timeslice.Triplets[i].ValidatorSrcAddress = newValAddr.String()
} else if timeslice.Triplets[i].ValidatorDstAddress == oldValAddr.String() {
timeslice.Triplets[i].ValidatorDstAddress = newValAddr.String()
}
}

bz := k.cdc.MustMarshal(&timeslice)
store.Set(redelegationTimesliceIterator.Key(), bz)
}
}

// Delegate performs a delegation, set/update everything necessary within the store.
// tokenSrc indicates the bond status of the incoming funds.
func (k Keeper) Delegate(
Expand Down
45 changes: 45 additions & 0 deletions x/staking/keeper/msg_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
distrtypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
govtypes "github.com/cosmos/cosmos-sdk/x/gov/types"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)
Expand Down Expand Up @@ -558,3 +559,47 @@ func (k msgServer) UpdateParams(goCtx context.Context, msg *types.MsgUpdateParam

return &types.MsgUpdateParamsResponse{}, nil
}

func (k msgServer) RotateOperatorKey(goCtx context.Context, req *types.MsgRotateOperatorKey) (*types.MsgRotateOperatorKeyResponse, error) {
ctx := sdk.UnwrapSDKContext(goCtx)

curValAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddress)
if err != nil {
return &types.MsgRotateOperatorKeyResponse{}, err
}

validator, found := k.Keeper.GetValidator(ctx, curValAddr)
if found {
return nil, types.ErrOperatorKeyAlreadyUsed
}

// checks if NewPubKey is not duplicated on ValidatorsByConsAddr
newValAddr, err := sdk.ValAddressFromBech32(req.NewOperatorKey)
if err != nil {
return &types.MsgRotateOperatorKeyResponse{}, err
}

_, found = k.Keeper.GetValidator(ctx, newValAddr)
if found {
return nil, types.ErrOperatorKeyAlreadyUsed
}

// checks if the signing account has enough balance to pay KeyRotationFee
// pays KeyRotationFee to community fund
rotationFee := k.OperatorKeyRotationFee(ctx)
delAddr := sdk.AccAddress(curValAddr)

err = k.Keeper.bankKeeper.SendCoinsFromAccountToModule(ctx, delAddr, distrtypes.ModuleName, sdk.NewCoins(rotationFee))
if err != nil {
return nil, err
}

k.updateValidatorOperatorKey(ctx, validator, delAddr, newValAddr, curValAddr)

// Add OperatorKeyRotationRecord for tracking rotations
if err := k.SetOperatorKeyRotationRecord(ctx, curValAddr, newValAddr, ctx.BlockHeight()); err != nil {
return &types.MsgRotateOperatorKeyResponse{}, err
}

return &types.MsgRotateOperatorKeyResponse{}, nil
}
Loading