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

refactor(x/staking): migrate UnbondingQueue to collections #17481

Merged
merged 17 commits into from
Aug 29, 2023
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
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
58 changes: 23 additions & 35 deletions x/staking/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -391,38 +383,34 @@ 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, &timeslice); 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
}
}

if err != nil {
return matureUnbonds, err
}

return matureUnbonds, nil
Expand Down
3 changes: 3 additions & 0 deletions x/staking/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"context"
"fmt"
"time"

"cosmossdk.io/collections"
collcodec "cosmossdk.io/collections/codec"
Expand Down Expand Up @@ -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]
Expand Down Expand Up @@ -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,
Expand Down
41 changes: 39 additions & 2 deletions x/staking/keeper/keeper_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -362,3 +395,7 @@ func (s *KeeperTestSuite) TestValidatorsMigrationToColls() {
)
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 @@ -101,7 +101,7 @@ func TestStoreMigration(t *testing.T) {
{
"UnbondingQueueKey",
v1.GetUnbondingDelegationTimeKey(now),
types.GetUnbondingDelegationTimeKey(now),
getUnbondingDelegationTimeKey(now),
},
{
"RedelegationQueueKey",
Expand Down Expand Up @@ -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)...)
}
Expand Down
12 changes: 3 additions & 9 deletions x/staking/types/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down