feat: include rotate keys logic in abci (#18236)
This commit is contained in:
parent
51b72d297a
commit
19e66a9dc8
@ -44,6 +44,7 @@ func SetupUnbondingTests(t *testing.T, f *fixture, hookCalled *bool, ubdeID *uin
|
||||
mockStackingHooks.EXPECT().BeforeDelegationSharesModified(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockStackingHooks.EXPECT().BeforeValidatorModified(gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockStackingHooks.EXPECT().BeforeValidatorSlashed(gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
mockStackingHooks.EXPECT().AfterConsensusPubKeyUpdate(gomock.Any(), gomock.Any(), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
f.stakingKeeper.SetHooks(types.NewMultiStakingHooks(mockStackingHooks))
|
||||
|
||||
addrDels = simtestutil.AddTestAddrsIncremental(f.bankKeeper, f.stakingKeeper, f.sdkCtx, 2, math.NewInt(10000))
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"cosmossdk.io/x/distribution/types"
|
||||
stakingtypes "cosmossdk.io/x/staking/types"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -187,3 +188,7 @@ func (h Hooks) BeforeDelegationRemoved(_ context.Context, _ sdk.AccAddress, _ sd
|
||||
func (h Hooks) AfterUnbondingInitiated(_ context.Context, _ uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h Hooks) AfterConsensusPubKeyUpdate(_ context.Context, _, _ cryptotypes.PubKey, _ sdk.Coin) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -40,6 +40,15 @@ func (k Keeper) handleEquivocationEvidence(ctx context.Context, evidence *types.
|
||||
}
|
||||
|
||||
if len(validator.GetOperator()) != 0 {
|
||||
// Get the consAddr from the validator read from the store and not from the evidence,
|
||||
// because if the validator has rotated its key, the key in evidence could be outdated.
|
||||
// (ValidatorByConsAddr can get a validator even if the key has been rotated)
|
||||
valConsAddr, err := validator.GetConsAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
consAddr = valConsAddr
|
||||
|
||||
if _, err := k.slashingKeeper.GetPubkey(ctx, consAddr.Bytes()); err != nil {
|
||||
// Ignore evidence that cannot be handled.
|
||||
//
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
sdkmath "cosmossdk.io/math"
|
||||
"cosmossdk.io/x/slashing/types"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -99,3 +100,16 @@ func (h Hooks) BeforeValidatorSlashed(_ context.Context, _ sdk.ValAddress, _ sdk
|
||||
func (h Hooks) AfterUnbondingInitiated(_ context.Context, _ uint64) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// AfterConsensusPubKeyUpdate triggers the functions to rotate the signing-infos also sets address pubkey relation.
|
||||
func (h Hooks) AfterConsensusPubKeyUpdate(ctx context.Context, oldPubKey, newPubKey cryptotypes.PubKey, _ sdk.Coin) error {
|
||||
if err := h.k.performConsensusPubKeyUpdate(ctx, oldPubKey, newPubKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := h.k.AddrPubkeyRelation.Remove(ctx, oldPubKey.Address()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -12,6 +12,7 @@ import (
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"cosmossdk.io/x/slashing/types"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -75,6 +76,21 @@ func (k Keeper) SetMissedBlockBitmapChunk(ctx context.Context, addr sdk.ConsAddr
|
||||
return k.ValidatorMissedBlockBitmap.Set(ctx, collections.Join(addr.Bytes(), uint64(chunkIndex)), chunk)
|
||||
}
|
||||
|
||||
// getPreviousConsKey checks if the key rotated, returns the old consKey to get the missed blocks
|
||||
// because missed blocks are still pointing to the old key
|
||||
func (k Keeper) getPreviousConsKey(ctx context.Context, addr sdk.ConsAddress) (sdk.ConsAddress, error) {
|
||||
oldPk, err := k.sk.ValidatorIdentifier(ctx, addr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if oldPk != nil {
|
||||
return oldPk, nil
|
||||
}
|
||||
|
||||
return addr, nil
|
||||
}
|
||||
|
||||
// GetMissedBlockBitmapValue returns true if a validator missed signing a block
|
||||
// at the given index and false otherwise. The index provided is assumed to be
|
||||
// the index in the range [0, SignedBlocksWindow), which represents the bitmap
|
||||
@ -82,6 +98,13 @@ func (k Keeper) SetMissedBlockBitmapChunk(ctx context.Context, addr sdk.ConsAddr
|
||||
// IndexOffset modulo SignedBlocksWindow. This index is used to fetch the chunk
|
||||
// in the bitmap and the relative bit in that chunk.
|
||||
func (k Keeper) GetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddress, index int64) (bool, error) {
|
||||
// check the key rotated, if rotated use the returned consKey to get the missed blocks
|
||||
// because missed blocks are still pointing to the old key
|
||||
addr, err := k.getPreviousConsKey(ctx, addr)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
|
||||
// get the chunk or "word" in the logical bitmap
|
||||
chunkIndex := index / types.MissedBlockBitmapChunkSize
|
||||
|
||||
@ -111,6 +134,13 @@ func (k Keeper) GetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddr
|
||||
// index is used to fetch the chunk in the bitmap and the relative bit in that
|
||||
// chunk.
|
||||
func (k Keeper) SetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddress, index int64, missed bool) error {
|
||||
// check the key rotated, if rotated use the returned consKey to get the missed blocks
|
||||
// because missed blocks are still pointing to the old key
|
||||
addr, err := k.getPreviousConsKey(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// get the chunk or "word" in the logical bitmap
|
||||
chunkIndex := index / types.MissedBlockBitmapChunkSize
|
||||
|
||||
@ -144,19 +174,21 @@ func (k Keeper) SetMissedBlockBitmapValue(ctx context.Context, addr sdk.ConsAddr
|
||||
|
||||
// DeleteMissedBlockBitmap removes a validator's missed block bitmap from state.
|
||||
func (k Keeper) DeleteMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddress) error {
|
||||
// check the key rotated, if rotated use the returned consKey to delete the missed blocks
|
||||
// because missed blocks are still pointing to the old key
|
||||
addr, err := k.getPreviousConsKey(ctx, addr)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
rng := collections.NewPrefixedPairRange[[]byte, uint64](addr.Bytes())
|
||||
err := k.ValidatorMissedBlockBitmap.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], value []byte) (bool, error) {
|
||||
return k.ValidatorMissedBlockBitmap.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], value []byte) (bool, error) {
|
||||
err := k.ValidatorMissedBlockBitmap.Remove(ctx, key)
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// IterateMissedBlockBitmap iterates over a validator's signed blocks window
|
||||
@ -168,7 +200,7 @@ func (k Keeper) DeleteMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddres
|
||||
func (k Keeper) IterateMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddress, cb func(index int64, missed bool) (stop bool)) error {
|
||||
var index int64
|
||||
rng := collections.NewPrefixedPairRange[[]byte, uint64](addr.Bytes())
|
||||
err := k.ValidatorMissedBlockBitmap.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], value []byte) (bool, error) {
|
||||
return k.ValidatorMissedBlockBitmap.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], value []byte) (bool, error) {
|
||||
bs := bitset.New(uint(types.MissedBlockBitmapChunkSize))
|
||||
|
||||
if err := bs.UnmarshalBinary(value); err != nil {
|
||||
@ -185,10 +217,6 @@ func (k Keeper) IterateMissedBlockBitmap(ctx context.Context, addr sdk.ConsAddre
|
||||
}
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetValidatorMissedBlocks returns array of missed blocks for given validator.
|
||||
@ -209,3 +237,24 @@ func (k Keeper) GetValidatorMissedBlocks(ctx context.Context, addr sdk.ConsAddre
|
||||
|
||||
return missedBlocks, err
|
||||
}
|
||||
|
||||
// performConsensusPubKeyUpdate updates cons address to its pub key relation
|
||||
// Updates signing info, missed blocks (removes old one, and sets new one)
|
||||
func (k Keeper) performConsensusPubKeyUpdate(ctx context.Context, oldPubKey, newPubKey cryptotypes.PubKey) error {
|
||||
// Connect new consensus address with PubKey
|
||||
if err := k.AddrPubkeyRelation.Set(ctx, newPubKey.Address(), newPubKey); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Migrate ValidatorSigningInfo from oldPubKey to newPubKey
|
||||
signingInfo, err := k.ValidatorSigningInfo.Get(ctx, sdk.ConsAddress(oldPubKey.Address()))
|
||||
if err != nil {
|
||||
return types.ErrInvalidConsPubKey.Wrap("failed to get signing info for old public key")
|
||||
}
|
||||
|
||||
if err := k.ValidatorSigningInfo.Set(ctx, sdk.ConsAddress(newPubKey.Address()), signingInfo); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return k.ValidatorSigningInfo.Remove(ctx, sdk.ConsAddress(oldPubKey.Address()))
|
||||
}
|
||||
|
||||
@ -3,6 +3,8 @@ package keeper_test
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"cosmossdk.io/x/slashing/testutil"
|
||||
slashingtypes "cosmossdk.io/x/slashing/types"
|
||||
|
||||
@ -65,6 +67,8 @@ func (s *KeeperTestSuite) TestValidatorMissedBlockBitmap_SmallWindow() {
|
||||
params.SignedBlocksWindow = window
|
||||
require.NoError(keeper.Params.Set(ctx, params))
|
||||
|
||||
s.stakingKeeper.EXPECT().ValidatorIdentifier(gomock.Any(), consAddr).Return(consAddr, nil).AnyTimes()
|
||||
|
||||
// validator misses all blocks in the window
|
||||
var valIdxOffset int64
|
||||
for valIdxOffset < params.SignedBlocksWindow {
|
||||
@ -97,5 +101,13 @@ func (s *KeeperTestSuite) TestValidatorMissedBlockBitmap_SmallWindow() {
|
||||
missedBlocks, err = keeper.GetValidatorMissedBlocks(ctx, consAddr)
|
||||
require.NoError(err)
|
||||
require.Len(missedBlocks, int(params.SignedBlocksWindow)-1)
|
||||
|
||||
// if the validator rotated it's key there will be different consKeys and a mapping will be added in the state.
|
||||
consAddr1 := sdk.ConsAddress(sdk.AccAddress([]byte("addr1_______________")))
|
||||
s.stakingKeeper.EXPECT().ValidatorIdentifier(gomock.Any(), consAddr1).Return(consAddr, nil).AnyTimes()
|
||||
|
||||
missedBlocks, err = keeper.GetValidatorMissedBlocks(ctx, consAddr1)
|
||||
require.NoError(err)
|
||||
require.Len(missedBlocks, int(params.SignedBlocksWindow)-1)
|
||||
}
|
||||
}
|
||||
|
||||
@ -371,6 +371,21 @@ func (mr *MockStakingKeeperMockRecorder) ValidatorByConsAddr(arg0, arg1 interfac
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatorByConsAddr", reflect.TypeOf((*MockStakingKeeper)(nil).ValidatorByConsAddr), arg0, arg1)
|
||||
}
|
||||
|
||||
// ValidatorIdentifier mocks base method.
|
||||
func (m *MockStakingKeeper) ValidatorIdentifier(arg0 context.Context, arg1 types0.ConsAddress) (types0.ConsAddress, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidatorIdentifier", arg0, arg1)
|
||||
ret0, _ := ret[0].(types0.ConsAddress)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// ValidatorIdentifier indicates an expected call of ValidatorIdentifier.
|
||||
func (mr *MockStakingKeeperMockRecorder) ValidatorIdentifier(arg0, arg1 interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ValidatorIdentifier", reflect.TypeOf((*MockStakingKeeper)(nil).ValidatorIdentifier), arg0, arg1)
|
||||
}
|
||||
|
||||
// MockStakingHooks is a mock of StakingHooks interface.
|
||||
type MockStakingHooks struct {
|
||||
ctrl *gomock.Controller
|
||||
|
||||
@ -13,4 +13,5 @@ var (
|
||||
ErrNoSigningInfoFound = errors.Register(ModuleName, 8, "no validator signing info found")
|
||||
ErrValidatorTombstoned = errors.Register(ModuleName, 9, "validator already tombstoned")
|
||||
ErrInvalidSigner = errors.Register(ModuleName, 10, "expected authority account as only signer for proposal message")
|
||||
ErrInvalidConsPubKey = errors.Register(ModuleName, 11, "invalid consensus pubkey")
|
||||
)
|
||||
|
||||
@ -53,6 +53,10 @@ type StakingKeeper interface {
|
||||
|
||||
// IsValidatorJailed returns if the validator is jailed.
|
||||
IsValidatorJailed(ctx context.Context, addr sdk.ConsAddress) (bool, error)
|
||||
|
||||
// ValidatorIdentifier maps the new cons key to previous cons key (which is the address before the rotation).
|
||||
// (that is: newConsKey -> oldConsKey)
|
||||
ValidatorIdentifier(context.Context, sdk.ConsAddress) (sdk.ConsAddress, error)
|
||||
}
|
||||
|
||||
// StakingHooks event hooks for staking validator object (noalias)
|
||||
|
||||
@ -3,13 +3,18 @@ package keeper
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"cosmossdk.io/collections"
|
||||
"cosmossdk.io/collections/indexes"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"cosmossdk.io/x/staking/types"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// maxRotations is the value of max rotations can be made in unbonding period for a validator.
|
||||
@ -29,7 +34,7 @@ func (k Keeper) setConsPubKeyRotationHistory(
|
||||
Height: height,
|
||||
Fee: fee,
|
||||
}
|
||||
err := k.RotationHistory.Set(ctx, valAddr, history)
|
||||
err := k.RotationHistory.Set(ctx, collections.Join(valAddr.Bytes(), height), history)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@ -39,7 +44,7 @@ func (k Keeper) setConsPubKeyRotationHistory(
|
||||
return err
|
||||
}
|
||||
|
||||
queueTime := sdkCtx.BlockHeader().Time.Add(ubdTime)
|
||||
queueTime := sdkCtx.HeaderInfo().Time.Add(ubdTime)
|
||||
if err := k.ValidatorConsensusKeyRotationRecordIndexKey.Set(ctx, collections.Join(valAddr.Bytes(), queueTime)); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -47,6 +52,85 @@ func (k Keeper) setConsPubKeyRotationHistory(
|
||||
return k.setConsKeyQueue(ctx, queueTime, valAddr)
|
||||
}
|
||||
|
||||
// updateToNewPubkey gets called from the `ApplyAndReturnValidatorSetUpdates` method during EndBlock.
|
||||
//
|
||||
// This method makes the relative state changes to update the keys,
|
||||
// also maintains a map with old to new conskey rotation which is needed to retrieve the old conskey.
|
||||
// And also triggers the hook to make changes required in slashing and distribution modules.
|
||||
func (k Keeper) updateToNewPubkey(ctx context.Context, val types.Validator, oldPubKey, newPubKey *codectypes.Any, fee sdk.Coin) error {
|
||||
consAddr, err := val.GetConsAddr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := k.ValidatorByConsensusAddress.Remove(ctx, consAddr); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := k.DeleteValidatorByPowerIndex(ctx, val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
val.ConsensusPubkey = newPubKey
|
||||
if err := k.SetValidator(ctx, val); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.SetValidatorByConsAddr(ctx, val); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := k.SetValidatorByPowerIndex(ctx, val); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
oldPk, ok := oldPubKey.GetCachedValue().(cryptotypes.PubKey)
|
||||
if !ok {
|
||||
return errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPk)
|
||||
}
|
||||
|
||||
newPk, ok := newPubKey.GetCachedValue().(cryptotypes.PubKey)
|
||||
if !ok {
|
||||
return errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", newPk)
|
||||
}
|
||||
|
||||
// sets a map: oldConsKey -> newConsKey
|
||||
if err := k.OldToNewConsKeyMap.Set(ctx, oldPk.Address(), newPk.Address()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// sets a map: newConsKey -> oldConsKey
|
||||
if err := k.setNewToOldConsKeyMap(ctx, sdk.ConsAddress(oldPk.Address()), sdk.ConsAddress(newPk.Address())); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return k.Hooks().AfterConsensusPubKeyUpdate(ctx, oldPk, newPk, fee)
|
||||
}
|
||||
|
||||
// setNewToOldConsKeyMap adds an entry in the state with the current consKey to the initial consKey of the validator.
|
||||
// it tries to find the oldPk if there is a entry already present in the state
|
||||
func (k Keeper) setNewToOldConsKeyMap(ctx context.Context, oldPk, newPk sdk.ConsAddress) error {
|
||||
pk, err := k.NewToOldConsKeyMap.Get(ctx, oldPk)
|
||||
if err != nil && !errors.Is(err, collections.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
|
||||
if pk != nil {
|
||||
oldPk = pk
|
||||
}
|
||||
|
||||
return k.NewToOldConsKeyMap.Set(ctx, newPk, oldPk)
|
||||
}
|
||||
|
||||
// ValidatorIdentifier maps the new cons key to previous cons key (which is the address before the rotation).
|
||||
// (that is: newConsKey -> oldConsKey)
|
||||
func (k Keeper) ValidatorIdentifier(ctx context.Context, newPk sdk.ConsAddress) (sdk.ConsAddress, error) {
|
||||
pk, err := k.NewToOldConsKeyMap.Get(ctx, newPk)
|
||||
if err != nil && !errors.Is(err, collections.ErrNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return pk, nil
|
||||
}
|
||||
|
||||
// exceedsMaxRotations returns true if the key rotations exceed the limit, currently we are limiting one rotation for unbonding period.
|
||||
func (k Keeper) exceedsMaxRotations(ctx context.Context, valAddr sdk.ValAddress) error {
|
||||
count := 0
|
||||
@ -70,10 +154,12 @@ func (k Keeper) exceedsMaxRotations(ctx context.Context, valAddr sdk.ValAddress)
|
||||
// this is to keep track of rotations made within the unbonding period
|
||||
func (k Keeper) setConsKeyQueue(ctx context.Context, ts time.Time, valAddr sdk.ValAddress) error {
|
||||
queueRec, err := k.ValidatorConsensusKeyRotationRecordQueue.Get(ctx, ts)
|
||||
if err != nil {
|
||||
// we should return if the key found here.
|
||||
if err != nil && !errors.Is(err, collections.ErrNotFound) {
|
||||
return err
|
||||
}
|
||||
|
||||
// push the address if it is not present in the array.
|
||||
if !bytesSliceExists(queueRec.Addresses, valAddr.Bytes()) {
|
||||
// Address does not exist, so you can append it to the list
|
||||
queueRec.Addresses = append(queueRec.Addresses, valAddr.Bytes())
|
||||
@ -82,6 +168,7 @@ func (k Keeper) setConsKeyQueue(ctx context.Context, ts time.Time, valAddr sdk.V
|
||||
return k.ValidatorConsensusKeyRotationRecordQueue.Set(ctx, ts, queueRec)
|
||||
}
|
||||
|
||||
// bytesSliceExists tries to find the duplicate entry the array.
|
||||
func bytesSliceExists(sliceList [][]byte, targetBytes []byte) bool {
|
||||
for _, bytesSlice := range sliceList {
|
||||
if bytes.Equal(bytesSlice, targetBytes) {
|
||||
@ -90,3 +177,79 @@ func bytesSliceExists(sliceList [][]byte, targetBytes []byte) bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// PurgeAllMaturedConsKeyRotatedKeys deletes all the matured key rotations.
|
||||
func (k Keeper) PurgeAllMaturedConsKeyRotatedKeys(ctx sdk.Context, maturedTime time.Time) error {
|
||||
maturedRotatedValAddrs, err := k.getAndRemoveAllMaturedRotatedKeys(ctx, maturedTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, valAddr := range maturedRotatedValAddrs {
|
||||
err := k.deleteConsKeyIndexKey(ctx, valAddr, maturedTime)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// deleteConsKeyIndexKey deletes the keys which forms a with given validator address and time lesser than the given time.
|
||||
// eventually there should be only one occurrence since we allow only one rotation for bonding period.
|
||||
func (k Keeper) deleteConsKeyIndexKey(ctx sdk.Context, valAddr sdk.ValAddress, ts time.Time) error {
|
||||
rng := new(collections.Range[collections.Pair[[]byte, time.Time]]).
|
||||
StartInclusive(collections.Join(valAddr.Bytes(), time.Time{})).
|
||||
EndInclusive(collections.Join(valAddr.Bytes(), ts))
|
||||
|
||||
return k.ValidatorConsensusKeyRotationRecordIndexKey.Walk(ctx, rng, func(key collections.Pair[[]byte, time.Time]) (stop bool, err error) {
|
||||
return false, k.ValidatorConsensusKeyRotationRecordIndexKey.Remove(ctx, key)
|
||||
})
|
||||
}
|
||||
|
||||
// getAndRemoveAllMaturedRotatedKeys returns all matured valaddresses.
|
||||
func (k Keeper) getAndRemoveAllMaturedRotatedKeys(ctx sdk.Context, matureTime time.Time) ([][]byte, error) {
|
||||
valAddrs := [][]byte{}
|
||||
|
||||
// get an iterator for all timeslices from time 0 until the current HeaderInfo time
|
||||
rng := new(collections.Range[time.Time]).EndInclusive(matureTime)
|
||||
err := k.ValidatorConsensusKeyRotationRecordQueue.Walk(ctx, rng, func(key time.Time, value types.ValAddrsOfRotatedConsKeys) (stop bool, err error) {
|
||||
valAddrs = append(valAddrs, value.Addresses...)
|
||||
return false, k.ValidatorConsensusKeyRotationRecordQueue.Remove(ctx, key)
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return valAddrs, nil
|
||||
}
|
||||
|
||||
// GetBlockConsPubKeyRotationHistory returns the rotation history for the current height.
|
||||
func (k Keeper) GetBlockConsPubKeyRotationHistory(ctx context.Context) ([]types.ConsPubKeyRotationHistory, error) {
|
||||
sdkCtx := sdk.UnwrapSDKContext(ctx)
|
||||
|
||||
iterator, err := k.RotationHistory.Indexes.Block.MatchExact(ctx, uint64(sdkCtx.BlockHeight()))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer iterator.Close()
|
||||
|
||||
return indexes.CollectValues(ctx, k.RotationHistory, iterator)
|
||||
}
|
||||
|
||||
// GetValidatorConsPubKeyRotationHistory iterates over all the rotated history objects in the state with the given valAddr and returns.
|
||||
func (k Keeper) GetValidatorConsPubKeyRotationHistory(ctx sdk.Context, operatorAddress sdk.ValAddress) ([]types.ConsPubKeyRotationHistory, error) {
|
||||
var historyObjects []types.ConsPubKeyRotationHistory
|
||||
|
||||
rng := collections.NewPrefixedPairRange[[]byte, uint64](operatorAddress.Bytes())
|
||||
|
||||
err := k.RotationHistory.Walk(ctx, rng, func(key collections.Pair[[]byte, uint64], history types.ConsPubKeyRotationHistory) (stop bool, err error) {
|
||||
historyObjects = append(historyObjects, history)
|
||||
return false, nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return historyObjects, nil
|
||||
}
|
||||
|
||||
180
x/staking/keeper/cons_pubkey_test.go
Normal file
180
x/staking/keeper/cons_pubkey_test.go
Normal file
@ -0,0 +1,180 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
|
||||
"cosmossdk.io/collections"
|
||||
"cosmossdk.io/core/header"
|
||||
authtypes "cosmossdk.io/x/auth/types"
|
||||
stakingkeeper "cosmossdk.io/x/staking/keeper"
|
||||
"cosmossdk.io/x/staking/testutil"
|
||||
"cosmossdk.io/x/staking/types"
|
||||
|
||||
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func (s *KeeperTestSuite) TestConsPubKeyRotationHistory() {
|
||||
stakingKeeper, ctx := s.stakingKeeper, s.ctx
|
||||
|
||||
_, addrVals := createValAddrs(2)
|
||||
|
||||
// create a validator with a self-delegation
|
||||
val := testutil.NewValidator(s.T(), addrVals[0], PKs[0])
|
||||
valTokens := stakingKeeper.TokensFromConsensusPower(ctx, 10)
|
||||
val, issuedShares := val.AddTokensFromDel(valTokens)
|
||||
s.Require().Equal(valTokens, issuedShares.RoundInt())
|
||||
|
||||
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), types.NotBondedPoolName, types.BondedPoolName, gomock.Any())
|
||||
_ = stakingkeeper.TestingUpdateValidator(stakingKeeper, ctx, val, true)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[0].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr.String(), addrVals[0].String(), issuedShares)
|
||||
|
||||
err := stakingKeeper.SetDelegation(ctx, selfDelegation)
|
||||
s.Require().NoError(err)
|
||||
|
||||
validators, err := stakingKeeper.GetAllValidators(ctx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(validators, 1)
|
||||
|
||||
validator := validators[0]
|
||||
valAddr, err := sdk.ValAddressFromBech32(validator.OperatorAddress)
|
||||
s.Require().NoError(err)
|
||||
|
||||
historyObjects, err := stakingKeeper.GetValidatorConsPubKeyRotationHistory(ctx, valAddr)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(historyObjects, 0)
|
||||
|
||||
newConsPub, err := codectypes.NewAnyWithValue(PKs[1])
|
||||
s.Require().NoError(err)
|
||||
|
||||
newConsPub2, err := codectypes.NewAnyWithValue(PKs[2])
|
||||
s.Require().NoError(err)
|
||||
|
||||
params, err := stakingKeeper.Params.Get(ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
height := uint64(ctx.BlockHeight())
|
||||
err = stakingKeeper.RotationHistory.Set(ctx, collections.Join(valAddr.Bytes(), height), types.ConsPubKeyRotationHistory{
|
||||
OperatorAddress: valAddr,
|
||||
OldConsPubkey: validator.ConsensusPubkey,
|
||||
NewConsPubkey: newConsPub,
|
||||
Height: height,
|
||||
Fee: params.KeyRotationFee,
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
|
||||
historyObjects, err = stakingKeeper.GetValidatorConsPubKeyRotationHistory(ctx, valAddr)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(historyObjects, 1)
|
||||
|
||||
historyObjects, err = stakingKeeper.GetBlockConsPubKeyRotationHistory(ctx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(historyObjects, 1)
|
||||
|
||||
err = stakingKeeper.RotationHistory.Set(ctx, collections.Join(valAddr.Bytes(), height+1), types.ConsPubKeyRotationHistory{
|
||||
OperatorAddress: valAddr,
|
||||
OldConsPubkey: newConsPub,
|
||||
NewConsPubkey: newConsPub2,
|
||||
Height: height + 1,
|
||||
Fee: params.KeyRotationFee,
|
||||
})
|
||||
s.Require().NoError(err)
|
||||
|
||||
historyObjects1, err := stakingKeeper.GetValidatorConsPubKeyRotationHistory(ctx, valAddr)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(historyObjects1, 2)
|
||||
|
||||
historyObjects, err = stakingKeeper.GetBlockConsPubKeyRotationHistory(ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Len(historyObjects, 1)
|
||||
}
|
||||
|
||||
func (s *KeeperTestSuite) TestValidatorIdentifier() {
|
||||
stakingKeeper, ctx, accountKeeper, bankKeeper := s.stakingKeeper, s.ctx, s.accountKeeper, s.bankKeeper
|
||||
|
||||
msgServer := stakingkeeper.NewMsgServerImpl(stakingKeeper)
|
||||
s.setValidators(6)
|
||||
validators, err := stakingKeeper.GetAllValidators(ctx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(validators, 6)
|
||||
|
||||
initialConsAddr, err := validators[3].GetConsAddr()
|
||||
s.Require().NoError(err)
|
||||
|
||||
oldPk, err := stakingKeeper.ValidatorIdentifier(ctx, initialConsAddr)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Nil(oldPk)
|
||||
|
||||
bondedPool := authtypes.NewEmptyModuleAccount(types.BondedPoolName)
|
||||
accountKeeper.EXPECT().GetModuleAccount(gomock.Any(), types.BondedPoolName).Return(bondedPool).AnyTimes()
|
||||
bankKeeper.EXPECT().GetBalance(gomock.Any(), bondedPool.GetAddress(), sdk.DefaultBondDenom).Return(sdk.NewInt64Coin(sdk.DefaultBondDenom, 1000000)).AnyTimes()
|
||||
|
||||
val, err := stakingKeeper.ValidatorAddressCodec().StringToBytes(validators[3].GetOperator())
|
||||
s.Require().NoError(err)
|
||||
bankKeeper.EXPECT().SendCoinsFromAccountToModule(gomock.Any(), sdk.AccAddress(val), gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
|
||||
|
||||
req, err := types.NewMsgRotateConsPubKey(validators[3].GetOperator(), PKs[495])
|
||||
s.Require().NoError(err)
|
||||
_, err = msgServer.RotateConsPubKey(ctx, req)
|
||||
s.Require().NoError(err)
|
||||
_, err = stakingKeeper.BlockValidatorUpdates(ctx)
|
||||
s.Require().NoError(err)
|
||||
params, err := stakingKeeper.Params.Get(ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
oldPk1, err := stakingKeeper.ValidatorIdentifier(ctx, sdk.ConsAddress(PKs[495].Address()))
|
||||
s.Require().NoError(err)
|
||||
s.Require().Equal(oldPk1.Bytes(), initialConsAddr)
|
||||
|
||||
ctx = ctx.WithHeaderInfo(header.Info{Time: ctx.BlockTime().Add(params.UnbondingTime).Add(time.Hour)})
|
||||
_, err = stakingKeeper.BlockValidatorUpdates(ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
req, err = types.NewMsgRotateConsPubKey(validators[3].GetOperator(), PKs[494])
|
||||
s.Require().NoError(err)
|
||||
_, err = msgServer.RotateConsPubKey(ctx, req)
|
||||
s.Require().NoError(err)
|
||||
_, err = stakingKeeper.BlockValidatorUpdates(ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
ctx = ctx.WithHeaderInfo(header.Info{Time: ctx.BlockTime().Add(params.UnbondingTime)})
|
||||
|
||||
oldPk2, err := stakingKeeper.ValidatorIdentifier(ctx, sdk.ConsAddress(PKs[494].Address()))
|
||||
s.Require().NoError(err)
|
||||
_, err = stakingKeeper.BlockValidatorUpdates(ctx)
|
||||
s.Require().NoError(err)
|
||||
|
||||
s.Require().Equal(oldPk2.Bytes(), initialConsAddr)
|
||||
}
|
||||
|
||||
func (s *KeeperTestSuite) setValidators(n int) {
|
||||
stakingKeeper, ctx := s.stakingKeeper, s.ctx
|
||||
|
||||
_, addrVals := createValAddrs(n)
|
||||
|
||||
for i := 0; i < n; i++ {
|
||||
val := testutil.NewValidator(s.T(), addrVals[i], PKs[i])
|
||||
valTokens := stakingKeeper.TokensFromConsensusPower(ctx, 10)
|
||||
val, issuedShares := val.AddTokensFromDel(valTokens)
|
||||
s.Require().Equal(valTokens, issuedShares.RoundInt())
|
||||
|
||||
s.bankKeeper.EXPECT().SendCoinsFromModuleToModule(gomock.Any(), types.NotBondedPoolName, types.BondedPoolName, gomock.Any())
|
||||
_ = stakingkeeper.TestingUpdateValidator(stakingKeeper, ctx, val, true)
|
||||
val0AccAddr := sdk.AccAddress(addrVals[i].Bytes())
|
||||
selfDelegation := types.NewDelegation(val0AccAddr.String(), addrVals[i].String(), issuedShares)
|
||||
err := stakingKeeper.SetDelegation(ctx, selfDelegation)
|
||||
s.Require().NoError(err)
|
||||
|
||||
err = stakingKeeper.SetValidatorByConsAddr(ctx, val)
|
||||
s.Require().NoError(err)
|
||||
|
||||
}
|
||||
|
||||
validators, err := stakingKeeper.GetAllValidators(ctx)
|
||||
s.Require().NoError(err)
|
||||
s.Require().Len(validators, n)
|
||||
}
|
||||
15
x/staking/keeper/hooks_test.go
Normal file
15
x/staking/keeper/hooks_test.go
Normal file
@ -0,0 +1,15 @@
|
||||
package keeper_test
|
||||
|
||||
import (
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
func (s *KeeperTestSuite) TestHookAfterConsensusPubKeyUpdate() {
|
||||
stKeeper := s.stakingKeeper
|
||||
ctx := s.ctx
|
||||
require := s.Require()
|
||||
|
||||
rotationFee := sdk.NewInt64Coin("stake", 1000000)
|
||||
err := stKeeper.Hooks().AfterConsensusPubKeyUpdate(ctx, PKs[0], PKs[1], rotationFee)
|
||||
require.NoError(err)
|
||||
}
|
||||
@ -43,11 +43,11 @@ func HistoricalInfoCodec(cdc codec.BinaryCodec) collcodec.ValueCodec[types.Histo
|
||||
}
|
||||
|
||||
type rotationHistoryIndexes struct {
|
||||
Block *indexes.Multi[uint64, []byte, types.ConsPubKeyRotationHistory]
|
||||
Block *indexes.Multi[uint64, collections.Pair[[]byte, uint64], types.ConsPubKeyRotationHistory]
|
||||
}
|
||||
|
||||
func (a rotationHistoryIndexes) IndexesList() []collections.Index[[]byte, types.ConsPubKeyRotationHistory] {
|
||||
return []collections.Index[[]byte, types.ConsPubKeyRotationHistory]{
|
||||
func (a rotationHistoryIndexes) IndexesList() []collections.Index[collections.Pair[[]byte, uint64], types.ConsPubKeyRotationHistory] {
|
||||
return []collections.Index[collections.Pair[[]byte, uint64], types.ConsPubKeyRotationHistory]{
|
||||
a.Block,
|
||||
}
|
||||
}
|
||||
@ -55,8 +55,12 @@ func (a rotationHistoryIndexes) IndexesList() []collections.Index[[]byte, types.
|
||||
func NewRotationHistoryIndexes(sb *collections.SchemaBuilder) rotationHistoryIndexes {
|
||||
return rotationHistoryIndexes{
|
||||
Block: indexes.NewMulti(
|
||||
sb, types.BlockConsPubKeyRotationHistoryKey, "cons_pubkey_history_by_block", collections.Uint64Key, collections.BytesKey,
|
||||
func(_ []byte, v types.ConsPubKeyRotationHistory) (uint64, error) {
|
||||
sb,
|
||||
types.BlockConsPubKeyRotationHistoryKey,
|
||||
"cons_pubkey_history_by_block",
|
||||
collections.Uint64Key,
|
||||
collections.PairKeyCodec(collections.BytesKey, collections.Uint64Key),
|
||||
func(key collections.Pair[[]byte, uint64], v types.ConsPubKeyRotationHistory) (uint64, error) {
|
||||
return v.Height, nil
|
||||
},
|
||||
),
|
||||
@ -119,11 +123,13 @@ type Keeper struct {
|
||||
ValidatorConsensusKeyRotationRecordIndexKey collections.KeySet[collections.Pair[[]byte, time.Time]]
|
||||
// ValidatorConsensusKeyRotationRecordQueue: this key is used to set the unbonding period time on each rotation
|
||||
ValidatorConsensusKeyRotationRecordQueue collections.Map[time.Time, types.ValAddrsOfRotatedConsKeys]
|
||||
// RotatedConsKeyMapIndex: prefix for rotated cons address to new cons address
|
||||
RotatedConsKeyMapIndex collections.Map[[]byte, []byte]
|
||||
// NewToOldConsKeyMap: prefix for rotated old cons address to new cons address
|
||||
NewToOldConsKeyMap collections.Map[[]byte, []byte]
|
||||
// OldToNewConsKeyMap: prefix for rotated new cons address to old cons address
|
||||
OldToNewConsKeyMap collections.Map[[]byte, []byte]
|
||||
// ValidatorConsPubKeyRotationHistory: consPubkey rotation history by validator
|
||||
// A index is being added with key `BlockConsPubKeyRotationHistory`: consPubkey rotation history by height
|
||||
RotationHistory *collections.IndexedMap[[]byte, types.ConsPubKeyRotationHistory, rotationHistoryIndexes]
|
||||
RotationHistory *collections.IndexedMap[collections.Pair[[]byte, uint64], types.ConsPubKeyRotationHistory, rotationHistoryIndexes]
|
||||
}
|
||||
|
||||
// NewKeeper creates a new staking Keeper instance
|
||||
@ -273,10 +279,18 @@ func NewKeeper(
|
||||
codec.CollValue[types.ValAddrsOfRotatedConsKeys](cdc),
|
||||
),
|
||||
|
||||
// key format is: 105 | valAddr
|
||||
RotatedConsKeyMapIndex: collections.NewMap(
|
||||
sb, types.RotatedConsKeyMapIndex,
|
||||
"cons_pubkey_map",
|
||||
// key format is: 105 | consAddr
|
||||
NewToOldConsKeyMap: collections.NewMap(
|
||||
sb, types.NewToOldConsKeyMap,
|
||||
"new_to_old_cons_key_map",
|
||||
collections.BytesKey,
|
||||
collections.BytesValue,
|
||||
),
|
||||
|
||||
// key format is: 106 | consAddr
|
||||
OldToNewConsKeyMap: collections.NewMap(
|
||||
sb, types.OldToNewConsKeyMap,
|
||||
"old_to_new_cons_key_map",
|
||||
collections.BytesKey,
|
||||
collections.BytesValue,
|
||||
),
|
||||
@ -287,7 +301,7 @@ func NewKeeper(
|
||||
sb,
|
||||
types.ValidatorConsPubKeyRotationHistoryKey,
|
||||
"cons_pub_rotation_history",
|
||||
collections.BytesKey,
|
||||
collections.PairKeyCodec(collections.BytesKey, collections.Uint64Key),
|
||||
codec.CollValue[types.ConsPubKeyRotationHistory](cdc),
|
||||
NewRotationHistoryIndexes(sb),
|
||||
),
|
||||
|
||||
@ -617,7 +617,7 @@ func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateCon
|
||||
}
|
||||
|
||||
// check cons key is already present in the key rotation history.
|
||||
rotatedTo, err := k.RotatedConsKeyMapIndex.Get(ctx, pk.Address())
|
||||
rotatedTo, err := k.NewToOldConsKeyMap.Get(ctx, pk.Address())
|
||||
if err != nil && !errors.Is(err, collections.ErrNotFound) {
|
||||
return nil, err
|
||||
}
|
||||
@ -630,8 +630,8 @@ func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateCon
|
||||
newConsAddr := sdk.ConsAddress(pk.Address())
|
||||
|
||||
// checks if NewPubKey is not duplicated on ValidatorsByConsAddr
|
||||
validator1, _ := k.Keeper.ValidatorByConsAddr(ctx, newConsAddr)
|
||||
if validator1 != nil {
|
||||
_, err = k.Keeper.ValidatorByConsAddr(ctx, newConsAddr)
|
||||
if err == nil {
|
||||
return nil, types.ErrConsensusPubKeyAlreadyUsedForValidator
|
||||
}
|
||||
|
||||
@ -642,6 +642,10 @@ func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateCon
|
||||
|
||||
validator2, err := k.Keeper.GetValidator(ctx, valAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if validator2.GetOperator() == "" {
|
||||
return nil, types.ErrNoValidatorFound
|
||||
}
|
||||
|
||||
@ -663,7 +667,7 @@ func (k msgServer) RotateConsPubKey(ctx context.Context, msg *types.MsgRotateCon
|
||||
return nil, err
|
||||
}
|
||||
|
||||
err = k.Keeper.bankKeeper.SendCoinsFromAccountToModule(ctx, sdk.AccAddress(valAddr), types.DistributionModuleName, sdk.NewCoins(params.KeyRotationFee))
|
||||
err = k.Keeper.bankKeeper.SendCoinsFromAccountToModule(ctx, sdk.AccAddress(valAddr), types.PoolModuleName, sdk.NewCoins(params.KeyRotationFee))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -10,10 +10,14 @@ import (
|
||||
gogotypes "github.com/cosmos/gogoproto/types"
|
||||
|
||||
"cosmossdk.io/core/address"
|
||||
errorsmod "cosmossdk.io/errors"
|
||||
"cosmossdk.io/math"
|
||||
"cosmossdk.io/x/staking/types"
|
||||
|
||||
cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
|
||||
)
|
||||
|
||||
// BlockValidatorUpdates calculates the ValidatorUpdates for the current block
|
||||
@ -112,6 +116,11 @@ func (k Keeper) BlockValidatorUpdates(ctx context.Context) ([]abci.ValidatorUpda
|
||||
)
|
||||
}
|
||||
|
||||
err = k.PurgeAllMaturedConsKeyRotatedKeys(sdkCtx, sdkCtx.HeaderInfo().Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return validatorUpdates, nil
|
||||
}
|
||||
|
||||
@ -241,6 +250,63 @@ func (k Keeper) ApplyAndReturnValidatorSetUpdates(ctx context.Context) (updates
|
||||
updates = append(updates, validator.ABCIValidatorUpdateZero())
|
||||
}
|
||||
|
||||
// ApplyAndReturnValidatorSetUpdates checks if there is ConsPubKeyRotationHistory
|
||||
// with ConsPubKeyRotationHistory.RotatedHeight == ctx.BlockHeight() and if so, generates 2 ValidatorUpdate,
|
||||
// one for a remove validator and one for create new validator
|
||||
historyObjects, err := k.GetBlockConsPubKeyRotationHistory(ctx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
for _, history := range historyObjects {
|
||||
valAddr := history.OperatorAddress
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
validator, err := k.GetValidator(ctx, valAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
oldPk, ok := history.OldConsPubkey.GetCachedValue().(cryptotypes.PubKey)
|
||||
if !ok {
|
||||
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPk)
|
||||
}
|
||||
oldCmtPk, err := cryptocodec.ToCmtProtoPublicKey(oldPk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
newPk, ok := history.NewConsPubkey.GetCachedValue().(cryptotypes.PubKey)
|
||||
if !ok {
|
||||
return nil, errorsmod.Wrapf(sdkerrors.ErrInvalidType, "Expecting cryptotypes.PubKey, got %T", oldPk)
|
||||
}
|
||||
newCmtPk, err := cryptocodec.ToCmtProtoPublicKey(newPk)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// a validator cannot rotate keys if it's not bonded or if it's jailed
|
||||
// - a validator can be unbonding state but jailed status false
|
||||
// - a validator can be jailed and status can be unbonding
|
||||
if !(validator.Jailed || validator.Status != types.Bonded) {
|
||||
updates = append(updates, abci.ValidatorUpdate{
|
||||
PubKey: oldCmtPk,
|
||||
Power: 0,
|
||||
})
|
||||
|
||||
updates = append(updates, abci.ValidatorUpdate{
|
||||
PubKey: newCmtPk,
|
||||
Power: validator.ConsensusPower(powerReduction),
|
||||
})
|
||||
|
||||
if err := k.updateToNewPubkey(ctx, validator, history.OldConsPubkey, history.NewConsPubkey, history.Fee); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update the pools based on the recent updates in the validator set:
|
||||
// - The tokens from the non-bonded candidates that enter the new validator set need to be transferred
|
||||
// to the Bonded pool.
|
||||
|
||||
@ -38,11 +38,21 @@ func (k Keeper) GetValidator(ctx context.Context, addr sdk.ValAddress) (validato
|
||||
func (k Keeper) GetValidatorByConsAddr(ctx context.Context, consAddr sdk.ConsAddress) (validator types.Validator, err error) {
|
||||
opAddr, err := k.ValidatorByConsensusAddress.Get(ctx, consAddr)
|
||||
if err != nil && !errors.Is(err, collections.ErrNotFound) {
|
||||
return validator, err
|
||||
// if the validator not found try to find it in the map of `OldToNewConsKeyMap`` because validator may've rotated it's key.
|
||||
if !errors.Is(err, collections.ErrNotFound) {
|
||||
return types.Validator{}, err
|
||||
}
|
||||
|
||||
newConsAddr, err := k.OldToNewConsKeyMap.Get(ctx, consAddr)
|
||||
if err != nil {
|
||||
return types.Validator{}, err
|
||||
}
|
||||
|
||||
opAddr = newConsAddr
|
||||
}
|
||||
|
||||
if opAddr == nil {
|
||||
return validator, types.ErrNoValidatorFound
|
||||
return types.Validator{}, types.ErrNoValidatorFound
|
||||
}
|
||||
|
||||
return k.GetValidator(ctx, opAddr)
|
||||
|
||||
@ -13,7 +13,8 @@ import (
|
||||
math "cosmossdk.io/math"
|
||||
types "cosmossdk.io/x/staking/types"
|
||||
crypto "github.com/cometbft/cometbft/proto/tendermint/crypto"
|
||||
types0 "github.com/cosmos/cosmos-sdk/types"
|
||||
types0 "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
types1 "github.com/cosmos/cosmos-sdk/types"
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
@ -55,10 +56,10 @@ func (mr *MockAccountKeeperMockRecorder) AddressCodec() *gomock.Call {
|
||||
}
|
||||
|
||||
// GetAccount mocks base method.
|
||||
func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types0.AccAddress) types0.AccountI {
|
||||
func (m *MockAccountKeeper) GetAccount(ctx context.Context, addr types1.AccAddress) types1.AccountI {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetAccount", ctx, addr)
|
||||
ret0, _ := ret[0].(types0.AccountI)
|
||||
ret0, _ := ret[0].(types1.AccountI)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -69,10 +70,10 @@ func (mr *MockAccountKeeperMockRecorder) GetAccount(ctx, addr interface{}) *gomo
|
||||
}
|
||||
|
||||
// GetModuleAccount mocks base method.
|
||||
func (m *MockAccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) types0.ModuleAccountI {
|
||||
func (m *MockAccountKeeper) GetModuleAccount(ctx context.Context, moduleName string) types1.ModuleAccountI {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetModuleAccount", ctx, moduleName)
|
||||
ret0, _ := ret[0].(types0.ModuleAccountI)
|
||||
ret0, _ := ret[0].(types1.ModuleAccountI)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -83,10 +84,10 @@ func (mr *MockAccountKeeperMockRecorder) GetModuleAccount(ctx, moduleName interf
|
||||
}
|
||||
|
||||
// GetModuleAddress mocks base method.
|
||||
func (m *MockAccountKeeper) GetModuleAddress(name string) types0.AccAddress {
|
||||
func (m *MockAccountKeeper) GetModuleAddress(name string) types1.AccAddress {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetModuleAddress", name)
|
||||
ret0, _ := ret[0].(types0.AccAddress)
|
||||
ret0, _ := ret[0].(types1.AccAddress)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -97,7 +98,7 @@ func (mr *MockAccountKeeperMockRecorder) GetModuleAddress(name interface{}) *gom
|
||||
}
|
||||
|
||||
// IterateAccounts mocks base method.
|
||||
func (m *MockAccountKeeper) IterateAccounts(ctx context.Context, process func(types0.AccountI) bool) {
|
||||
func (m *MockAccountKeeper) IterateAccounts(ctx context.Context, process func(types1.AccountI) bool) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "IterateAccounts", ctx, process)
|
||||
}
|
||||
@ -109,7 +110,7 @@ func (mr *MockAccountKeeperMockRecorder) IterateAccounts(ctx, process interface{
|
||||
}
|
||||
|
||||
// SetModuleAccount mocks base method.
|
||||
func (m *MockAccountKeeper) SetModuleAccount(arg0 context.Context, arg1 types0.ModuleAccountI) {
|
||||
func (m *MockAccountKeeper) SetModuleAccount(arg0 context.Context, arg1 types1.ModuleAccountI) {
|
||||
m.ctrl.T.Helper()
|
||||
m.ctrl.Call(m, "SetModuleAccount", arg0, arg1)
|
||||
}
|
||||
@ -144,7 +145,7 @@ func (m *MockBankKeeper) EXPECT() *MockBankKeeperMockRecorder {
|
||||
}
|
||||
|
||||
// BurnCoins mocks base method.
|
||||
func (m *MockBankKeeper) BurnCoins(arg0 context.Context, arg1 []byte, arg2 types0.Coins) error {
|
||||
func (m *MockBankKeeper) BurnCoins(arg0 context.Context, arg1 []byte, arg2 types1.Coins) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BurnCoins", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -158,7 +159,7 @@ func (mr *MockBankKeeperMockRecorder) BurnCoins(arg0, arg1, arg2 interface{}) *g
|
||||
}
|
||||
|
||||
// DelegateCoinsFromAccountToModule mocks base method.
|
||||
func (m *MockBankKeeper) DelegateCoinsFromAccountToModule(ctx context.Context, senderAddr types0.AccAddress, recipientModule string, amt types0.Coins) error {
|
||||
func (m *MockBankKeeper) DelegateCoinsFromAccountToModule(ctx context.Context, senderAddr types1.AccAddress, recipientModule string, amt types1.Coins) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "DelegateCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -172,10 +173,10 @@ func (mr *MockBankKeeperMockRecorder) DelegateCoinsFromAccountToModule(ctx, send
|
||||
}
|
||||
|
||||
// GetAllBalances mocks base method.
|
||||
func (m *MockBankKeeper) GetAllBalances(ctx context.Context, addr types0.AccAddress) types0.Coins {
|
||||
func (m *MockBankKeeper) GetAllBalances(ctx context.Context, addr types1.AccAddress) types1.Coins {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetAllBalances", ctx, addr)
|
||||
ret0, _ := ret[0].(types0.Coins)
|
||||
ret0, _ := ret[0].(types1.Coins)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -186,10 +187,10 @@ func (mr *MockBankKeeperMockRecorder) GetAllBalances(ctx, addr interface{}) *gom
|
||||
}
|
||||
|
||||
// GetBalance mocks base method.
|
||||
func (m *MockBankKeeper) GetBalance(ctx context.Context, addr types0.AccAddress, denom string) types0.Coin {
|
||||
func (m *MockBankKeeper) GetBalance(ctx context.Context, addr types1.AccAddress, denom string) types1.Coin {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetBalance", ctx, addr, denom)
|
||||
ret0, _ := ret[0].(types0.Coin)
|
||||
ret0, _ := ret[0].(types1.Coin)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -200,10 +201,10 @@ func (mr *MockBankKeeperMockRecorder) GetBalance(ctx, addr, denom interface{}) *
|
||||
}
|
||||
|
||||
// GetSupply mocks base method.
|
||||
func (m *MockBankKeeper) GetSupply(ctx context.Context, denom string) types0.Coin {
|
||||
func (m *MockBankKeeper) GetSupply(ctx context.Context, denom string) types1.Coin {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetSupply", ctx, denom)
|
||||
ret0, _ := ret[0].(types0.Coin)
|
||||
ret0, _ := ret[0].(types1.Coin)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -214,10 +215,10 @@ func (mr *MockBankKeeperMockRecorder) GetSupply(ctx, denom interface{}) *gomock.
|
||||
}
|
||||
|
||||
// LockedCoins mocks base method.
|
||||
func (m *MockBankKeeper) LockedCoins(ctx context.Context, addr types0.AccAddress) types0.Coins {
|
||||
func (m *MockBankKeeper) LockedCoins(ctx context.Context, addr types1.AccAddress) types1.Coins {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "LockedCoins", ctx, addr)
|
||||
ret0, _ := ret[0].(types0.Coins)
|
||||
ret0, _ := ret[0].(types1.Coins)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -228,7 +229,7 @@ func (mr *MockBankKeeperMockRecorder) LockedCoins(ctx, addr interface{}) *gomock
|
||||
}
|
||||
|
||||
// SendCoinsFromAccountToModule mocks base method.
|
||||
func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx context.Context, senderAddr types0.AccAddress, recipientModule string, amt types0.Coins) error {
|
||||
func (m *MockBankKeeper) SendCoinsFromAccountToModule(ctx context.Context, senderAddr types1.AccAddress, recipientModule string, amt types1.Coins) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendCoinsFromAccountToModule", ctx, senderAddr, recipientModule, amt)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -242,7 +243,7 @@ func (mr *MockBankKeeperMockRecorder) SendCoinsFromAccountToModule(ctx, senderAd
|
||||
}
|
||||
|
||||
// SendCoinsFromModuleToModule mocks base method.
|
||||
func (m *MockBankKeeper) SendCoinsFromModuleToModule(ctx context.Context, senderPool, recipientPool string, amt types0.Coins) error {
|
||||
func (m *MockBankKeeper) SendCoinsFromModuleToModule(ctx context.Context, senderPool, recipientPool string, amt types1.Coins) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SendCoinsFromModuleToModule", ctx, senderPool, recipientPool, amt)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -256,10 +257,10 @@ func (mr *MockBankKeeperMockRecorder) SendCoinsFromModuleToModule(ctx, senderPoo
|
||||
}
|
||||
|
||||
// SpendableCoins mocks base method.
|
||||
func (m *MockBankKeeper) SpendableCoins(ctx context.Context, addr types0.AccAddress) types0.Coins {
|
||||
func (m *MockBankKeeper) SpendableCoins(ctx context.Context, addr types1.AccAddress) types1.Coins {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SpendableCoins", ctx, addr)
|
||||
ret0, _ := ret[0].(types0.Coins)
|
||||
ret0, _ := ret[0].(types1.Coins)
|
||||
return ret0
|
||||
}
|
||||
|
||||
@ -270,7 +271,7 @@ func (mr *MockBankKeeperMockRecorder) SpendableCoins(ctx, addr interface{}) *gom
|
||||
}
|
||||
|
||||
// UndelegateCoinsFromModuleToAccount mocks base method.
|
||||
func (m *MockBankKeeper) UndelegateCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types0.AccAddress, amt types0.Coins) error {
|
||||
func (m *MockBankKeeper) UndelegateCoinsFromModuleToAccount(ctx context.Context, senderModule string, recipientAddr types1.AccAddress, amt types1.Coins) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "UndelegateCoinsFromModuleToAccount", ctx, senderModule, recipientAddr, amt)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -307,10 +308,10 @@ func (m *MockValidatorSet) EXPECT() *MockValidatorSetMockRecorder {
|
||||
}
|
||||
|
||||
// Delegation mocks base method.
|
||||
func (m *MockValidatorSet) Delegation(arg0 context.Context, arg1 types0.AccAddress, arg2 types0.ValAddress) (types0.DelegationI, error) {
|
||||
func (m *MockValidatorSet) Delegation(arg0 context.Context, arg1 types1.AccAddress, arg2 types1.ValAddress) (types1.DelegationI, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Delegation", arg0, arg1, arg2)
|
||||
ret0, _ := ret[0].(types0.DelegationI)
|
||||
ret0, _ := ret[0].(types1.DelegationI)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -322,7 +323,7 @@ func (mr *MockValidatorSetMockRecorder) Delegation(arg0, arg1, arg2 interface{})
|
||||
}
|
||||
|
||||
// GetPubKeyByConsAddr mocks base method.
|
||||
func (m *MockValidatorSet) GetPubKeyByConsAddr(arg0 context.Context, arg1 types0.ConsAddress) (crypto.PublicKey, error) {
|
||||
func (m *MockValidatorSet) GetPubKeyByConsAddr(arg0 context.Context, arg1 types1.ConsAddress) (crypto.PublicKey, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "GetPubKeyByConsAddr", arg0, arg1)
|
||||
ret0, _ := ret[0].(crypto.PublicKey)
|
||||
@ -337,7 +338,7 @@ func (mr *MockValidatorSetMockRecorder) GetPubKeyByConsAddr(arg0, arg1 interface
|
||||
}
|
||||
|
||||
// IterateBondedValidatorsByPower mocks base method.
|
||||
func (m *MockValidatorSet) IterateBondedValidatorsByPower(arg0 context.Context, arg1 func(int64, types0.ValidatorI) bool) error {
|
||||
func (m *MockValidatorSet) IterateBondedValidatorsByPower(arg0 context.Context, arg1 func(int64, types1.ValidatorI) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IterateBondedValidatorsByPower", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -351,7 +352,7 @@ func (mr *MockValidatorSetMockRecorder) IterateBondedValidatorsByPower(arg0, arg
|
||||
}
|
||||
|
||||
// IterateValidators mocks base method.
|
||||
func (m *MockValidatorSet) IterateValidators(arg0 context.Context, arg1 func(int64, types0.ValidatorI) bool) error {
|
||||
func (m *MockValidatorSet) IterateValidators(arg0 context.Context, arg1 func(int64, types1.ValidatorI) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IterateValidators", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -365,7 +366,7 @@ func (mr *MockValidatorSetMockRecorder) IterateValidators(arg0, arg1 interface{}
|
||||
}
|
||||
|
||||
// Jail mocks base method.
|
||||
func (m *MockValidatorSet) Jail(arg0 context.Context, arg1 types0.ConsAddress) error {
|
||||
func (m *MockValidatorSet) Jail(arg0 context.Context, arg1 types1.ConsAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Jail", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -394,7 +395,7 @@ func (mr *MockValidatorSetMockRecorder) MaxValidators(arg0 interface{}) *gomock.
|
||||
}
|
||||
|
||||
// Slash mocks base method.
|
||||
func (m *MockValidatorSet) Slash(arg0 context.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 math.LegacyDec) (math.Int, error) {
|
||||
func (m *MockValidatorSet) Slash(arg0 context.Context, arg1 types1.ConsAddress, arg2, arg3 int64, arg4 math.LegacyDec) (math.Int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Slash", arg0, arg1, arg2, arg3, arg4)
|
||||
ret0, _ := ret[0].(math.Int)
|
||||
@ -409,7 +410,7 @@ func (mr *MockValidatorSetMockRecorder) Slash(arg0, arg1, arg2, arg3, arg4 inter
|
||||
}
|
||||
|
||||
// SlashWithInfractionReason mocks base method.
|
||||
func (m *MockValidatorSet) SlashWithInfractionReason(arg0 context.Context, arg1 types0.ConsAddress, arg2, arg3 int64, arg4 math.LegacyDec, arg5 stakingv1beta1.Infraction) (math.Int, error) {
|
||||
func (m *MockValidatorSet) SlashWithInfractionReason(arg0 context.Context, arg1 types1.ConsAddress, arg2, arg3 int64, arg4 math.LegacyDec, arg5 stakingv1beta1.Infraction) (math.Int, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "SlashWithInfractionReason", arg0, arg1, arg2, arg3, arg4, arg5)
|
||||
ret0, _ := ret[0].(math.Int)
|
||||
@ -454,7 +455,7 @@ func (mr *MockValidatorSetMockRecorder) TotalBondedTokens(arg0 interface{}) *gom
|
||||
}
|
||||
|
||||
// Unjail mocks base method.
|
||||
func (m *MockValidatorSet) Unjail(arg0 context.Context, arg1 types0.ConsAddress) error {
|
||||
func (m *MockValidatorSet) Unjail(arg0 context.Context, arg1 types1.ConsAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Unjail", arg0, arg1)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -468,10 +469,10 @@ func (mr *MockValidatorSetMockRecorder) Unjail(arg0, arg1 interface{}) *gomock.C
|
||||
}
|
||||
|
||||
// Validator mocks base method.
|
||||
func (m *MockValidatorSet) Validator(arg0 context.Context, arg1 types0.ValAddress) (types0.ValidatorI, error) {
|
||||
func (m *MockValidatorSet) Validator(arg0 context.Context, arg1 types1.ValAddress) (types1.ValidatorI, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "Validator", arg0, arg1)
|
||||
ret0, _ := ret[0].(types0.ValidatorI)
|
||||
ret0, _ := ret[0].(types1.ValidatorI)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -483,10 +484,10 @@ func (mr *MockValidatorSetMockRecorder) Validator(arg0, arg1 interface{}) *gomoc
|
||||
}
|
||||
|
||||
// ValidatorByConsAddr mocks base method.
|
||||
func (m *MockValidatorSet) ValidatorByConsAddr(arg0 context.Context, arg1 types0.ConsAddress) (types0.ValidatorI, error) {
|
||||
func (m *MockValidatorSet) ValidatorByConsAddr(arg0 context.Context, arg1 types1.ConsAddress) (types1.ValidatorI, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "ValidatorByConsAddr", arg0, arg1)
|
||||
ret0, _ := ret[0].(types0.ValidatorI)
|
||||
ret0, _ := ret[0].(types1.ValidatorI)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
@ -535,7 +536,7 @@ func (mr *MockDelegationSetMockRecorder) GetValidatorSet() *gomock.Call {
|
||||
}
|
||||
|
||||
// IterateDelegations mocks base method.
|
||||
func (m *MockDelegationSet) IterateDelegations(ctx context.Context, delegator types0.AccAddress, fn func(int64, types0.DelegationI) bool) error {
|
||||
func (m *MockDelegationSet) IterateDelegations(ctx context.Context, delegator types1.AccAddress, fn func(int64, types1.DelegationI) bool) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "IterateDelegations", ctx, delegator, fn)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -571,8 +572,22 @@ func (m *MockStakingHooks) EXPECT() *MockStakingHooksMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// AfterConsensusPubKeyUpdate mocks base method.
|
||||
func (m *MockStakingHooks) AfterConsensusPubKeyUpdate(ctx context.Context, oldPubKey, newPubKey types0.PubKey, rotationFee types1.Coin) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterConsensusPubKeyUpdate", ctx, oldPubKey, newPubKey, rotationFee)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// AfterConsensusPubKeyUpdate indicates an expected call of AfterConsensusPubKeyUpdate.
|
||||
func (mr *MockStakingHooksMockRecorder) AfterConsensusPubKeyUpdate(ctx, oldPubKey, newPubKey, rotationFee interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AfterConsensusPubKeyUpdate", reflect.TypeOf((*MockStakingHooks)(nil).AfterConsensusPubKeyUpdate), ctx, oldPubKey, newPubKey, rotationFee)
|
||||
}
|
||||
|
||||
// AfterDelegationModified mocks base method.
|
||||
func (m *MockStakingHooks) AfterDelegationModified(ctx context.Context, delAddr types0.AccAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) AfterDelegationModified(ctx context.Context, delAddr types1.AccAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterDelegationModified", ctx, delAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -600,7 +615,7 @@ func (mr *MockStakingHooksMockRecorder) AfterUnbondingInitiated(ctx, id interfac
|
||||
}
|
||||
|
||||
// AfterValidatorBeginUnbonding mocks base method.
|
||||
func (m *MockStakingHooks) AfterValidatorBeginUnbonding(ctx context.Context, consAddr types0.ConsAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) AfterValidatorBeginUnbonding(ctx context.Context, consAddr types1.ConsAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterValidatorBeginUnbonding", ctx, consAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -614,7 +629,7 @@ func (mr *MockStakingHooksMockRecorder) AfterValidatorBeginUnbonding(ctx, consAd
|
||||
}
|
||||
|
||||
// AfterValidatorBonded mocks base method.
|
||||
func (m *MockStakingHooks) AfterValidatorBonded(ctx context.Context, consAddr types0.ConsAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) AfterValidatorBonded(ctx context.Context, consAddr types1.ConsAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterValidatorBonded", ctx, consAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -628,7 +643,7 @@ func (mr *MockStakingHooksMockRecorder) AfterValidatorBonded(ctx, consAddr, valA
|
||||
}
|
||||
|
||||
// AfterValidatorCreated mocks base method.
|
||||
func (m *MockStakingHooks) AfterValidatorCreated(ctx context.Context, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) AfterValidatorCreated(ctx context.Context, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterValidatorCreated", ctx, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -642,7 +657,7 @@ func (mr *MockStakingHooksMockRecorder) AfterValidatorCreated(ctx, valAddr inter
|
||||
}
|
||||
|
||||
// AfterValidatorRemoved mocks base method.
|
||||
func (m *MockStakingHooks) AfterValidatorRemoved(ctx context.Context, consAddr types0.ConsAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) AfterValidatorRemoved(ctx context.Context, consAddr types1.ConsAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "AfterValidatorRemoved", ctx, consAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -656,7 +671,7 @@ func (mr *MockStakingHooksMockRecorder) AfterValidatorRemoved(ctx, consAddr, val
|
||||
}
|
||||
|
||||
// BeforeDelegationCreated mocks base method.
|
||||
func (m *MockStakingHooks) BeforeDelegationCreated(ctx context.Context, delAddr types0.AccAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) BeforeDelegationCreated(ctx context.Context, delAddr types1.AccAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforeDelegationCreated", ctx, delAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -670,7 +685,7 @@ func (mr *MockStakingHooksMockRecorder) BeforeDelegationCreated(ctx, delAddr, va
|
||||
}
|
||||
|
||||
// BeforeDelegationRemoved mocks base method.
|
||||
func (m *MockStakingHooks) BeforeDelegationRemoved(ctx context.Context, delAddr types0.AccAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) BeforeDelegationRemoved(ctx context.Context, delAddr types1.AccAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforeDelegationRemoved", ctx, delAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -684,7 +699,7 @@ func (mr *MockStakingHooksMockRecorder) BeforeDelegationRemoved(ctx, delAddr, va
|
||||
}
|
||||
|
||||
// BeforeDelegationSharesModified mocks base method.
|
||||
func (m *MockStakingHooks) BeforeDelegationSharesModified(ctx context.Context, delAddr types0.AccAddress, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) BeforeDelegationSharesModified(ctx context.Context, delAddr types1.AccAddress, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforeDelegationSharesModified", ctx, delAddr, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -698,7 +713,7 @@ func (mr *MockStakingHooksMockRecorder) BeforeDelegationSharesModified(ctx, delA
|
||||
}
|
||||
|
||||
// BeforeValidatorModified mocks base method.
|
||||
func (m *MockStakingHooks) BeforeValidatorModified(ctx context.Context, valAddr types0.ValAddress) error {
|
||||
func (m *MockStakingHooks) BeforeValidatorModified(ctx context.Context, valAddr types1.ValAddress) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforeValidatorModified", ctx, valAddr)
|
||||
ret0, _ := ret[0].(error)
|
||||
@ -712,7 +727,7 @@ func (mr *MockStakingHooksMockRecorder) BeforeValidatorModified(ctx, valAddr int
|
||||
}
|
||||
|
||||
// BeforeValidatorSlashed mocks base method.
|
||||
func (m *MockStakingHooks) BeforeValidatorSlashed(ctx context.Context, valAddr types0.ValAddress, fraction math.LegacyDec) error {
|
||||
func (m *MockStakingHooks) BeforeValidatorSlashed(ctx context.Context, valAddr types1.ValAddress, fraction math.LegacyDec) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "BeforeValidatorSlashed", ctx, valAddr, fraction)
|
||||
ret0, _ := ret[0].(error)
|
||||
|
||||
@ -18,6 +18,7 @@ func RegisterLegacyAminoCodec(cdc *codec.LegacyAmino) {
|
||||
legacy.RegisterAminoMsg(cdc, &MsgBeginRedelegate{}, "cosmos-sdk/MsgBeginRedelegate")
|
||||
legacy.RegisterAminoMsg(cdc, &MsgCancelUnbondingDelegation{}, "cosmos-sdk/MsgCancelUnbondingDelegation")
|
||||
legacy.RegisterAminoMsg(cdc, &MsgUpdateParams{}, "cosmos-sdk/x/staking/MsgUpdateParams")
|
||||
legacy.RegisterAminoMsg(cdc, &MsgRotateConsPubKey{}, "cosmos-sdk/MsgRotateConsPubKey")
|
||||
|
||||
cdc.RegisterInterface((*isStakeAuthorization_Validators)(nil), nil)
|
||||
cdc.RegisterConcrete(&StakeAuthorization_AllowList{}, "cosmos-sdk/StakeAuthorization/AllowList", nil)
|
||||
|
||||
@ -9,6 +9,7 @@ import (
|
||||
"cosmossdk.io/core/address"
|
||||
"cosmossdk.io/math"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -107,6 +108,7 @@ type StakingHooks interface {
|
||||
AfterDelegationModified(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) error
|
||||
BeforeValidatorSlashed(ctx context.Context, valAddr sdk.ValAddress, fraction math.LegacyDec) error
|
||||
AfterUnbondingInitiated(ctx context.Context, id uint64) error
|
||||
AfterConsensusPubKeyUpdate(ctx context.Context, oldPubKey, newPubKey cryptotypes.PubKey, rotationFee sdk.Coin) error
|
||||
}
|
||||
|
||||
// StakingHooksWrapper is a wrapper for modules to inject StakingHooks using depinject.
|
||||
|
||||
@ -5,6 +5,7 @@ import (
|
||||
|
||||
sdkmath "cosmossdk.io/math"
|
||||
|
||||
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
|
||||
sdk "github.com/cosmos/cosmos-sdk/types"
|
||||
)
|
||||
|
||||
@ -116,3 +117,12 @@ func (h MultiStakingHooks) AfterUnbondingInitiated(ctx context.Context, id uint6
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (h MultiStakingHooks) AfterConsensusPubKeyUpdate(ctx context.Context, oldPubKey, newPubKey cryptotypes.PubKey, rotationFee sdk.Coin) error {
|
||||
for i := range h {
|
||||
if err := h[i].AfterConsensusPubKeyUpdate(ctx, oldPubKey, newPubKey, rotationFee); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@ -25,10 +25,10 @@ const (
|
||||
// GovModuleName is the name of the gov module
|
||||
GovModuleName = "gov"
|
||||
|
||||
// distributionModuleName duplicates the distribution module's name to avoid a cyclic dependency with x/distribution.
|
||||
// PoolModuleName duplicates the Protocolpool module's name to avoid a cyclic dependency with x/protocolpool.
|
||||
// It should be synced with the distribution module's name if it is ever changed.
|
||||
// See: https://github.com/cosmos/cosmos-sdk/blob/912390d5fc4a32113ea1aacc98b77b2649aea4c2/x/distribution/types/keys.go#L15
|
||||
DistributionModuleName = "distribution"
|
||||
PoolModuleName = "protocolpool"
|
||||
)
|
||||
|
||||
var (
|
||||
@ -68,7 +68,8 @@ var (
|
||||
BlockConsPubKeyRotationHistoryKey = collections.NewPrefix(102) // prefix for consPubkey rotation history by height
|
||||
ValidatorConsensusKeyRotationRecordQueueKey = collections.NewPrefix(103) // this key is used to set the unbonding period time on each rotation
|
||||
ValidatorConsensusKeyRotationRecordIndexKey = collections.NewPrefix(104) // this key is used to restrict the validator next rotation within waiting (unbonding) period
|
||||
RotatedConsKeyMapIndex = collections.NewPrefix(105) // prefix for rotated cons address to new cons address
|
||||
NewToOldConsKeyMap = collections.NewPrefix(105) // prefix for rotated cons address to new cons address
|
||||
OldToNewConsKeyMap = collections.NewPrefix(106) // prefix for rotated cons address to new cons address
|
||||
)
|
||||
|
||||
// UnbondingType defines the type of unbonding operation
|
||||
|
||||
@ -142,3 +142,35 @@ func NewMsgCancelUnbondingDelegation(delAddr, valAddr string, creationHeight int
|
||||
CreationHeight: creationHeight,
|
||||
}
|
||||
}
|
||||
|
||||
// NewMsgRotateConsPubKey creates a new MsgRotateConsPubKey instance.
|
||||
func NewMsgRotateConsPubKey(valAddr string, pubKey cryptotypes.PubKey) (*MsgRotateConsPubKey, error) {
|
||||
var pkAny *codectypes.Any
|
||||
if pubKey != nil {
|
||||
var err error
|
||||
if pkAny, err = codectypes.NewAnyWithValue(pubKey); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return &MsgRotateConsPubKey{
|
||||
ValidatorAddress: valAddr,
|
||||
NewPubkey: pkAny,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
|
||||
func (msg MsgRotateConsPubKey) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
||||
var pubKey cryptotypes.PubKey
|
||||
return unpacker.UnpackAny(msg.NewPubkey, &pubKey)
|
||||
}
|
||||
|
||||
// UnpackInterfaces implements UnpackInterfacesMessage.UnpackInterfaces
|
||||
func (hi ConsPubKeyRotationHistory) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
|
||||
var oldPubKey cryptotypes.PubKey
|
||||
err := unpacker.UnpackAny(hi.OldConsPubkey, &oldPubKey)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var newPubKey cryptotypes.PubKey
|
||||
return unpacker.UnpackAny(hi.NewConsPubkey, &newPubKey)
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user