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: add delegations by validator index #15731

Merged
merged 41 commits into from
Apr 24, 2023
Merged
Show file tree
Hide file tree
Changes from 35 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
9cf2bda
add delegations by validator index
atheeshp Apr 4, 2023
445b722
refactor: add delegations by validator index
atheeshp Apr 5, 2023
9b3c8b4
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 5, 2023
cc1c2ce
nits
atheeshp Apr 5, 2023
71aabc2
update validator delegations query with index
atheeshp Apr 7, 2023
b99b5e8
remove unnecessory tests
atheeshp Apr 7, 2023
dc60199
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 7, 2023
d6a4a0c
fix tests
atheeshp Apr 7, 2023
76bc044
remove unnecessary test
atheeshp Apr 7, 2023
6656c62
remove test code
atheeshp Apr 7, 2023
faa45dc
refactor
atheeshp Apr 7, 2023
f96a4b3
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 11, 2023
d3f0412
review changes
atheeshp Apr 11, 2023
213ea9a
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 12, 2023
58aa3ba
review changes
atheeshp Apr 12, 2023
b03ad16
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 12, 2023
4a1ad7f
register migration
atheeshp Apr 12, 2023
64349dd
review changes
atheeshp Apr 13, 2023
7062b56
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 14, 2023
697ee7b
keys
atheeshp Apr 14, 2023
a04740a
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 17, 2023
07ea2e5
review changes
atheeshp Apr 17, 2023
d07bc41
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 18, 2023
8308684
review changes
atheeshp Apr 18, 2023
d655db3
review changes
atheeshp Apr 18, 2023
727e273
review changes
atheeshp Apr 18, 2023
d5f5fea
fix lint
atheeshp Apr 18, 2023
9ada08c
fix lint
atheeshp Apr 18, 2023
c058798
error handling
atheeshp Apr 18, 2023
cc2ee23
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 18, 2023
0a70b08
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 20, 2023
c3a2c41
review changes
atheeshp Apr 20, 2023
45a84e9
Merge branch 'ap/delegations-by-validator' of github.com:cosmos/cosmo…
atheeshp Apr 20, 2023
4743e24
Merge branch 'main' of github.com:cosmos/cosmos-sdk into ap/delegatio…
atheeshp Apr 20, 2023
555b237
add legacy support
atheeshp Apr 21, 2023
95f4fb7
Update x/staking/keeper/grpc_query.go
tac0turtle Apr 23, 2023
fdf4725
Update x/staking/migrations/v5/keys.go
tac0turtle Apr 23, 2023
68298ef
fix lint
atheeshp Apr 24, 2023
c42b943
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 24, 2023
dd5bf2c
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 24, 2023
74a8a89
Merge branch 'main' into ap/delegations-by-validator
atheeshp Apr 24, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/slashing) [#15580](https://github.com/cosmos/cosmos-sdk/pull/15580) The validator slashing window now stores "chunked" bitmap entries for each validator's signing window instead of a single boolean entry per signing window index.
* (x/feegrant) [#14294](https://github.com/cosmos/cosmos-sdk/pull/14294) Moved the logic of rejecting duplicate grant from `msg_server` to `keeper` method.
* (x/staking) [#14590](https://github.com/cosmos/cosmos-sdk/pull/14590) `MsgUndelegateResponse` now includes undelegated amount. `x/staking` module's `keeper.Undelegate` now returns 3 values (completionTime,undelegateAmount,error) instead of 2.
* (x/staking) (#15731) (https://github.com/cosmos/cosmos-sdk/pull/15731) Introducing a new index to retrieve the delegations by validator efficiently.

### API Breaking Changes

Expand Down
2 changes: 1 addition & 1 deletion tests/integration/staking/keeper/determinstic_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ func TestGRPCValidatorDelegations(t *testing.T) {
ValidatorAddr: validator.OperatorAddress,
}

testdata.DeterministicIterations(f.ctx, t, req, f.queryClient.ValidatorDelegations, 11985, false)
testdata.DeterministicIterations(f.ctx, t, req, f.queryClient.ValidatorDelegations, 14475, false)
}

func TestGRPCValidatorUnbondingDelegations(t *testing.T) {
Expand Down
125 changes: 124 additions & 1 deletion tests/integration/staking/keeper/validator_bench_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,15 @@
package keeper_test

import "testing"
import (
"fmt"
"testing"

"cosmossdk.io/simapp"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
banktestutil "github.com/cosmos/cosmos-sdk/x/bank/testutil"
"github.com/cosmos/cosmos-sdk/x/staking/types"
)

func BenchmarkGetValidator(b *testing.B) {
// 900 is the max number we are allowed to use in order to avoid simtestutil.CreateTestPubKeys
Expand All @@ -27,3 +36,117 @@ func BenchmarkGetValidator(b *testing.B) {
}
}
}

func BenchmarkGetValidatorDelegations(b *testing.B) {
alexanderbez marked this conversation as resolved.
Show resolved Hide resolved
var totalPower int64
powersNumber := 10

powers := make([]int64, powersNumber)
for i := range powers {
powers[i] = int64(i)
totalPower += int64(i)
}

app, ctx, _, valAddrs, vals := initValidators(b, totalPower, len(powers), powers)
for _, validator := range vals {
app.StakingKeeper.SetValidator(ctx, validator)
}

delegationsNum := 1000
for _, val := range valAddrs {
for i := 0; i < delegationsNum; i++ {
delegator := sdk.AccAddress(fmt.Sprintf("address%d", i))
banktestutil.FundAccount(app.BankKeeper, ctx, delegator,
sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(int64(i)))))
NewDel := types.NewDelegation(delegator, val, sdk.NewDec(int64(i)))
app.StakingKeeper.SetDelegation(ctx, NewDel)
}
}

b.ResetTimer()
for n := 0; n < b.N; n++ {
updateValidatorDelegations(ctx, app, valAddrs[0], sdk.ValAddress("val"))
}
}

func BenchmarkGetValidatorDelegationsLegacy(b *testing.B) {
var totalPower int64
powersNumber := 10

powers := make([]int64, powersNumber)
for i := range powers {
powers[i] = int64(i)
totalPower += int64(i)
}

app, ctx, _, valAddrs, vals := initValidators(b, totalPower, len(powers), powers)

for _, validator := range vals {
app.StakingKeeper.SetValidator(ctx, validator)
}

delegationsNum := 1000
for _, val := range valAddrs {
for i := 0; i < delegationsNum; i++ {
delegator := sdk.AccAddress(fmt.Sprintf("address%d", i))
banktestutil.FundAccount(app.BankKeeper, ctx, delegator,
sdk.NewCoins(sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(int64(i)))))
NewDel := types.NewDelegation(delegator, val, sdk.NewDec(int64(i)))
app.StakingKeeper.SetDelegation(ctx, NewDel)
}
}

b.ResetTimer()
for n := 0; n < b.N; n++ {
updateValidatorDelegationsLegacy(ctx, app, valAddrs[0], sdk.ValAddress("val"))
}
}

func updateValidatorDelegationsLegacy(ctx sdk.Context, app *simapp.SimApp, existingValAddr, newValAddr sdk.ValAddress) {
storeKey := app.GetKey(types.StoreKey)
cdc, k := app.AppCodec(), app.StakingKeeper

store := ctx.KVStore(storeKey)

iterator := storetypes.KVStorePrefixIterator(store, types.DelegationKey)
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
delegation := types.MustUnmarshalDelegation(cdc, iterator.Value())
if delegation.GetValidatorAddr().Equals(existingValAddr) {
k.RemoveDelegation(ctx, delegation)
delegation.ValidatorAddress = newValAddr.String()
k.SetDelegation(ctx, delegation)
}
}
}

func updateValidatorDelegations(ctx sdk.Context, app *simapp.SimApp, existingValAddr, newValAddr sdk.ValAddress) {
storeKey := app.GetKey(types.StoreKey)
cdc, k := app.AppCodec(), app.StakingKeeper

store := ctx.KVStore(storeKey)

itr := storetypes.KVStorePrefixIterator(store, types.GetDelegationsByValPrefixKey(existingValAddr))
defer itr.Close()

for ; itr.Valid(); itr.Next() {
key := itr.Key()
valAddr, delAddr, err := types.ParseDelegationsByValKey(key)
if err != nil {
panic(err)
}

bz := store.Get(types.GetDelegationKey(delAddr, valAddr))
delegation := types.MustUnmarshalDelegation(cdc, bz)

// remove old operator addr from delegation
if err := k.RemoveDelegation(ctx, delegation); err != nil {
panic(err)
}

delegation.ValidatorAddress = newValAddr.String()
// add with new operator addr
k.SetDelegation(ctx, delegation)
}
}
21 changes: 17 additions & 4 deletions x/staking/keeper/delegation.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,14 +60,22 @@ func (k Keeper) GetAllDelegations(ctx sdk.Context) (delegations []types.Delegati
func (k Keeper) GetValidatorDelegations(ctx sdk.Context, valAddr sdk.ValAddress) (delegations []types.Delegation) {
store := ctx.KVStore(k.storeKey)

iterator := storetypes.KVStorePrefixIterator(store, types.DelegationKey)
iterator := storetypes.KVStorePrefixIterator(store, types.GetDelegationsByValPrefixKey(valAddr))
defer iterator.Close()

for ; iterator.Valid(); iterator.Next() {
delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value())
if delegation.GetValidatorAddr().Equals(valAddr) {
delegations = append(delegations, delegation)
var delegation types.Delegation
valAddr, delAddr, err := types.ParseDelegationsByValKey(iterator.Key())
if err != nil {
panic(err)
}

bz := store.Get(types.GetDelegationKey(delAddr, valAddr))
if err := k.cdc.Unmarshal(bz, &delegation); err != nil {
panic(err)
}

delegations = append(delegations, delegation)
}

return delegations
Expand Down Expand Up @@ -103,6 +111,9 @@ func (k Keeper) SetDelegation(ctx sdk.Context, delegation types.Delegation) {
store := ctx.KVStore(k.storeKey)
b := types.MustMarshalDelegation(k.cdc, delegation)
store.Set(types.GetDelegationKey(delegatorAddress, delegation.GetValidatorAddr()), b)

// set the delegation in validator delegator index
store.Set(types.GetDelegationsByValKey(delegation.GetValidatorAddr(), delegatorAddress), []byte{})
}

// RemoveDelegation removes a delegation
Expand All @@ -119,6 +130,8 @@ func (k Keeper) RemoveDelegation(ctx sdk.Context, delegation types.Delegation) e

store := ctx.KVStore(k.storeKey)
store.Delete(types.GetDelegationKey(delegatorAddress, delegation.GetValidatorAddr()))
store.Delete(types.GetDelegationsByValKey(delegation.GetValidatorAddr(), delegatorAddress))

return nil
}

Expand Down
77 changes: 77 additions & 0 deletions x/staking/keeper/delegation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,83 @@ func (s *KeeperTestSuite) TestDelegation() {
require.Equal(0, len(resBonds))
}

func (s *KeeperTestSuite) TestDelegationsByValIndex() {
ctx, keeper := s.ctx, s.stakingKeeper
require := s.Require()

addrDels, valAddrs := createValAddrs(3)

for _, addr := range addrDels {
s.accountKeeper.EXPECT().StringToBytes(addr.String()).Return(addr, nil).AnyTimes()
s.accountKeeper.EXPECT().BytesToString(addr).Return(addr.String(), nil).AnyTimes()
s.bankKeeper.EXPECT().DelegateCoinsFromAccountToModule(gomock.Any(), addr, gomock.Any(), gomock.Any()).Return(nil).AnyTimes()
}

// construct the validators
amts := []math.Int{sdk.NewInt(9), sdk.NewInt(8), sdk.NewInt(7)}
var validators [3]stakingtypes.Validator
for i, amt := range amts {
validators[i] = testutil.NewValidator(s.T(), valAddrs[i], PKs[i])
validators[i], _ = validators[i].AddTokensFromDel(amt)

validators[i] = stakingkeeper.TestingUpdateValidator(keeper, ctx, validators[i], true)
}

// delegate 2 tokens
//
// total delegations after delegating: del1 -> 2stake
_, err := s.msgServer.Delegate(ctx, stakingtypes.NewMsgDelegate(addrDels[0], valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))))
require.NoError(err)

dels := s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.Len(dels, 1)

// delegate 4 tokens
//
// total delegations after delegating: del1 -> 2stake, del2 -> 4stake
_, err = s.msgServer.Delegate(ctx, stakingtypes.NewMsgDelegate(addrDels[1], valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(4))))
require.NoError(err)

dels = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.Len(dels, 2)

// undelegate 1 token from del1
//
// total delegations after undelegating: del1 -> 1stake, del2 -> 4stake
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[0], valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))))
require.NoError(err)

dels = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.Len(dels, 2)

// undelegate 1 token from del1
//
// total delegations after undelegating: del2 -> 4stake
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[0], valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(1))))
require.NoError(err)

dels = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.Len(dels, 1)

// undelegate 2 tokens from del2
//
// total delegations after undelegating: del2 -> 2stake
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[1], valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))))
require.NoError(err)

dels = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.Len(dels, 1)

// undelegate 2 tokens from del2
//
// total delegations after undelegating: []
_, err = s.msgServer.Undelegate(ctx, stakingtypes.NewMsgUndelegate(addrDels[1], valAddrs[0], sdk.NewCoin(sdk.DefaultBondDenom, sdk.NewInt(2))))
require.NoError(err)

dels = s.stakingKeeper.GetValidatorDelegations(ctx, valAddrs[0])
require.Len(dels, 0)
}

// tests Get/Set/Remove UnbondingDelegation
func (s *KeeperTestSuite) TestUnbondingDelegation() {
ctx, keeper := s.ctx, s.stakingKeeper
Expand Down
63 changes: 47 additions & 16 deletions x/staking/keeper/grpc_query.go
Original file line number Diff line number Diff line change
Expand Up @@ -92,31 +92,42 @@ func (k Querier) ValidatorDelegations(c context.Context, req *types.QueryValidat
if req.ValidatorAddr == "" {
return nil, status.Error(codes.InvalidArgument, "validator address cannot be empty")
}

tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddr)
if err != nil {
return nil, err
}
ctx := sdk.UnwrapSDKContext(c)

store := ctx.KVStore(k.storeKey)
valStore := prefix.NewStore(store, types.DelegationKey)
delegations, pageRes, err := query.GenericFilteredPaginate(k.cdc, valStore, req.Pagination, func(key []byte, delegation *types.Delegation) (*types.Delegation, error) {
valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddr)
if err != nil {
return nil, err
}
delStore := prefix.NewStore(store, types.GetDelegationsByValPrefixKey(valAddr))

if !delegation.GetValidatorAddr().Equals(valAddr) {
return nil, nil
var dels types.Delegations
var pageRes *query.PageResponse
tac0turtle marked this conversation as resolved.
Show resolved Hide resolved
pageRes, err = query.Paginate(delStore, req.Pagination, func(delAddr, value []byte) error {
bz := store.Get(types.GetDelegationKey(delAddr, valAddr))

var delegation types.Delegation
err = k.cdc.Unmarshal(bz, &delegation)
if err != nil {
return err
}

return delegation, nil
}, func() *types.Delegation {
return &types.Delegation{}
dels = append(dels, delegation)
return nil
})
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}
delegations, pageResponse, err := k.getValidatorDelegationsLegacy(ctx, req)
if err != nil {
return nil, status.Error(codes.Internal, err.Error())
}

dels = types.Delegations{}
for _, d := range delegations {
dels = append(dels, *d)
}

dels := types.Delegations{}
for _, d := range delegations {
dels = append(dels, *d)
pageRes = pageResponse
}

delResponses, err := DelegationsToDelegationResponses(ctx, k.Keeper, dels)
Expand All @@ -129,6 +140,26 @@ func (k Querier) ValidatorDelegations(c context.Context, req *types.QueryValidat
}, nil
}

func (k Querier) getValidatorDelegationsLegacy(ctx sdk.Context, req *types.QueryValidatorDelegationsRequest) ([]*types.Delegation, *query.PageResponse, error) {
store := ctx.KVStore(k.storeKey)

valStore := prefix.NewStore(store, types.DelegationKey)
return query.GenericFilteredPaginate(k.cdc, valStore, req.Pagination, func(key []byte, delegation *types.Delegation) (*types.Delegation, error) {
valAddr, err := sdk.ValAddressFromBech32(req.ValidatorAddr)
if err != nil {
return nil, err
}

if !delegation.GetValidatorAddr().Equals(valAddr) {
return nil, nil
}

return delegation, nil
}, func() *types.Delegation {
return &types.Delegation{}
})
}

// ValidatorUnbondingDelegations queries unbonding delegations of a validator
func (k Querier) ValidatorUnbondingDelegations(c context.Context, req *types.QueryValidatorUnbondingDelegationsRequest) (*types.QueryValidatorUnbondingDelegationsResponse, error) {
if req == nil {
Expand Down
2 changes: 1 addition & 1 deletion x/staking/keeper/migrations.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,5 @@ func (m Migrator) Migrate3to4(ctx sdk.Context) error {

// Migrate4to5 migrates x/staking state from consensus version 4 to 5.
func (m Migrator) Migrate4to5(ctx sdk.Context) error {
return v5.MigrateStore(ctx, m.keeper.storeKey)
return v5.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc)
}
Loading