diff --git a/CHANGELOG.md b/CHANGELOG.md index 5cfb9864cb50..22b18d6f19f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -56,6 +56,9 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (x/staking) [#17481](https://github.com/cosmos/cosmos-sdk/pull/17481) Use collections for `UnbondingQueue`: + * remove from `Keeper`: `UBDQueueIterator` + * remove from `types`: `GetUnbondingDelegationTimeKey` * (x/staking) [#17123](https://github.com/cosmos/cosmos-sdk/pull/17123) Use collections for `Validators` * (x/staking) [#17270](https://github.com/cosmos/cosmos-sdk/pull/17270) Use collections for `UnbondingDelegation`: * remove from `types`: `GetUBDsKey` diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index d5824cedcf89..801a370808fb 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -8,7 +8,6 @@ import ( "time" "cosmossdk.io/collections" - corestore "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" "cosmossdk.io/math" storetypes "cosmossdk.io/store/types" @@ -347,27 +346,21 @@ func (k Keeper) SetUnbondingDelegationEntry( // is a slice of DVPairs corresponding to unbonding delegations that expire at a // certain time. func (k Keeper) GetUBDQueueTimeSlice(ctx context.Context, timestamp time.Time) (dvPairs []types.DVPair, err error) { - store := k.storeService.OpenKVStore(ctx) - - bz, err := store.Get(types.GetUnbondingDelegationTimeKey(timestamp)) - if bz == nil || err != nil { - return []types.DVPair{}, err + pairs, err := k.UnbondingQueue.Get(ctx, timestamp) + if err != nil { + if !errors.Is(err, collections.ErrNotFound) { + return nil, err + } + return []types.DVPair{}, nil } - pairs := types.DVPairs{} - err = k.cdc.Unmarshal(bz, &pairs) - return pairs.Pairs, err } // SetUBDQueueTimeSlice sets a specific unbonding queue timeslice. func (k Keeper) SetUBDQueueTimeSlice(ctx context.Context, timestamp time.Time, keys []types.DVPair) error { - store := k.storeService.OpenKVStore(ctx) - bz, err := k.cdc.Marshal(&types.DVPairs{Pairs: keys}) - if err != nil { - return err - } - return store.Set(types.GetUnbondingDelegationTimeKey(timestamp), bz) + dvPairs := types.DVPairs{Pairs: keys} + return k.UnbondingQueue.Set(ctx, timestamp, dvPairs) } // InsertUBDQueue inserts an unbonding delegation to the appropriate timeslice @@ -379,9 +372,8 @@ func (k Keeper) InsertUBDQueue(ctx context.Context, ubd types.UnbondingDelegatio if err != nil { return err } - if len(timeSlice) == 0 { - if err = k.SetUBDQueueTimeSlice(ctx, completionTime, []types.DVPair{dvPair}); err != nil { + if err := k.SetUBDQueueTimeSlice(ctx, completionTime, []types.DVPair{dvPair}); err != nil { return err } return nil @@ -391,38 +383,30 @@ func (k Keeper) InsertUBDQueue(ctx context.Context, ubd types.UnbondingDelegatio return k.SetUBDQueueTimeSlice(ctx, completionTime, timeSlice) } -// UBDQueueIterator returns all the unbonding queue timeslices from time 0 until endTime. -func (k Keeper) UBDQueueIterator(ctx context.Context, endTime time.Time) (corestore.Iterator, error) { - store := k.storeService.OpenKVStore(ctx) - return store.Iterator(types.UnbondingQueueKey, - storetypes.InclusiveEndBytes(types.GetUnbondingDelegationTimeKey(endTime))) -} - // DequeueAllMatureUBDQueue returns a concatenated list of all the timeslices inclusively previous to // currTime, and deletes the timeslices from the queue. func (k Keeper) DequeueAllMatureUBDQueue(ctx context.Context, currTime time.Time) (matureUnbonds []types.DVPair, err error) { - store := k.storeService.OpenKVStore(ctx) - - // gets an iterator for all timeslices from time 0 until the current Blockheader time - unbondingTimesliceIterator, err := k.UBDQueueIterator(ctx, currTime) + // get an iterator for all timeslices from time 0 until the current Blockheader time + iter, err := k.UnbondingQueue.Iterate(ctx, (&collections.Range[time.Time]{}).EndInclusive(currTime)) if err != nil { return matureUnbonds, err } - defer unbondingTimesliceIterator.Close() + defer iter.Close() - for ; unbondingTimesliceIterator.Valid(); unbondingTimesliceIterator.Next() { - timeslice := types.DVPairs{} - value := unbondingTimesliceIterator.Value() - if err = k.cdc.Unmarshal(value, ×lice); err != nil { + for ; iter.Valid(); iter.Next() { + timeslice, err := iter.Value() + if err != nil { return matureUnbonds, err } matureUnbonds = append(matureUnbonds, timeslice.Pairs...) - - if err = store.Delete(unbondingTimesliceIterator.Key()); err != nil { + key, err := iter.Key() + if err != nil { + return matureUnbonds, err + } + if err = k.UnbondingQueue.Remove(ctx, key); err != nil { return matureUnbonds, err } - } return matureUnbonds, nil diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index 792b447e51f4..74543035580e 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -3,6 +3,7 @@ package keeper import ( "context" "fmt" + "time" "cosmossdk.io/collections" collcodec "cosmossdk.io/collections/codec" @@ -44,6 +45,7 @@ type Keeper struct { Redelegations collections.Map[collections.Triple[[]byte, []byte, []byte], types.Redelegation] Delegations collections.Map[collections.Pair[sdk.AccAddress, sdk.ValAddress], types.Delegation] UnbondingIndex collections.Map[uint64, []byte] + UnbondingQueue collections.Map[time.Time, types.DVPairs] Validators collections.Map[[]byte, types.Validator] UnbondingDelegations collections.Map[collections.Pair[[]byte, []byte], types.UnbondingDelegation] RedelegationsByValDst collections.Map[collections.Triple[[]byte, []byte, []byte], []byte] @@ -125,6 +127,7 @@ func NewKeeper( codec.CollValue[types.Redelegation](cdc), ), UnbondingIndex: collections.NewMap(sb, types.UnbondingIndexKey, "unbonding_index", collections.Uint64Key, collections.BytesValue), + UnbondingQueue: collections.NewMap(sb, types.UnbondingQueueKey, "unbonidng_queue", sdk.TimeKey, codec.CollValue[types.DVPairs](cdc)), // key format is: 53 | lengthPrefixedBytes(SrcValAddr) | lengthPrefixedBytes(AccAddr) | lengthPrefixedBytes(DstValAddr) RedelegationsByValSrc: collections.NewMap( sb, types.RedelegationByValSrcIndexKey, diff --git a/x/staking/keeper/keeper_test.go b/x/staking/keeper/keeper_test.go index 66f0227a89f4..bba448548031 100644 --- a/x/staking/keeper/keeper_test.go +++ b/x/staking/keeper/keeper_test.go @@ -174,6 +174,13 @@ func getUBDKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { return append(append(unbondingDelegationKey, addresstypes.MustLengthPrefix(delAddr)...), addresstypes.MustLengthPrefix(valAddr)...) } +// getUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator +func getUnbondingDelegationTimeKey(timestamp time.Time) []byte { + bz := sdk.FormatTimeBytes(timestamp) + unbondingQueueKey := []byte{0x41} + return append(unbondingQueueKey, bz...) +} + // getValidatorKey creates the key for the validator with address // VALUE: staking/Validator func getValidatorKey(operatorAddr sdk.ValAddress) []byte { @@ -299,8 +306,34 @@ func (s *KeeperTestSuite) TestUnbondingDelegationsMigrationToColls() { s.Require().NoError(err) } -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) +func (s *KeeperTestSuite) TestUBDQueueMigrationToColls() { + s.SetupTest() + + err := testutil.DiffCollectionsMigration( + s.ctx, + s.key, + 100, + func(i int64) { + date := time.Date(2023, 8, 21, 14, 33, 1, 0, &time.Location{}) + // legacy Set method + s.ctx.KVStore(s.key).Set(getUnbondingDelegationTimeKey(date), []byte{}) + }, + "7b8965aacc97646d6766a5a53bae397fe149d1c98fed027bea8774a18621ce6a", + ) + s.Require().NoError(err) + + err = testutil.DiffCollectionsMigration( + s.ctx, + s.key, + 100, + func(i int64) { + date := time.Date(2023, 8, 21, 14, 33, 1, 0, &time.Location{}) + err := s.stakingKeeper.SetUBDQueueTimeSlice(s.ctx, date, nil) + s.Require().NoError(err) + }, + "7b8965aacc97646d6766a5a53bae397fe149d1c98fed027bea8774a18621ce6a", + ) + s.Require().NoError(err) } func (s *KeeperTestSuite) TestValidatorsMigrationToColls() { @@ -362,3 +395,7 @@ func (s *KeeperTestSuite) TestValidatorsMigrationToColls() { ) s.Require().NoError(err) } + +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} diff --git a/x/staking/migrations/v2/store_test.go b/x/staking/migrations/v2/store_test.go index c7a933c43036..8baeb3193695 100644 --- a/x/staking/migrations/v2/store_test.go +++ b/x/staking/migrations/v2/store_test.go @@ -101,7 +101,7 @@ func TestStoreMigration(t *testing.T) { { "UnbondingQueueKey", v1.GetUnbondingDelegationTimeKey(now), - types.GetUnbondingDelegationTimeKey(now), + getUnbondingDelegationTimeKey(now), }, { "RedelegationQueueKey", @@ -141,6 +141,11 @@ func TestStoreMigration(t *testing.T) { } } +func getUnbondingDelegationTimeKey(timestamp time.Time) []byte { + bz := sdk.FormatTimeBytes(timestamp) + return append(types.UnbondingQueueKey, bz...) +} + func getValidatorKey(operatorAddr sdk.ValAddress) []byte { return append(types.ValidatorsKey, sdkaddress.MustLengthPrefix(operatorAddr)...) } diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 3e4c08427bd3..19c9627decd5 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -50,9 +50,9 @@ var ( UnbondingIndexKey = collections.NewPrefix(56) // prefix for an index for looking up unbonding operations by their IDs UnbondingTypeKey = collections.NewPrefix(57) // prefix for an index containing the type of unbonding operations - UnbondingQueueKey = []byte{0x41} // prefix for the timestamps in unbonding queue - RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue - ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue + UnbondingQueueKey = collections.NewPrefix(65) // prefix for the timestamps in unbonding queue + RedelegationQueueKey = []byte{0x42} // prefix for the timestamps in redelegations queue + ValidatorQueueKey = []byte{0x43} // prefix for the timestamps in validator queue HistoricalInfoKey = collections.NewPrefix(80) // prefix for the historical info ValidatorUpdatesKey = collections.NewPrefix(97) // prefix for the end block validator updates key @@ -221,12 +221,6 @@ func GetUBDsByValIndexKey(valAddr sdk.ValAddress) []byte { return append(UnbondingDelegationByValIndexKey, address.MustLengthPrefix(valAddr)...) } -// GetUnbondingDelegationTimeKey creates the prefix for all unbonding delegations from a delegator -func GetUnbondingDelegationTimeKey(timestamp time.Time) []byte { - bz := sdk.FormatTimeBytes(timestamp) - return append(UnbondingQueueKey, bz...) -} - // GetREDKey returns a key prefix for indexing a redelegation from a delegator // and source validator to a destination validator. func GetREDKey(delAddr sdk.AccAddress, valSrcAddr, valDstAddr sdk.ValAddress) []byte {