Skip to content

Commit

Permalink
refactor(x/staking): migrate RedelegationQueue to collections (#17486)
Browse files Browse the repository at this point in the history
Co-authored-by: Facundo Medica <[email protected]>
Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
3 people authored Sep 8, 2023
1 parent e53830d commit 2085695
Show file tree
Hide file tree
Showing 6 changed files with 91 additions and 56 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ Ref: https://keepachangelog.com/en/1.0.0/

### API Breaking Changes

* (x/staking) [#17486](https://github.com/cosmos/cosmos-sdk/pull/17486) Use collections for `RedelegationQueueKey`:
* remove from `types`: `GetRedelegationTimeKey`
* remove from `Keeper`: `RedelegationQueueIterator`
* (x/staking) [#17562](https://github.com/cosmos/cosmos-sdk/pull/17562) Use collections for `ValidatorQueue`
* remove from `types`: `GetValidatorQueueKey`, `ParseValidatorQueueKey`
* remove from `Keeper`: `ValidatorQueueIterator`
Expand Down
64 changes: 19 additions & 45 deletions x/staking/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import (
"cosmossdk.io/collections"
errorsmod "cosmossdk.io/errors"
"cosmossdk.io/math"
storetypes "cosmossdk.io/store/types"

sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
Expand Down Expand Up @@ -610,33 +609,18 @@ func (k Keeper) RemoveRedelegation(ctx context.Context, red types.Redelegation)
// timeslice is a slice of DVVTriplets corresponding to redelegations that
// expire at a certain time.
func (k Keeper) GetRedelegationQueueTimeSlice(ctx context.Context, timestamp time.Time) (dvvTriplets []types.DVVTriplet, err error) {
store := k.storeService.OpenKVStore(ctx)
bz, err := store.Get(types.GetRedelegationTimeKey(timestamp))
if err != nil {
return nil, err
}

if bz == nil {
return []types.DVVTriplet{}, nil
}

triplets := types.DVVTriplets{}
err = k.cdc.Unmarshal(bz, &triplets)
if err != nil {
return nil, err
triplets, err := k.RedelegationQueue.Get(ctx, timestamp)
if err != nil && !errors.Is(err, collections.ErrNotFound) {
return []types.DVVTriplet{}, err
}

return triplets.Triplets, nil
}

// SetRedelegationQueueTimeSlice sets a specific redelegation queue timeslice.
func (k Keeper) SetRedelegationQueueTimeSlice(ctx context.Context, timestamp time.Time, keys []types.DVVTriplet) error {
store := k.storeService.OpenKVStore(ctx)
bz, err := k.cdc.Marshal(&types.DVVTriplets{Triplets: keys})
if err != nil {
return err
}
return store.Set(types.GetRedelegationTimeKey(timestamp), bz)
triplets := types.DVVTriplets{Triplets: keys}
return k.RedelegationQueue.Set(ctx, timestamp, triplets)
}

// InsertRedelegationQueue insert an redelegation delegation to the appropriate
Expand All @@ -660,38 +644,28 @@ func (k Keeper) InsertRedelegationQueue(ctx context.Context, red types.Redelegat
return k.SetRedelegationQueueTimeSlice(ctx, completionTime, timeSlice)
}

// RedelegationQueueIterator returns all the redelegation queue timeslices from
// time 0 until endTime.
func (k Keeper) RedelegationQueueIterator(ctx context.Context, endTime time.Time) (storetypes.Iterator, error) {
store := k.storeService.OpenKVStore(ctx)
return store.Iterator(types.RedelegationQueueKey, storetypes.InclusiveEndBytes(types.GetRedelegationTimeKey(endTime)))
}

// DequeueAllMatureRedelegationQueue returns a concatenated list of all the
// timeslices inclusively previous to currTime, and deletes the timeslices from
// the queue.
func (k Keeper) DequeueAllMatureRedelegationQueue(ctx context.Context, currTime time.Time) (matureRedelegations []types.DVVTriplet, err error) {
store := k.storeService.OpenKVStore(ctx)
var keys []time.Time

// gets an iterator for all timeslices from time 0 until the current Blockheader time
sdkCtx := sdk.UnwrapSDKContext(ctx)
redelegationTimesliceIterator, err := k.RedelegationQueueIterator(ctx, sdkCtx.HeaderInfo().Time)

// gets an iterator for all timeslices from time 0 until the current Blockheader time
rng := (&collections.Range[time.Time]{}).EndInclusive(sdkCtx.HeaderInfo().Time)
err = k.RedelegationQueue.Walk(ctx, rng, func(key time.Time, value types.DVVTriplets) (bool, error) {
keys = append(keys, key)
matureRedelegations = append(matureRedelegations, value.Triplets...)
return false, nil
})
if err != nil {
return nil, err
return matureRedelegations, err
}
defer redelegationTimesliceIterator.Close()

for ; redelegationTimesliceIterator.Valid(); redelegationTimesliceIterator.Next() {
timeslice := types.DVVTriplets{}
value := redelegationTimesliceIterator.Value()
if err = k.cdc.Unmarshal(value, &timeslice); err != nil {
return nil, err
}

matureRedelegations = append(matureRedelegations, timeslice.Triplets...)

if err = store.Delete(redelegationTimesliceIterator.Key()); err != nil {
return nil, err
for _, key := range keys {
err := k.RedelegationQueue.Remove(ctx, key)
if err != nil {
return matureRedelegations, err
}
}

Expand Down
5 changes: 4 additions & 1 deletion x/staking/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,8 @@ type Keeper struct {
RedelegationsByValSrc collections.Map[collections.Triple[[]byte, []byte, []byte], []byte]
// UnbondingDelegationByValIndex key: valAddr+delAddr | value: none used (index key for UnbondingDelegations stored by validator index)
UnbondingDelegationByValIndex collections.Map[collections.Pair[[]byte, []byte], []byte]
// RedelegationQueue key: Timestamp | value: DVVTriplets [delAddr+valSrcAddr+valDstAddr]
RedelegationQueue collections.Map[time.Time, types.DVVTriplets]
// ValidatorQueue key: len(timestamp bytes)+timestamp+height | value: ValAddresses
ValidatorQueue collections.Map[collections.Triple[uint64, time.Time, uint64], types.ValAddresses]
// LastValidatorPower key: valAddr | value: power(gogotypes.Int64Value())
Expand Down Expand Up @@ -180,7 +182,8 @@ func NewKeeper(
),
collections.BytesValue,
),
Validators: collections.NewMap(sb, types.ValidatorsKey, "validators", sdk.LengthPrefixedBytesKey, codec.CollValue[types.Validator](cdc)), // sdk.LengthPrefixedBytesKey is needed to retain state compatibility
RedelegationQueue: collections.NewMap(sb, types.RedelegationQueueKey, "redelegation_queue", sdk.TimeKey, codec.CollValue[types.DVVTriplets](cdc)),
Validators: collections.NewMap(sb, types.ValidatorsKey, "validators", sdk.LengthPrefixedBytesKey, codec.CollValue[types.Validator](cdc)), // sdk.LengthPrefixedBytesKey is needed to retain state compatibility
UnbondingDelegations: collections.NewMap(
sb, types.UnbondingDelegationKey,
"unbonding_delegation",
Expand Down
58 changes: 58 additions & 0 deletions x/staking/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,14 @@ func getREDsFromValSrcIndexKey(valSrcAddr sdk.ValAddress) []byte {
return append(redelegationByValSrcIndexKey, addresstypes.MustLengthPrefix(valSrcAddr)...)
}

// getRedelegationTimeKey returns a key prefix for indexing an unbonding
// redelegation based on a completion time.
func getRedelegationTimeKey(timestamp time.Time) []byte {
bz := sdk.FormatTimeBytes(timestamp)
redelegationQueueKey := []byte{0x42}
return append(redelegationQueueKey, bz...)
}

// getUBDKey creates the key for an unbonding delegation by delegator and validator addr
// VALUE: staking/UnbondingDelegation
func getUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte {
Expand Down Expand Up @@ -510,6 +518,56 @@ func (s *KeeperTestSuite) TestValidatorQueueMigrationToColls() {
s.Require().NoError(err)
}

func (s *KeeperTestSuite) TestRedelegationQueueMigrationToColls() {
s.SetupTest()

addrs, valAddrs := createValAddrs(101)
err := testutil.DiffCollectionsMigration(
s.ctx,
s.key,
100,
func(i int64) {
date := time.Unix(i, i)
dvvTriplets := stakingtypes.DVVTriplets{
Triplets: []stakingtypes.DVVTriplet{
{
DelegatorAddress: addrs[i].String(),
ValidatorSrcAddress: valAddrs[i].String(),
ValidatorDstAddress: valAddrs[i+1].String(),
},
},
}
bz, err := s.cdc.Marshal(&dvvTriplets)
s.Require().NoError(err)
s.ctx.KVStore(s.key).Set(getRedelegationTimeKey(date), bz)
},
"de104dd19c7a72c6b0ad03d25c897313bb1473befc118952ad88e6a8726749c9",
)
s.Require().NoError(err)

err = testutil.DiffCollectionsMigration(
s.ctx,
s.key,
100,
func(i int64) {
date := time.Unix(i, i)
dvvTriplets := stakingtypes.DVVTriplets{
Triplets: []stakingtypes.DVVTriplet{
{
DelegatorAddress: addrs[i].String(),
ValidatorSrcAddress: valAddrs[i].String(),
ValidatorDstAddress: valAddrs[i+1].String(),
},
},
}
err := s.stakingKeeper.SetRedelegationQueueTimeSlice(s.ctx, date, dvvTriplets.Triplets)
s.Require().NoError(err)
},
"de104dd19c7a72c6b0ad03d25c897313bb1473befc118952ad88e6a8726749c9",
)
s.Require().NoError(err)
}

func TestKeeperTestSuite(t *testing.T) {
suite.Run(t, new(KeeperTestSuite))
}
7 changes: 6 additions & 1 deletion x/staking/migrations/v2/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func TestStoreMigration(t *testing.T) {
{
"RedelegationQueueKey",
v1.GetRedelegationTimeKey(now),
types.GetRedelegationTimeKey(now),
getRedelegationTimeKey(now),
},
{
"ValidatorQueueKey",
Expand Down Expand Up @@ -141,6 +141,11 @@ func TestStoreMigration(t *testing.T) {
}
}

func getRedelegationTimeKey(timestamp time.Time) []byte {
bz := sdk.FormatTimeBytes(timestamp)
return append(types.RedelegationQueueKey, bz...)
}

func getLastValidatorPowerKey(operator sdk.ValAddress) []byte {
return append(types.LastValidatorPowerKey, sdkaddress.MustLengthPrefix(operator)...)
}
Expand Down
10 changes: 1 addition & 9 deletions x/staking/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package types

import (
"encoding/binary"
"time"

"cosmossdk.io/collections"
addresscodec "cosmossdk.io/core/address"
Expand Down Expand Up @@ -50,7 +49,7 @@ var (
UnbondingTypeKey = collections.NewPrefix(57) // prefix for an index containing the type of unbonding operations

UnbondingQueueKey = collections.NewPrefix(65) // prefix for the timestamps in unbonding queue
RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue
RedelegationQueueKey = collections.NewPrefix(66) // prefix for the timestamps in redelegations queue
ValidatorQueueKey = collections.NewPrefix(67) // prefix for the timestamps in validator queue

HistoricalInfoKey = collections.NewPrefix(80) // prefix for the historical info
Expand Down Expand Up @@ -161,13 +160,6 @@ func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []
return key
}

// GetRedelegationTimeKey returns a key prefix for indexing an unbonding
// redelegation based on a completion time.
func GetRedelegationTimeKey(timestamp time.Time) []byte {
bz := sdk.FormatTimeBytes(timestamp)
return append(RedelegationQueueKey, bz...)
}

// GetREDsKey returns a key prefix for indexing a redelegation from a delegator
// address.
func GetREDsKey(delAddr sdk.AccAddress) []byte {
Expand Down

0 comments on commit 2085695

Please sign in to comment.