diff --git a/CHANGELOG.md b/CHANGELOG.md index 37376d2292..f86c308924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -64,6 +64,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking Changes +* (x/staking) [#17260](https://github.com/cosmos/cosmos-sdk/pull/17260) Use collections for `DelegationKey`: + * remove from `types`: `GetDelegationKey`, `GetDelegationsKey` * (x/staking) [#17288](https://github.com/cosmos/cosmos-sdk/pull/17288) Use collections for `UnbondingIndex`: * remove from `types`: `GetUnbondingIndexKey`. * (x/staking) [#17256](https://github.com/cosmos/cosmos-sdk/pull/17256) Use collections for `UnbondingID`. @@ -76,7 +78,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * remove from `Keeper`: `GetPreviousProposerConsAddr`, `SetPreviousProposerConsAddr`, `GetValidatorHistoricalReferenceCount`, `GetValidatorSlashEvent`, `SetValidatorSlashEvent`. * (x/feegrant) [#16535](https://github.com/cosmos/cosmos-sdk/pull/16535) Use collections for `FeeAllowance`, `FeeAllowanceQueue`. * (x/staking) [#17063](https://github.com/cosmos/cosmos-sdk/pull/17063) Use collections for `HistoricalInfo`: - * remove `Keeper`: `GetHistoricalInfo`, `SetHistoricalInfo`, + * remove `Keeper`: `GetHistoricalInfo`, `SetHistoricalInfo` * (x/staking) [#17062](https://github.com/cosmos/cosmos-sdk/pull/17062) Use collections for `ValidatorUpdates`: * remove `Keeper`: `SetValidatorUpdates`, `GetValidatorUpdates` * (x/slashing) [#17023](https://github.com/cosmos/cosmos-sdk/pull/17023) Use collections for `ValidatorSigningInfo`: diff --git a/go.mod b/go.mod index ad6fb882f4..cbe59cce71 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ module github.com/cosmos/cosmos-sdk require ( cosmossdk.io/api v0.7.0 - cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 + cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 cosmossdk.io/core v0.9.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0 diff --git a/go.sum b/go.sum index f5c90b9bfe..cb90520ea0 100644 --- a/go.sum +++ b/go.sum @@ -37,8 +37,8 @@ cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9 cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3fOKtUw0Xmo= cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4= cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= -cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 h1:4XhcAIVBXPwCFTT9abOzZZaEadbRaVws8A6UTr2KGIE= -cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7/go.mod h1:+KJND4gZHilxE3meopEl/Uet6IAw3PyiSbgeOrFzAZE= +cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 h1:aFHpJtJgdqBH8kRvD86Rl92rvd1+JFpaUpj+5NZNodg= +cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68/go.mod h1:OK08xZu8fxXLoQcFIfkBDayo2aRokLfC3vVcXX0MB8E= cosmossdk.io/core v0.9.0 h1:30ScAOHDIUOCg1DKAwqkho9wuQJnu7GUrMcg0XLioic= cosmossdk.io/core v0.9.0/go.mod h1:NFgl5r41Q36+RixTvyrfsS6qQ65agCbZ1FTpnN7/G1Y= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= diff --git a/simapp/go.mod b/simapp/go.mod index f5206d72c9..9b8d8bd77b 100644 --- a/simapp/go.mod +++ b/simapp/go.mod @@ -5,7 +5,7 @@ go 1.20 require ( cosmossdk.io/api v0.7.0 cosmossdk.io/client/v2 v2.0.0-20230630094428-02b760776860 - cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 + cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 cosmossdk.io/core v0.9.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/log v1.2.0 diff --git a/simapp/go.sum b/simapp/go.sum index d58a9e714c..ac1c66261f 100644 --- a/simapp/go.sum +++ b/simapp/go.sum @@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4= cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= -cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 h1:4XhcAIVBXPwCFTT9abOzZZaEadbRaVws8A6UTr2KGIE= -cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7/go.mod h1:+KJND4gZHilxE3meopEl/Uet6IAw3PyiSbgeOrFzAZE= +cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 h1:aFHpJtJgdqBH8kRvD86Rl92rvd1+JFpaUpj+5NZNodg= +cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68/go.mod h1:OK08xZu8fxXLoQcFIfkBDayo2aRokLfC3vVcXX0MB8E= cosmossdk.io/core v0.9.0 h1:30ScAOHDIUOCg1DKAwqkho9wuQJnu7GUrMcg0XLioic= cosmossdk.io/core v0.9.0/go.mod h1:NFgl5r41Q36+RixTvyrfsS6qQ65agCbZ1FTpnN7/G1Y= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= diff --git a/tests/go.mod b/tests/go.mod index f0cf6ab3a6..f2204c1998 100644 --- a/tests/go.mod +++ b/tests/go.mod @@ -4,7 +4,7 @@ go 1.20 require ( cosmossdk.io/api v0.7.0 - cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 + cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 cosmossdk.io/core v0.9.0 cosmossdk.io/depinject v1.0.0-alpha.3 cosmossdk.io/errors v1.0.0 diff --git a/tests/go.sum b/tests/go.sum index 34c295bfc7..54b50c186f 100644 --- a/tests/go.sum +++ b/tests/go.sum @@ -189,8 +189,8 @@ cloud.google.com/go/workflows v1.6.0/go.mod h1:6t9F5h/unJz41YqfBmqSASJSXccBLtD1V cloud.google.com/go/workflows v1.7.0/go.mod h1:JhSrZuVZWuiDfKEFxU0/F1PQjmpnpcoISEXH2bcHC3M= cosmossdk.io/api v0.7.0 h1:QsEMIWuv9xWDbF2HZnW4Lpu1/SejCztPu0LQx7t6MN4= cosmossdk.io/api v0.7.0/go.mod h1:kJFAEMLN57y0viszHDPLMmieF0471o5QAwwApa+270M= -cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7 h1:4XhcAIVBXPwCFTT9abOzZZaEadbRaVws8A6UTr2KGIE= -cosmossdk.io/collections v0.3.1-0.20230727092431-f0f777fa3cb7/go.mod h1:+KJND4gZHilxE3meopEl/Uet6IAw3PyiSbgeOrFzAZE= +cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68 h1:aFHpJtJgdqBH8kRvD86Rl92rvd1+JFpaUpj+5NZNodg= +cosmossdk.io/collections v0.3.1-0.20230808102719-f04fefdc7a68/go.mod h1:OK08xZu8fxXLoQcFIfkBDayo2aRokLfC3vVcXX0MB8E= cosmossdk.io/core v0.9.0 h1:30ScAOHDIUOCg1DKAwqkho9wuQJnu7GUrMcg0XLioic= cosmossdk.io/core v0.9.0/go.mod h1:NFgl5r41Q36+RixTvyrfsS6qQ65agCbZ1FTpnN7/G1Y= cosmossdk.io/depinject v1.0.0-alpha.3 h1:6evFIgj//Y3w09bqOUOzEpFj5tsxBqdc5CfkO7z+zfw= diff --git a/tests/integration/distribution/keeper/msg_server_test.go b/tests/integration/distribution/keeper/msg_server_test.go index 0a32dc847a..46a1e7008b 100644 --- a/tests/integration/distribution/keeper/msg_server_test.go +++ b/tests/integration/distribution/keeper/msg_server_test.go @@ -253,7 +253,7 @@ func TestMsgWithdrawDelegatorReward(t *testing.T) { ValidatorAddress: f.valAddr.String(), }, expErr: true, - expErrMsg: "no delegation for (address, validator) tuple", + expErrMsg: "not found", }, { name: "validator with no delegations", diff --git a/tests/integration/evidence/keeper/infraction_test.go b/tests/integration/evidence/keeper/infraction_test.go index f716cf4f01..e250bfb382 100644 --- a/tests/integration/evidence/keeper/infraction_test.go +++ b/tests/integration/evidence/keeper/infraction_test.go @@ -11,6 +11,7 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "gotest.tools/v3/assert" + "cosmossdk.io/collections" "cosmossdk.io/core/appmodule" "cosmossdk.io/core/comet" "cosmossdk.io/log" @@ -243,7 +244,7 @@ func TestHandleDoubleSign(t *testing.T) { // require we be able to unbond now ctx = ctx.WithBlockHeight(ctx.BlockHeight() + 1) - del, _ := f.stakingKeeper.GetDelegation(ctx, sdk.AccAddress(operatorAddr), operatorAddr) + del, _ := f.stakingKeeper.Delegations.Get(ctx, collections.Join(sdk.AccAddress(operatorAddr), operatorAddr)) validator, _ := f.stakingKeeper.GetValidator(ctx, operatorAddr) totalBond := validator.TokensFromShares(del.GetShares()).TruncateInt() tstaking.Ctx = ctx diff --git a/tests/integration/staking/keeper/grpc_query_test.go b/tests/integration/staking/keeper/grpc_query_test.go index c5500f232b..fbb4f4e87f 100644 --- a/tests/integration/staking/keeper/grpc_query_test.go +++ b/tests/integration/staking/keeper/grpc_query_test.go @@ -8,6 +8,7 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "gotest.tools/v3/assert" + "cosmossdk.io/collections" "cosmossdk.io/math" simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" @@ -223,7 +224,7 @@ func TestGRPCQueryDelegatorValidator(t *testing.T) { } }, false, - "no delegation for (address, validator) tuple", + "not found", }, { "empty delegator address", @@ -289,7 +290,7 @@ func TestGRPCQueryDelegation(t *testing.T) { addrVal := vals[0].OperatorAddress valAddr, err := sdk.ValAddressFromBech32(addrVal) assert.NilError(t, err) - delegation, found := f.stakingKeeper.GetDelegation(ctx, addrAcc, valAddr) + delegation, found := f.stakingKeeper.Delegations.Get(ctx, collections.Join(addrAcc, valAddr)) assert.Assert(t, found) var req *types.QueryDelegationRequest @@ -358,7 +359,7 @@ func TestGRPCQueryDelegatorDelegations(t *testing.T) { addrVal1 := vals[0].OperatorAddress valAddr, err := sdk.ValAddressFromBech32(addrVal1) assert.NilError(t, err) - delegation, found := f.stakingKeeper.GetDelegation(ctx, addrAcc, valAddr) + delegation, found := f.stakingKeeper.Delegations.Get(ctx, collections.Join(addrAcc, valAddr)) assert.Assert(t, found) var req *types.QueryDelegatorDelegationsRequest @@ -438,7 +439,7 @@ func TestGRPCQueryValidatorDelegations(t *testing.T) { addrVal2 := valAddrs[4] valAddr, err := sdk.ValAddressFromBech32(addrVal1) assert.NilError(t, err) - delegation, found := f.stakingKeeper.GetDelegation(ctx, addrAcc, valAddr) + delegation, found := f.stakingKeeper.Delegations.Get(ctx, collections.Join(addrAcc, valAddr)) assert.Assert(t, found) var req *types.QueryValidatorDelegationsRequest diff --git a/tests/integration/staking/keeper/slash_test.go b/tests/integration/staking/keeper/slash_test.go index 7595e7034e..245eec0cf4 100644 --- a/tests/integration/staking/keeper/slash_test.go +++ b/tests/integration/staking/keeper/slash_test.go @@ -8,6 +8,7 @@ import ( "github.com/stretchr/testify/require" "gotest.tools/v3/assert" + "cosmossdk.io/collections" "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec/address" @@ -167,7 +168,7 @@ func TestSlashRedelegation(t *testing.T) { assert.DeepEqual(t, math.NewInt(10), rd.Entries[0].InitialBalance) // shares decreased - del, found = f.stakingKeeper.GetDelegation(f.sdkCtx, addrDels[0], addrVals[1]) + del, found = f.stakingKeeper.Delegations.Get(f.sdkCtx, collections.Join(addrDels[0], addrVals[1])) assert.Assert(t, found) assert.Equal(t, int64(5), del.Shares.RoundInt64()) diff --git a/tests/integration/staking/keeper/validator_bench_test.go b/tests/integration/staking/keeper/validator_bench_test.go index 70f38055f2..7984e4b0db 100644 --- a/tests/integration/staking/keeper/validator_bench_test.go +++ b/tests/integration/staking/keeper/validator_bench_test.go @@ -152,17 +152,16 @@ func updateValidatorDelegationsLegacy(f *fixture, existingValAddr, newValAddr sd } func updateValidatorDelegations(f *fixture, existingValAddr, newValAddr sdk.ValAddress) { - storeKey := f.keys[types.StoreKey] - cdc, k := f.cdc, f.stakingKeeper - - store := f.sdkCtx.KVStore(storeKey) + k := f.stakingKeeper rng := collections.NewPrefixedPairRange[sdk.ValAddress, sdk.AccAddress](existingValAddr) err := k.DelegationsByValidator.Walk(f.sdkCtx, rng, func(key collections.Pair[sdk.ValAddress, sdk.AccAddress], _ []byte) (stop bool, err error) { valAddr, delAddr := key.K1(), key.K2() - bz := store.Get(types.GetDelegationKey(delAddr, valAddr)) - delegation := types.MustUnmarshalDelegation(cdc, bz) + delegation, err := k.Delegations.Get(f.sdkCtx, collections.Join(delAddr, valAddr)) + if err != nil { + return true, err + } // remove old operator addr from delegation if err := k.RemoveDelegation(f.sdkCtx, delegation); err != nil { diff --git a/x/gov/abci_test.go b/x/gov/abci_test.go index 411e6cd7f8..c43d07a8a9 100644 --- a/x/gov/abci_test.go +++ b/x/gov/abci_test.go @@ -35,7 +35,7 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.NoError(t, err) govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newProposalMsg, err := v1.NewMsgSubmitProposal( []sdk.Msg{mkTestLegacyContent(t)}, @@ -52,25 +52,25 @@ func TestTickExpiredDepositPeriod(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newHeader := ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) params, _ := suite.GovKeeper.Params.Get(ctx) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) err = gov.EndBlocker(ctx, suite.GovKeeper) require.NoError(t, err) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) } func TestTickMultipleExpiredDepositPeriod(t *testing.T) { @@ -86,7 +86,7 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.NoError(t, err) govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newProposalMsg, err := v1.NewMsgSubmitProposal( []sdk.Msg{mkTestLegacyContent(t)}, @@ -103,13 +103,13 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { require.NoError(t, err) require.NotNil(t, res) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newHeader := ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(2) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newProposalMsg2, err := v1.NewMsgSubmitProposal( []sdk.Msg{mkTestLegacyContent(t)}, @@ -131,17 +131,17 @@ func TestTickMultipleExpiredDepositPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(time.Duration(-1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) require.NoError(t, gov.EndBlocker(ctx, suite.GovKeeper)) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newHeader = ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(5) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) require.NoError(t, gov.EndBlocker(ctx, suite.GovKeeper)) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) } func TestTickPassedDepositPeriod(t *testing.T) { @@ -174,13 +174,13 @@ func TestTickPassedDepositPeriod(t *testing.T) { proposalID := res.ProposalId - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newHeader := ctx.BlockHeader() newHeader.Time = ctx.BlockHeader().Time.Add(time.Duration(1) * time.Second) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) newDepositMsg := v1.NewMsgDeposit(addrs[1], proposalID, sdk.Coins{sdk.NewInt64Coin(sdk.DefaultBondDenom, 5)}) @@ -188,7 +188,7 @@ func TestTickPassedDepositPeriod(t *testing.T) { require.NoError(t, err) require.NotNil(t, res1) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) } func TestTickPassedVotingPeriod(t *testing.T) { @@ -222,8 +222,8 @@ func TestTickPassedVotingPeriod(t *testing.T) { require.NoError(t, err) govMsgSvr := keeper.NewMsgServerImpl(suite.GovKeeper) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposalCoins := sdk.Coins{sdk.NewCoin(sdk.DefaultBondDenom, suite.StakingKeeper.TokensFromConsensusPower(ctx, 5*depositMultiplier))} newProposalMsg, err := v1.NewMsgSubmitProposal([]sdk.Msg{mkTestLegacyContent(t)}, proposalCoins, addrs[0].String(), "", "Proposal", "description of proposal", tc.expedited) @@ -255,8 +255,8 @@ func TestTickPassedVotingPeriod(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*votingPeriod) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposal, err := suite.GovKeeper.Proposals.Get(ctx, res.ProposalId) require.NoError(t, err) @@ -266,12 +266,12 @@ func TestTickPassedVotingPeriod(t *testing.T) { require.NoError(t, err) if !tc.expedited { - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) return } // If expedited, it should be converted to a regular proposal instead. - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId) require.Nil(t, err) @@ -467,8 +467,8 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { createValidators(t, stakingMsgSvr, ctx, []sdk.ValAddress{valAddr}, []int64{10}) _, err = suite.StakingKeeper.EndBlocker(ctx) require.NoError(t, err) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) macc := suite.GovKeeper.GetGovernanceAccount(ctx) require.NotNil(t, macc) @@ -501,8 +501,8 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*params.ExpeditedVotingPeriod) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposal, err := suite.GovKeeper.Proposals.Get(ctx, res.ProposalId) require.Nil(t, err) @@ -518,7 +518,7 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { err = gov.EndBlocker(ctx, suite.GovKeeper) require.NoError(t, err) if tc.expeditedPasses { - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId) require.Nil(t, err) @@ -539,7 +539,7 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { } // Expedited proposal should be converted to a regular proposal instead. - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId) require.Nil(t, err) require.Equal(t, v1.StatusVotingPeriod, proposal.Status) @@ -560,8 +560,8 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { newHeader.Time = ctx.BlockHeader().Time.Add(*params.MaxDepositPeriod).Add(*params.VotingPeriod) ctx = ctx.WithBlockHeader(newHeader) - checkInactiveProposalsQueue(t, ctx, suite.GovKeeper, true) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, false) + checkInactiveProposalsQueue(t, ctx, suite.GovKeeper) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) if tc.regularEventuallyPassing { // Validator votes YES, letting the converted regular proposal pass. @@ -579,7 +579,7 @@ func TestExpeditedProposal_PassAndConversionToRegular(t *testing.T) { submitterEventualBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[0]) depositorEventualBalance := suite.BankKeeper.GetAllBalances(ctx, addrs[1]) - checkActiveProposalsQueue(t, ctx, suite.GovKeeper, true) + checkActiveProposalsQueue(t, ctx, suite.GovKeeper) proposal, err = suite.GovKeeper.Proposals.Get(ctx, res.ProposalId) require.Nil(t, err) @@ -632,26 +632,20 @@ func getDepositMultiplier(expedited bool) int64 { return 1 } -func checkActiveProposalsQueue(t *testing.T, ctx sdk.Context, k *keeper.Keeper, invalid bool) { +func checkActiveProposalsQueue(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { t.Helper() err := k.ActiveProposalsQueue.Walk(ctx, collections.NewPrefixUntilPairRange[time.Time, uint64](ctx.BlockTime()), func(key collections.Pair[time.Time, uint64], value uint64) (stop bool, err error) { return false, err }) - if invalid { - require.ErrorIs(t, err, collections.ErrInvalidIterator) - } else { - require.NoError(t, err) - } + + require.NoError(t, err) } -func checkInactiveProposalsQueue(t *testing.T, ctx sdk.Context, k *keeper.Keeper, invalid bool) { +func checkInactiveProposalsQueue(t *testing.T, ctx sdk.Context, k *keeper.Keeper) { t.Helper() err := k.InactiveProposalsQueue.Walk(ctx, collections.NewPrefixUntilPairRange[time.Time, uint64](ctx.BlockTime()), func(key collections.Pair[time.Time, uint64], value uint64) (stop bool, err error) { return false, err }) - if invalid { - require.ErrorIs(t, err, collections.ErrInvalidIterator) - } else { - require.NoError(t, err) - } + + require.NoError(t, err) } diff --git a/x/gov/keeper/tally_test.go b/x/gov/keeper/tally_test.go index bae984b75f..daff9f043d 100644 --- a/x/gov/keeper/tally_test.go +++ b/x/gov/keeper/tally_test.go @@ -418,7 +418,7 @@ func TestTally(t *testing.T) { // Assert votes removal after tally rng := collections.NewPrefixedPairRange[uint64, sdk.AccAddress](proposal.Id) _, err = suite.keeper.Votes.Iterate(suite.ctx, rng) - assert.ErrorIs(t, err, collections.ErrInvalidIterator, "votes must be removed after tally") + assert.Nil(t, err, collections.ErrInvalidIterator, "votes must be removed after tally") }) } } diff --git a/x/staking/app_test.go b/x/staking/app_test.go index ae68287c40..b0ef33359b 100644 --- a/x/staking/app_test.go +++ b/x/staking/app_test.go @@ -7,6 +7,7 @@ import ( cmtproto "github.com/cometbft/cometbft/proto/tendermint/types" "github.com/stretchr/testify/require" + "cosmossdk.io/collections" "cosmossdk.io/depinject" "cosmossdk.io/log" "cosmossdk.io/math" @@ -115,7 +116,7 @@ func TestStakingMsgs(t *testing.T) { ctxCheck = app.BaseApp.NewContext(true) require.True(t, sdk.Coins{genCoin.Sub(bondCoin)}.Equal(bankKeeper.GetAllBalances(ctxCheck, addr2))) - _, err = stakingKeeper.GetDelegation(ctxCheck, addr2, sdk.ValAddress(addr1)) + _, err = stakingKeeper.Delegations.Get(ctxCheck, collections.Join(addr2, sdk.ValAddress(addr1))) require.NoError(t, err) // begin unbonding @@ -126,8 +127,8 @@ func TestStakingMsgs(t *testing.T) { // delegation should exist anymore ctxCheck = app.BaseApp.NewContext(true) - _, err = stakingKeeper.GetDelegation(ctxCheck, addr2, sdk.ValAddress(addr1)) - require.ErrorIs(t, err, types.ErrNoDelegation) + _, err = stakingKeeper.Delegations.Get(ctxCheck, collections.Join(addr2, sdk.ValAddress(addr1))) + require.ErrorIs(t, err, collections.ErrNotFound) // balance should be the same because bonding not yet complete require.True(t, sdk.Coins{genCoin.Sub(bondCoin)}.Equal(bankKeeper.GetAllBalances(ctxCheck, addr2))) diff --git a/x/staking/keeper/alias_functions.go b/x/staking/keeper/alias_functions.go index 4379043cc6..d9790e7841 100644 --- a/x/staking/keeper/alias_functions.go +++ b/x/staking/keeper/alias_functions.go @@ -3,6 +3,7 @@ package keeper import ( "context" + "cosmossdk.io/collections" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -115,7 +116,7 @@ func (k Keeper) GetValidatorSet() types.ValidatorSet { // Delegation gets the delegation interface for a particular set of delegator and validator addresses func (k Keeper) Delegation(ctx context.Context, addrDel sdk.AccAddress, addrVal sdk.ValAddress) (types.DelegationI, error) { - bond, err := k.GetDelegation(ctx, addrDel, addrVal) + bond, err := k.Delegations.Get(ctx, collections.Join(addrDel, addrVal)) if err != nil { return nil, err } @@ -127,25 +128,19 @@ func (k Keeper) Delegation(ctx context.Context, addrDel sdk.AccAddress, addrVal func (k Keeper) IterateDelegations(ctx context.Context, delAddr sdk.AccAddress, fn func(index int64, del types.DelegationI) (stop bool), ) error { - store := k.storeService.OpenKVStore(ctx) - delegatorPrefixKey := types.GetDelegationsKey(delAddr) - iterator, err := store.Iterator(delegatorPrefixKey, storetypes.PrefixEndBytes(delegatorPrefixKey)) - if err != nil { - return err - } - defer iterator.Close() - - for i := int64(0); iterator.Valid(); iterator.Next() { - del, err := types.UnmarshalDelegation(k.cdc, iterator.Value()) - if err != nil { - return err - } - - stop := fn(i, del) + var i int64 + rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delAddr) + err := k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { + stop = fn(i, del) if stop { - break + return true, nil } i++ + + return false, nil + }) + if err != nil { + return err } return nil diff --git a/x/staking/keeper/delegation.go b/x/staking/keeper/delegation.go index f7761c9f91..111439d078 100644 --- a/x/staking/keeper/delegation.go +++ b/x/staking/keeper/delegation.go @@ -18,76 +18,39 @@ import ( "github.com/cosmos/cosmos-sdk/x/staking/types" ) -// GetDelegation returns a specific delegation. -func (k Keeper) GetDelegation(ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress) (types.Delegation, error) { - store := k.storeService.OpenKVStore(ctx) - key := types.GetDelegationKey(delAddr, valAddr) - - value, err := store.Get(key) - if err != nil { - return types.Delegation{}, err - } - - if value == nil { - return types.Delegation{}, types.ErrNoDelegation - } - - return types.UnmarshalDelegation(k.cdc, value) -} - -// IterateAllDelegations iterates through all of the delegations. -func (k Keeper) IterateAllDelegations(ctx context.Context, cb func(delegation types.Delegation) (stop bool)) error { - store := k.storeService.OpenKVStore(ctx) - iterator, err := store.Iterator(types.DelegationKey, storetypes.PrefixEndBytes(types.DelegationKey)) - if err != nil { - return err - } - defer iterator.Close() - - for ; iterator.Valid(); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) - if cb(delegation) { - break - } - } - - return nil -} - // GetAllDelegations returns all delegations used during genesis dump. -func (k Keeper) GetAllDelegations(ctx context.Context) (delegations []types.Delegation, err error) { - err = k.IterateAllDelegations(ctx, func(delegation types.Delegation) bool { - delegations = append(delegations, delegation) - return false - }) +func (k Keeper) GetAllDelegations(ctx context.Context) ([]types.Delegation, error) { + var delegations types.Delegations + err := k.Delegations.Walk(ctx, nil, + func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], delegation types.Delegation) (stop bool, err error) { + delegations = append(delegations, delegation) + return false, nil + }, + ) + if err != nil { + return nil, err + } - return delegations, err + return delegations, nil } // GetValidatorDelegations returns all delegations to a specific validator. // Useful for querier. func (k Keeper) GetValidatorDelegations(ctx context.Context, valAddr sdk.ValAddress) ([]types.Delegation, error) { - store := k.storeService.OpenKVStore(ctx) - var delegations []types.Delegation rng := collections.NewPrefixedPairRange[sdk.ValAddress, sdk.AccAddress](valAddr) err := k.DelegationsByValidator.Walk(ctx, rng, func(key collections.Pair[sdk.ValAddress, sdk.AccAddress], _ []byte) (stop bool, err error) { - var delegation types.Delegation valAddr, delAddr := key.K1(), key.K2() - bz, err := store.Get(types.GetDelegationKey(delAddr, valAddr)) + delegation, err := k.Delegations.Get(ctx, collections.Join(delAddr, valAddr)) if err != nil { return true, err } - if err := k.cdc.Unmarshal(bz, &delegation); err != nil { - return true, err - } - delegations = append(delegations, delegation) return false, nil }) - if err != nil && !errors.Is(err, collections.ErrInvalidIterator) { + if err != nil { return nil, err } @@ -96,25 +59,22 @@ func (k Keeper) GetValidatorDelegations(ctx context.Context, valAddr sdk.ValAddr // GetDelegatorDelegations returns a given amount of all the delegations from a // delegator. -func (k Keeper) GetDelegatorDelegations(ctx context.Context, delegator sdk.AccAddress, maxRetrieve uint16) (delegations []types.Delegation, err error) { - delegations = make([]types.Delegation, maxRetrieve) - store := k.storeService.OpenKVStore(ctx) - delegatorPrefixKey := types.GetDelegationsKey(delegator) +func (k Keeper) GetDelegatorDelegations(ctx context.Context, delegator sdk.AccAddress, maxRetrieve uint16) ([]types.Delegation, error) { + delegations := make([]types.Delegation, maxRetrieve) - iterator, err := store.Iterator(delegatorPrefixKey, storetypes.PrefixEndBytes(delegatorPrefixKey)) - if err != nil { - return delegations, err - } - defer iterator.Close() - - i := 0 - for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - delegation, err := types.UnmarshalDelegation(k.cdc, iterator.Value()) - if err != nil { - return delegations, err + var i uint16 + rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delegator) + err := k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { + if i >= maxRetrieve { + return true, nil } - delegations[i] = delegation + delegations[i] = del i++ + + return false, nil + }) + if err != nil { + return nil, err } return delegations[:i], nil // trim if the array length < maxRetrieve @@ -132,9 +92,7 @@ func (k Keeper) SetDelegation(ctx context.Context, delegation types.Delegation) return err } - store := k.storeService.OpenKVStore(ctx) - b := types.MustMarshalDelegation(k.cdc, delegation) - err = store.Set(types.GetDelegationKey(delegatorAddress, valAddr), b) + err = k.Delegations.Set(ctx, collections.Join(sdk.AccAddress(delegatorAddress), sdk.ValAddress(valAddr)), delegation) if err != nil { return err } @@ -160,8 +118,7 @@ func (k Keeper) RemoveDelegation(ctx context.Context, delegation types.Delegatio return err } - store := k.storeService.OpenKVStore(ctx) - err = store.Delete(types.GetDelegationKey(delegatorAddress, valAddr)) + err = k.Delegations.Remove(ctx, collections.Join(sdk.AccAddress(delegatorAddress), sdk.ValAddress(valAddr))) if err != nil { return err } @@ -319,23 +276,18 @@ func (k Keeper) GetDelegatorBonded(ctx context.Context, delegator sdk.AccAddress // IterateDelegatorDelegations iterates through one delegator's delegations. func (k Keeper) IterateDelegatorDelegations(ctx context.Context, delegator sdk.AccAddress, cb func(delegation types.Delegation) (stop bool)) error { - store := k.storeService.OpenKVStore(ctx) - prefix := types.GetDelegationsKey(delegator) - iterator, err := store.Iterator(prefix, storetypes.PrefixEndBytes(prefix)) + rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delegator) + err := k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { + if cb(del) { + return true, nil + } + + return false, nil + }) if err != nil { return err } - defer iterator.Close() - for ; iterator.Valid(); iterator.Next() { - delegation, err := types.UnmarshalDelegation(k.cdc, iterator.Value()) - if err != nil { - return err - } - if cb(delegation) { - break - } - } return nil } @@ -870,11 +822,11 @@ func (k Keeper) Delegate( } // Get or create the delegation object and call the appropriate hook if present - delegation, err := k.GetDelegation(ctx, delAddr, validator.GetOperator()) + delegation, err := k.Delegations.Get(ctx, collections.Join(delAddr, validator.GetOperator())) if err == nil { // found err = k.Hooks().BeforeDelegationSharesModified(ctx, delAddr, validator.GetOperator()) - } else if errors.Is(err, types.ErrNoDelegation) { + } else if errors.Is(err, collections.ErrNotFound) { // not found delAddrStr, err1 := k.authKeeper.AddressCodec().BytesToString(delAddr) if err1 != nil { @@ -972,8 +924,8 @@ func (k Keeper) Unbond( ctx context.Context, delAddr sdk.AccAddress, valAddr sdk.ValAddress, shares math.LegacyDec, ) (amount math.Int, err error) { // check if a delegation object exists in the store - delegation, err := k.GetDelegation(ctx, delAddr, valAddr) - if errors.Is(err, types.ErrNoDelegation) { + delegation, err := k.Delegations.Get(ctx, collections.Join(delAddr, valAddr)) + if errors.Is(err, collections.ErrNotFound) { return amount, types.ErrNoDelegatorForAddress } else if err != nil { return amount, err @@ -1348,7 +1300,7 @@ func (k Keeper) ValidateUnbondAmount( return shares, err } - del, err := k.GetDelegation(ctx, delAddr, valAddr) + del, err := k.Delegations.Get(ctx, collections.Join(delAddr, valAddr)) if err != nil { return shares, err } diff --git a/x/staking/keeper/delegation_test.go b/x/staking/keeper/delegation_test.go index 26fe6fbebb..8910e0b504 100644 --- a/x/staking/keeper/delegation_test.go +++ b/x/staking/keeper/delegation_test.go @@ -5,6 +5,7 @@ import ( "github.com/golang/mock/gomock" + "cosmossdk.io/collections" "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec/address" @@ -45,19 +46,19 @@ func (s *KeeperTestSuite) TestDelegation() { bond1to1 := stakingtypes.NewDelegation(addrDels[0].String(), valAddrs[0].String(), math.LegacyNewDec(9)) // check the empty keeper first - _, err := keeper.GetDelegation(ctx, addrDels[0], valAddrs[0]) - require.ErrorIs(err, stakingtypes.ErrNoDelegation) + _, err := keeper.Delegations.Get(ctx, collections.Join(addrDels[0], valAddrs[0])) + require.ErrorIs(err, collections.ErrNotFound) // set and retrieve a record require.NoError(keeper.SetDelegation(ctx, bond1to1)) - resBond, err := keeper.GetDelegation(ctx, addrDels[0], valAddrs[0]) + resBond, err := keeper.Delegations.Get(ctx, collections.Join(addrDels[0], valAddrs[0])) require.NoError(err) require.Equal(bond1to1, resBond) // modify a records, save, and retrieve bond1to1.Shares = math.LegacyNewDec(99) require.NoError(keeper.SetDelegation(ctx, bond1to1)) - resBond, err = keeper.GetDelegation(ctx, addrDels[0], valAddrs[0]) + resBond, err = keeper.Delegations.Get(ctx, collections.Join(addrDels[0], valAddrs[0])) require.NoError(err) require.Equal(bond1to1, resBond) @@ -131,8 +132,8 @@ func (s *KeeperTestSuite) TestDelegation() { // delete a record require.NoError(keeper.RemoveDelegation(ctx, bond2to3)) - _, err = keeper.GetDelegation(ctx, addrDels[1], valAddrs[2]) - require.ErrorIs(err, stakingtypes.ErrNoDelegation) + _, err = keeper.Delegations.Get(ctx, collections.Join(addrDels[1], valAddrs[2])) + require.ErrorIs(err, collections.ErrNotFound) resBonds, err = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.NoError(err) require.Equal(2, len(resBonds)) @@ -146,10 +147,10 @@ func (s *KeeperTestSuite) TestDelegation() { // delete all the records from delegator 2 require.NoError(keeper.RemoveDelegation(ctx, bond2to1)) require.NoError(keeper.RemoveDelegation(ctx, bond2to2)) - _, err = keeper.GetDelegation(ctx, addrDels[1], valAddrs[0]) - require.ErrorIs(err, stakingtypes.ErrNoDelegation) - _, err = keeper.GetDelegation(ctx, addrDels[1], valAddrs[1]) - require.ErrorIs(err, stakingtypes.ErrNoDelegation) + _, err = keeper.Delegations.Get(ctx, collections.Join(addrDels[1], valAddrs[0])) + require.ErrorIs(err, collections.ErrNotFound) + _, err = keeper.Delegations.Get(ctx, collections.Join(addrDels[1], valAddrs[1])) + require.ErrorIs(err, collections.ErrNotFound) resBonds, err = keeper.GetDelegatorDelegations(ctx, addrDels[1], 5) require.NoError(err) require.Equal(0, len(resBonds)) @@ -385,7 +386,7 @@ func (s *KeeperTestSuite) TestUnbondDelegation() { require.NoError(err) require.Equal(bondTokens, amount) // shares to be added to an unbonding delegation - delegation, err = keeper.GetDelegation(ctx, delAddrs[0], valAddrs[0]) + delegation, err = keeper.Delegations.Get(ctx, collections.Join(delAddrs[0], valAddrs[0])) require.NoError(err) validator, err = keeper.GetValidator(ctx, valAddrs[0]) require.NoError(err) diff --git a/x/staking/keeper/grpc_query.go b/x/staking/keeper/grpc_query.go index 39f628dee8..126a0026f3 100644 --- a/x/staking/keeper/grpc_query.go +++ b/x/staking/keeper/grpc_query.go @@ -2,6 +2,7 @@ package keeper import ( "context" + "errors" "strings" "google.golang.org/grpc/codes" @@ -101,8 +102,6 @@ func (k Querier) ValidatorDelegations(ctx context.Context, req *types.QueryValid return nil, err } - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - var ( dels types.Delegations pageRes *query.PageResponse @@ -111,16 +110,14 @@ func (k Querier) ValidatorDelegations(ctx context.Context, req *types.QueryValid dels, pageRes, err = query.CollectionPaginate(ctx, k.DelegationsByValidator, req.Pagination, func(key collections.Pair[sdk.ValAddress, sdk.AccAddress], _ []byte) (types.Delegation, error) { valAddr, delAddr := key.K1(), key.K2() - var delegation types.Delegation - - bz := store.Get(types.GetDelegationKey(delAddr, valAddr)) - err = k.cdc.Unmarshal(bz, &delegation) + delegation, err := k.Delegations.Get(ctx, collections.Join(delAddr, valAddr)) if err != nil { return types.Delegation{}, err } return delegation, nil - }, query.WithCollectionPaginationPairPrefix[sdk.ValAddress, sdk.AccAddress](valAddr)) + }, query.WithCollectionPaginationPairPrefix[sdk.ValAddress, sdk.AccAddress](valAddr), + ) if err != nil { delegations, pageResponse, err := k.getValidatorDelegationsLegacy(ctx, req) @@ -229,12 +226,15 @@ func (k Querier) Delegation(ctx context.Context, req *types.QueryDelegationReque return nil, err } - delegation, err := k.GetDelegation(ctx, delAddr, valAddr) + delegation, err := k.Delegations.Get(ctx, collections.Join(sdk.AccAddress(delAddr), sdk.ValAddress(valAddr))) if err != nil { - return nil, status.Errorf( - codes.NotFound, - "delegation with delegator %s not found for validator %s", - req.DelegatorAddr, req.ValidatorAddr) + if errors.Is(err, collections.ErrNotFound) { + return nil, status.Errorf( + codes.NotFound, + "delegation with delegator %s not found for validator %s", + req.DelegatorAddr, req.ValidatorAddr) + } + return nil, status.Error(codes.Internal, err.Error()) } delResponse, err := delegationToDelegationResponse(ctx, k.Keeper, delegation) @@ -288,23 +288,17 @@ func (k Querier) DelegatorDelegations(ctx context.Context, req *types.QueryDeleg if req.DelegatorAddr == "" { return nil, status.Error(codes.InvalidArgument, "delegator address cannot be empty") } - var delegations types.Delegations delAddr, err := k.authKeeper.AddressCodec().StringToBytes(req.DelegatorAddr) if err != nil { return nil, err } - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) - delStore := prefix.NewStore(store, types.GetDelegationsKey(delAddr)) - pageRes, err := query.Paginate(delStore, req.Pagination, func(key, value []byte) error { - delegation, err := types.UnmarshalDelegation(k.cdc, value) - if err != nil { - return err - } - delegations = append(delegations, delegation) - return nil - }) + delegations, pageRes, err := query.CollectionPaginate(ctx, k.Delegations, req.Pagination, + func(_ collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (types.Delegation, error) { + return del, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, sdk.ValAddress](delAddr), + ) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } @@ -442,32 +436,26 @@ func (k Querier) DelegatorValidators(ctx context.Context, req *types.QueryDelega } var validators types.Validators - store := runtime.KVStoreAdapter(k.storeService.OpenKVStore(ctx)) delAddr, err := k.authKeeper.AddressCodec().StringToBytes(req.DelegatorAddr) if err != nil { return nil, err } - delStore := prefix.NewStore(store, types.GetDelegationsKey(delAddr)) - pageRes, err := query.Paginate(delStore, req.Pagination, func(key, value []byte) error { - delegation, err := types.UnmarshalDelegation(k.cdc, value) - if err != nil { - return err - } + _, pageRes, err := query.CollectionPaginate(ctx, k.Delegations, req.Pagination, + func(_ collections.Pair[sdk.AccAddress, sdk.ValAddress], delegation types.Delegation) (types.Delegation, error) { + valAddr, err := k.validatorAddressCodec.StringToBytes(delegation.GetValidatorAddr()) + if err != nil { + return types.Delegation{}, err + } + validator, err := k.GetValidator(ctx, valAddr) + if err != nil { + return types.Delegation{}, err + } - valAddr, err := k.validatorAddressCodec.StringToBytes(delegation.GetValidatorAddr()) - if err != nil { - return err - } - - validator, err := k.GetValidator(ctx, valAddr) - if err != nil { - return err - } - - validators = append(validators, validator) - return nil - }) + validators = append(validators, validator) + return types.Delegation{}, nil + }, query.WithCollectionPaginationPairPrefix[sdk.AccAddress, sdk.ValAddress](delAddr), + ) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } diff --git a/x/staking/keeper/keeper.go b/x/staking/keeper/keeper.go index acb452d8e2..08a3dcc6e9 100644 --- a/x/staking/keeper/keeper.go +++ b/x/staking/keeper/keeper.go @@ -41,6 +41,7 @@ type Keeper struct { UnbondingID collections.Sequence ValidatorByConsensusAddress collections.Map[sdk.ConsAddress, sdk.ValAddress] UnbondingType collections.Map[uint64, uint64] + Delegations collections.Map[collections.Pair[sdk.AccAddress, sdk.ValAddress], types.Delegation] UnbondingIndex collections.Map[uint64, []byte] } @@ -85,6 +86,14 @@ func NewKeeper( LastTotalPower: collections.NewItem(sb, types.LastTotalPowerKey, "last_total_power", sdk.IntValue), HistoricalInfo: collections.NewMap(sb, types.HistoricalInfoKey, "historical_info", collections.Uint64Key, codec.CollValue[types.HistoricalInfo](cdc)), ValidatorUpdates: collections.NewItem(sb, types.ValidatorUpdatesKey, "validator_updates", codec.CollValue[types.ValidatorUpdates](cdc)), + Delegations: collections.NewMap( + sb, types.DelegationKey, "delegations", + collections.PairKeyCodec( + sdk.LengthPrefixedAddressKey(sdk.AccAddressKey), // nolint: staticcheck // sdk.LengthPrefixedAddressKey is needed to retain state compatibility + sdk.LengthPrefixedAddressKey(sdk.ValAddressKey), // nolint: staticcheck // sdk.LengthPrefixedAddressKey is needed to retain state compatibility + ), + codec.CollValue[types.Delegation](cdc), + ), DelegationsByValidator: collections.NewMap( sb, types.DelegationByValIndexKey, "delegations_by_validator", diff --git a/x/staking/keeper/msg_server_test.go b/x/staking/keeper/msg_server_test.go index df339ae371..bc3fa965e3 100644 --- a/x/staking/keeper/msg_server_test.go +++ b/x/staking/keeper/msg_server_test.go @@ -6,6 +6,7 @@ import ( "github.com/golang/mock/gomock" + "cosmossdk.io/collections" "cosmossdk.io/math" "github.com/cosmos/cosmos-sdk/codec/address" @@ -568,7 +569,7 @@ func (s *KeeperTestSuite) TestMsgBeginRedelegate() { shares := math.LegacyNewDec(100) del := stakingtypes.NewDelegation(Addr.String(), srcValAddr.String(), shares) require.NoError(keeper.SetDelegation(ctx, del)) - _, err = keeper.GetDelegation(ctx, Addr, srcValAddr) + _, err = keeper.Delegations.Get(ctx, collections.Join(Addr, srcValAddr)) require.NoError(err) testCases := []struct { @@ -722,7 +723,7 @@ func (s *KeeperTestSuite) TestMsgUndelegate() { shares := math.LegacyNewDec(100) del := stakingtypes.NewDelegation(Addr.String(), ValAddr.String(), shares) require.NoError(keeper.SetDelegation(ctx, del)) - _, err = keeper.GetDelegation(ctx, Addr, ValAddr) + _, err = keeper.Delegations.Get(ctx, collections.Join(Addr, ValAddr)) require.NoError(err) testCases := []struct { @@ -847,7 +848,7 @@ func (s *KeeperTestSuite) TestMsgCancelUnbondingDelegation() { shares := math.LegacyNewDec(100) del := stakingtypes.NewDelegation(Addr.String(), ValAddr.String(), shares) require.NoError(keeper.SetDelegation(ctx, del)) - resDel, err := keeper.GetDelegation(ctx, Addr, ValAddr) + resDel, err := keeper.Delegations.Get(ctx, collections.Join(Addr, ValAddr)) require.NoError(err) require.Equal(del, resDel) diff --git a/x/staking/keeper/query_utils.go b/x/staking/keeper/query_utils.go index 6bb16da3fc..c4e19feb4c 100644 --- a/x/staking/keeper/query_utils.go +++ b/x/staking/keeper/query_utils.go @@ -3,6 +3,7 @@ package keeper import ( "context" + "cosmossdk.io/collections" storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -14,31 +15,31 @@ func (k Keeper) GetDelegatorValidators( ctx context.Context, delegatorAddr sdk.AccAddress, maxRetrieve uint32, ) (types.Validators, error) { validators := make([]types.Validator, maxRetrieve) - store := k.storeService.OpenKVStore(ctx) - delegatorPrefixKey := types.GetDelegationsKey(delegatorAddr) - iterator, err := store.Iterator(delegatorPrefixKey, storetypes.PrefixEndBytes(delegatorPrefixKey)) // smallest to largest - if err != nil { - return nil, err - } - defer iterator.Close() + var i uint32 + rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delegatorAddr) + err := k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { + if i >= maxRetrieve { + return true, nil + } - i := 0 - for ; iterator.Valid() && i < int(maxRetrieve); iterator.Next() { - delegation := types.MustUnmarshalDelegation(k.cdc, iterator.Value()) - - valAddr, err := k.validatorAddressCodec.StringToBytes(delegation.GetValidatorAddr()) + valAddr, err := k.validatorAddressCodec.StringToBytes(del.GetValidatorAddr()) if err != nil { - return nil, err + return true, err } validator, err := k.GetValidator(ctx, valAddr) if err != nil { - return nil, err + return true, err } validators[i] = validator i++ + + return false, nil + }) + if err != nil { + return nil, err } return validators[:i], nil // trim @@ -48,7 +49,7 @@ func (k Keeper) GetDelegatorValidators( func (k Keeper) GetDelegatorValidator( ctx context.Context, delegatorAddr sdk.AccAddress, validatorAddr sdk.ValAddress, ) (validator types.Validator, err error) { - delegation, err := k.GetDelegation(ctx, delegatorAddr, validatorAddr) + delegation, err := k.Delegations.Get(ctx, collections.Join(delegatorAddr, validatorAddr)) if err != nil { return validator, err } @@ -65,23 +66,17 @@ func (k Keeper) GetDelegatorValidator( func (k Keeper) GetAllDelegatorDelegations(ctx context.Context, delegator sdk.AccAddress) ([]types.Delegation, error) { delegations := make([]types.Delegation, 0) - store := k.storeService.OpenKVStore(ctx) - delegatorPrefixKey := types.GetDelegationsKey(delegator) + var i int64 + rng := collections.NewPrefixedPairRange[sdk.AccAddress, sdk.ValAddress](delegator) + err := k.Delegations.Walk(ctx, rng, func(key collections.Pair[sdk.AccAddress, sdk.ValAddress], del types.Delegation) (stop bool, err error) { + delegations = append(delegations, del) + i++ - iterator, err := store.Iterator(delegatorPrefixKey, storetypes.PrefixEndBytes(delegatorPrefixKey)) // smallest to largest + return false, nil + }) if err != nil { return nil, err } - defer iterator.Close() - - for i := 0; iterator.Valid(); iterator.Next() { - delegation, err := types.UnmarshalDelegation(k.cdc, iterator.Value()) - if err != nil { - return nil, err - } - delegations = append(delegations, delegation) - i++ - } return delegations, nil } diff --git a/x/staking/keeper/slash.go b/x/staking/keeper/slash.go index d23b9b720a..06332a306d 100644 --- a/x/staking/keeper/slash.go +++ b/x/staking/keeper/slash.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" + "cosmossdk.io/collections" "cosmossdk.io/math" sdk "github.com/cosmos/cosmos-sdk/types" @@ -319,7 +320,7 @@ func (k Keeper) SlashRedelegation(ctx context.Context, srcValidator types.Valida panic(err) } - delegation, err := k.GetDelegation(ctx, delegatorAddress, valDstAddr) + delegation, err := k.Delegations.Get(ctx, collections.Join(sdk.AccAddress(delegatorAddress), sdk.ValAddress(valDstAddr))) if err != nil { // If deleted, delegation has zero shares, and we can't unbond any more continue diff --git a/x/staking/migrations/v2/keys.go b/x/staking/migrations/v2/keys.go index b115ed5492..8bdeef1741 100644 --- a/x/staking/migrations/v2/keys.go +++ b/x/staking/migrations/v2/keys.go @@ -14,6 +14,7 @@ const ( var ( ValidatorsByConsAddrKey = []byte{0x22} // prefix for validators by consensus address + DelegationKey = []byte{0x31} // prefix for the delegation HistoricalInfoKey = []byte{0x50} // prefix for the historical info ) @@ -22,6 +23,17 @@ func GetHistoricalInfoKey(height int64) []byte { return append(HistoricalInfoKey, []byte(strconv.FormatInt(height, 10))...) } +// GetDelegationKey creates the key for delegator bond with validator +// VALUE: staking/Delegation +func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append(GetDelegationsKey(delAddr), address.MustLengthPrefix(valAddr)...) +} + +// GetDelegationsKey gets the prefix for a delegator for all validators +func GetDelegationsKey(delAddr sdk.AccAddress) []byte { + return append(DelegationKey, address.MustLengthPrefix(delAddr.Bytes())...) +} + // GetValidatorByConsAddrKey creates the key for the validator with pubkey // VALUE: validator operator address ([]byte) func GetValidatorByConsAddrKey(addr sdk.ConsAddress) []byte { diff --git a/x/staking/migrations/v2/store_test.go b/x/staking/migrations/v2/store_test.go index da808b2a3a..b99d1b12ff 100644 --- a/x/staking/migrations/v2/store_test.go +++ b/x/staking/migrations/v2/store_test.go @@ -69,7 +69,7 @@ func TestStoreMigration(t *testing.T) { { "DelegationKey", v1.GetDelegationKey(addr4, valAddr1), - types.GetDelegationKey(addr4, valAddr1), + v2.GetDelegationKey(addr4, valAddr1), }, { "UnbondingDelegationKey", diff --git a/x/staking/migrations/v5/keys.go b/x/staking/migrations/v5/keys.go index 69e763ce61..44bc03998c 100644 --- a/x/staking/migrations/v5/keys.go +++ b/x/staking/migrations/v5/keys.go @@ -101,3 +101,14 @@ func ParseDelegationsByValKey(bz []byte) (sdk.ValAddress, sdk.AccAddress, error) return val, del, nil } + +// GetDelegationKey creates the key for delegator bond with validator +// VALUE: staking/Delegation +func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { + return append(GetDelegationsKey(delAddr), address.MustLengthPrefix(valAddr)...) +} + +// GetDelegationsKey creates the prefix for a delegator for all validators +func GetDelegationsKey(delAddr sdk.AccAddress) []byte { + return append(DelegationKey, address.MustLengthPrefix(delAddr)...) +} diff --git a/x/staking/migrations/v5/migrations_test.go b/x/staking/migrations/v5/migrations_test.go index c27180eb65..846ad86982 100644 --- a/x/staking/migrations/v5/migrations_test.go +++ b/x/staking/migrations/v5/migrations_test.go @@ -91,7 +91,7 @@ func TestDelegationsByValidatorMigrations(t *testing.T) { for i := 1; i < 11; i++ { del1 := stakingtypes.NewDelegation(accAddrs[i].String(), valAddrs[0].String(), sdkmath.LegacyNewDec(100)) - store.Set(stakingtypes.GetDelegationKey(accAddrs[i], valAddrs[0]), stakingtypes.MustMarshalDelegation(cdc, del1)) + store.Set(v5.GetDelegationKey(accAddrs[i], valAddrs[0]), stakingtypes.MustMarshalDelegation(cdc, del1)) addedDels = append(addedDels, del1) } @@ -120,7 +120,7 @@ func getValDelegations(ctx sdk.Context, cdc codec.Codec, storeKey storetypes.Sto panic(err) } - bz := store.Get(stakingtypes.GetDelegationKey(delAddr, valAddr)) + bz := store.Get(v5.GetDelegationKey(delAddr, valAddr)) cdc.MustUnmarshal(bz, &delegation) diff --git a/x/staking/simulation/decoder_test.go b/x/staking/simulation/decoder_test.go index 0179794929..b49b371d25 100644 --- a/x/staking/simulation/decoder_test.go +++ b/x/staking/simulation/decoder_test.go @@ -31,7 +31,6 @@ func TestDecodeStore(t *testing.T) { val, err := types.NewValidator(valAddr1.String(), delPk1, types.NewDescription("test", "test", "test", "test", "test")) require.NoError(t, err) - del := types.NewDelegation(delAddr1.String(), valAddr1.String(), math.LegacyOneDec()) ubd := types.NewUnbondingDelegation(delAddr1, valAddr1, 15, bondTime, math.OneInt(), 1, address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos")) red := types.NewRedelegation(delAddr1, valAddr1, valAddr1, 12, bondTime, math.OneInt(), math.LegacyOneDec(), 0, address.NewBech32Codec("cosmosvaloper"), address.NewBech32Codec("cosmos")) oneIntBz, err := math.OneInt().Marshal() @@ -42,7 +41,6 @@ func TestDecodeStore(t *testing.T) { {Key: types.LastTotalPowerKey, Value: oneIntBz}, {Key: types.GetValidatorKey(valAddr1), Value: cdc.MustMarshal(&val)}, {Key: types.LastValidatorPowerKey, Value: valAddr1.Bytes()}, - {Key: types.GetDelegationKey(delAddr1, valAddr1), Value: cdc.MustMarshal(&del)}, {Key: types.GetUBDKey(delAddr1, valAddr1), Value: cdc.MustMarshal(&ubd)}, {Key: types.GetREDKey(delAddr1, valAddr1, valAddr1), Value: cdc.MustMarshal(&red)}, {Key: []byte{0x99}, Value: []byte{0x99}}, @@ -56,7 +54,6 @@ func TestDecodeStore(t *testing.T) { {"LastTotalPower", fmt.Sprintf("%v\n%v", math.OneInt(), math.OneInt())}, {"Validator", fmt.Sprintf("%v\n%v", val, val)}, {"LastValidatorPower/ValidatorsByConsAddr/ValidatorsByPowerIndex", fmt.Sprintf("%v\n%v", valAddr1, valAddr1)}, - {"Delegation", fmt.Sprintf("%v\n%v", del, del)}, {"UnbondingDelegation", fmt.Sprintf("%v\n%v", ubd, ubd)}, {"Redelegation", fmt.Sprintf("%v\n%v", red, red)}, {"other", ""}, diff --git a/x/staking/testutil/helpers.go b/x/staking/testutil/helpers.go index 2387952b61..be09bc2625 100644 --- a/x/staking/testutil/helpers.go +++ b/x/staking/testutil/helpers.go @@ -119,12 +119,6 @@ func (sh *Helper) CheckValidator(addr sdk.ValAddress, status stakingtypes.BondSt return v } -// CheckDelegator asserts that a delegator exists -func (sh *Helper) CheckDelegator(delegator sdk.AccAddress, val sdk.ValAddress, found bool) { - _, ok := sh.k.GetDelegation(sh.Ctx, delegator, val) - require.Equal(sh.t, ok, found) -} - // TurnBlock calls EndBlocker and updates the block time func (sh *Helper) TurnBlock(newTime time.Time) sdk.Context { sh.Ctx = sh.Ctx.WithBlockTime(newTime) diff --git a/x/staking/types/keys.go b/x/staking/types/keys.go index 0c034cd633..558388291e 100644 --- a/x/staking/types/keys.go +++ b/x/staking/types/keys.go @@ -38,12 +38,12 @@ var ( ValidatorsByConsAddrKey = collections.NewPrefix(34) // prefix for each key to a validator index, by pubkey ValidatorsByPowerIndexKey = []byte{0x23} // prefix for each key to a validator index, sorted by power - DelegationKey = []byte{0x31} // key for a delegation - UnbondingDelegationKey = []byte{0x32} // key for an unbonding-delegation - UnbondingDelegationByValIndexKey = []byte{0x33} // prefix for each key for an unbonding-delegation, by validator operator - RedelegationKey = []byte{0x34} // key for a redelegation - RedelegationByValSrcIndexKey = []byte{0x35} // prefix for each key for an redelegation, by source validator operator - RedelegationByValDstIndexKey = []byte{0x36} // prefix for each key for an redelegation, by destination validator operator + DelegationKey = collections.NewPrefix(49) // key for a delegation + UnbondingDelegationKey = []byte{0x32} // key for an unbonding-delegation + UnbondingDelegationByValIndexKey = []byte{0x33} // prefix for each key for an unbonding-delegation, by validator operator + RedelegationKey = []byte{0x34} // key for a redelegation + RedelegationByValSrcIndexKey = []byte{0x35} // prefix for each key for an redelegation, by source validator operator + RedelegationByValDstIndexKey = []byte{0x36} // prefix for each key for an redelegation, by destination validator operator UnbondingIDKey = collections.NewPrefix(55) // key for the counter for the incrementing id for UnbondingOperations UnbondingIndexKey = collections.NewPrefix(56) // prefix for an index for looking up unbonding operations by their IDs @@ -189,17 +189,6 @@ func ParseValidatorQueueKey(bz []byte) (time.Time, int64, error) { return ts, int64(height), nil } -// GetDelegationKey creates the key for delegator bond with validator -// VALUE: staking/Delegation -func GetDelegationKey(delAddr sdk.AccAddress, valAddr sdk.ValAddress) []byte { - return append(GetDelegationsKey(delAddr), address.MustLengthPrefix(valAddr)...) -} - -// GetDelegationsKey creates the prefix for a delegator for all validators -func GetDelegationsKey(delAddr sdk.AccAddress) []byte { - return append(DelegationKey, address.MustLengthPrefix(delAddr)...) -} - // 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 {