From df36a6fe5f07916aa08f98296dafe8d857b79a7d Mon Sep 17 00:00:00 2001 From: Callum Waters Date: Tue, 1 Feb 2022 19:25:50 +0100 Subject: [PATCH] feat: v1beta1 gov query server (#11029) --- CHANGELOG.md | 1 + x/gov/keeper/grpc_query.go | 177 ++++++++++++++++++++ x/gov/keeper/grpc_query_test.go | 267 +++++++++++++++++++++++++++++++ x/gov/keeper/keeper_test.go | 15 +- x/gov/migrations/v046/migrate.go | 119 ++++++++++++++ x/gov/module.go | 4 +- 6 files changed, 577 insertions(+), 6 deletions(-) create mode 100644 x/gov/migrations/v046/migrate.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 43dab52c4135..754a308be2be 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -124,6 +124,7 @@ Ref: https://keepachangelog.com/en/1.0.0/ * [\#9594](https://github.com/cosmos/cosmos-sdk/pull/9594) Remove legacy REST API. Please see the [REST Endpoints Migration guide](https://docs.cosmos.network/master/migrations/rest.html) to migrate to the new REST endpoints. * [\#9995](https://github.com/cosmos/cosmos-sdk/pull/9995) Increased gas cost for creating proposals. +* [\#11029](https://github.com/cosmos/cosmos-sdk/pull/11029) The deprecated Vote Option field is removed in gov v1beta2 and nil in v1beta1. Use Options instead. * [\#11013](https://github.com/cosmos/cosmos-sdk/pull/) The `tx gov submit-proposal` command has changed syntax to support the new Msg-based gov proposals. To access the old CLI command, please use `tx gov submit-legacy-proposal`. ### CLI Breaking Changes diff --git a/x/gov/keeper/grpc_query.go b/x/gov/keeper/grpc_query.go index f0a605c34bc2..167f563a71e4 100644 --- a/x/gov/keeper/grpc_query.go +++ b/x/gov/keeper/grpc_query.go @@ -9,7 +9,9 @@ import ( "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/gov/migrations/v046" "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2" ) @@ -277,3 +279,178 @@ func (q Keeper) TallyResult(c context.Context, req *v1beta2.QueryTallyResultRequ return &v1beta2.QueryTallyResultResponse{Tally: &tallyResult}, nil } + +var _ v1beta1.QueryServer = legacyQueryServer{} + +type legacyQueryServer struct { + keeper Keeper +} + +func NewLegacyQueryServer(k Keeper) v1beta1.QueryServer { + return &legacyQueryServer{keeper: k} +} + +func (q legacyQueryServer) Proposal(c context.Context, req *v1beta1.QueryProposalRequest) (*v1beta1.QueryProposalResponse, error) { + resp, err := q.keeper.Proposal(c, &v1beta2.QueryProposalRequest{ + ProposalId: req.ProposalId, + }) + if err != nil { + return nil, err + } + + proposal, err := v046.ConvertToLegacyProposal(*resp.Proposal) + if err != nil { + return nil, err + } + + return &v1beta1.QueryProposalResponse{Proposal: proposal}, nil +} + +func (q legacyQueryServer) Proposals(c context.Context, req *v1beta1.QueryProposalsRequest) (*v1beta1.QueryProposalsResponse, error) { + resp, err := q.keeper.Proposals(c, &v1beta2.QueryProposalsRequest{ + ProposalStatus: v1beta2.ProposalStatus(req.ProposalStatus), + Voter: req.Voter, + Depositor: req.Depositor, + Pagination: req.Pagination, + }) + if err != nil { + return nil, err + } + + legacyProposals := make([]v1beta1.Proposal, len(resp.Proposals)) + for idx, proposal := range resp.Proposals { + legacyProposals[idx], err = v046.ConvertToLegacyProposal(*proposal) + if err != nil { + return nil, err + } + } + + return &v1beta1.QueryProposalsResponse{ + Proposals: legacyProposals, + Pagination: resp.Pagination, + }, nil +} + +func (q legacyQueryServer) Vote(c context.Context, req *v1beta1.QueryVoteRequest) (*v1beta1.QueryVoteResponse, error) { + resp, err := q.keeper.Vote(c, &v1beta2.QueryVoteRequest{ + ProposalId: req.ProposalId, + Voter: req.Voter, + }) + if err != nil { + return nil, err + } + + vote, err := v046.ConvertToLegacyVote(*resp.Vote) + if err != nil { + return nil, err + } + + return &v1beta1.QueryVoteResponse{Vote: vote}, nil +} + +func (q legacyQueryServer) Votes(c context.Context, req *v1beta1.QueryVotesRequest) (*v1beta1.QueryVotesResponse, error) { + resp, err := q.keeper.Votes(c, &v1beta2.QueryVotesRequest{ + ProposalId: req.ProposalId, + Pagination: req.Pagination, + }) + if err != nil { + return nil, err + } + + votes := make([]v1beta1.Vote, len(resp.Votes)) + for i, v := range resp.Votes { + votes[i], err = v046.ConvertToLegacyVote(*v) + if err != nil { + return nil, err + } + } + + return &v1beta1.QueryVotesResponse{ + Votes: votes, + Pagination: resp.Pagination, + }, nil +} + +func (q legacyQueryServer) Params(c context.Context, req *v1beta1.QueryParamsRequest) (*v1beta1.QueryParamsResponse, error) { + resp, err := q.keeper.Params(c, &v1beta2.QueryParamsRequest{ + ParamsType: req.ParamsType, + }) + if err != nil { + return nil, err + } + + response := &v1beta1.QueryParamsResponse{} + + if resp.DepositParams != nil { + minDeposit := sdk.NewCoins(resp.DepositParams.MinDeposit...) + response.DepositParams = v1beta1.NewDepositParams(minDeposit, *resp.DepositParams.MaxDepositPeriod) + } + + if resp.VotingParams != nil { + response.VotingParams = v1beta1.NewVotingParams(*resp.VotingParams.VotingPeriod) + } + + if resp.TallyParams != nil { + quorum, err := sdk.NewDecFromStr(resp.TallyParams.Quorum) + if err != nil { + return nil, err + } + threshold, err := sdk.NewDecFromStr(resp.TallyParams.Threshold) + if err != nil { + return nil, err + } + vetoThreshold, err := sdk.NewDecFromStr(resp.TallyParams.VetoThreshold) + if err != nil { + return nil, err + } + + response.TallyParams = v1beta1.NewTallyParams(quorum, threshold, vetoThreshold) + } + + return response, nil +} + +func (q legacyQueryServer) Deposit(c context.Context, req *v1beta1.QueryDepositRequest) (*v1beta1.QueryDepositResponse, error) { + resp, err := q.keeper.Deposit(c, &v1beta2.QueryDepositRequest{ + ProposalId: req.ProposalId, + Depositor: req.Depositor, + }) + if err != nil { + return nil, err + } + + deposit := v046.ConvertToLegacyDeposit(resp.Deposit) + return &v1beta1.QueryDepositResponse{Deposit: deposit}, nil +} + +func (q legacyQueryServer) Deposits(c context.Context, req *v1beta1.QueryDepositsRequest) (*v1beta1.QueryDepositsResponse, error) { + resp, err := q.keeper.Deposits(c, &v1beta2.QueryDepositsRequest{ + ProposalId: req.ProposalId, + Pagination: req.Pagination, + }) + if err != nil { + return nil, err + } + deposits := make([]v1beta1.Deposit, len(resp.Deposits)) + for idx, deposit := range resp.Deposits { + deposits[idx] = v046.ConvertToLegacyDeposit(deposit) + } + + return &v1beta1.QueryDepositsResponse{Deposits: deposits, Pagination: resp.Pagination}, nil +} + +func (q legacyQueryServer) TallyResult(c context.Context, req *v1beta1.QueryTallyResultRequest) (*v1beta1.QueryTallyResultResponse, error) { + resp, err := q.keeper.TallyResult(c, &v1beta2.QueryTallyResultRequest{ + ProposalId: req.ProposalId, + }) + if err != nil { + return nil, err + } + + tally, err := v046.ConvertToLegacyTallyResult(resp.Tally) + if err != nil { + return nil, err + } + + return &v1beta1.QueryTallyResultResponse{Tally: tally}, nil +} diff --git a/x/gov/keeper/grpc_query_test.go b/x/gov/keeper/grpc_query_test.go index 1b3c6986886d..4f2750e8738d 100644 --- a/x/gov/keeper/grpc_query_test.go +++ b/x/gov/keeper/grpc_query_test.go @@ -7,6 +7,7 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" + "github.com/cosmos/cosmos-sdk/x/gov/migrations/v046" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2" ) @@ -85,6 +86,81 @@ func (suite *KeeperTestSuite) TestGRPCQueryProposal() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryProposal() { + app, ctx, queryClient := suite.app, suite.ctx, suite.legacyQueryClient + + var ( + req *v1beta1.QueryProposalRequest + expProposal v1beta1.Proposal + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryProposalRequest{} + }, + false, + }, + { + "non existing proposal request", + func() { + req = &v1beta1.QueryProposalRequest{ProposalId: 3} + }, + false, + }, + { + "zero proposal id request", + func() { + req = &v1beta1.QueryProposalRequest{ProposalId: 0} + }, + false, + }, + { + "valid request", + func() { + req = &v1beta1.QueryProposalRequest{ProposalId: 1} + testProposal := v1beta1.NewTextProposal("Proposal", "testing proposal") + msgContent, err := v1beta2.NewLegacyContent(testProposal, govAcct.String()) + suite.Require().NoError(err) + submittedProposal, err := app.GovKeeper.SubmitProposal(ctx, []sdk.Msg{msgContent}, nil) + suite.Require().NoError(err) + suite.Require().NotEmpty(submittedProposal) + + expProposal, err = v046.ConvertToLegacyProposal(submittedProposal) + suite.Require().NoError(err) + }, + true, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + proposalRes, err := queryClient.Proposal(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + // Instead of using MashalJSON, we could compare .String() output too. + // https://github.com/cosmos/cosmos-sdk/issues/10965 + expJSON, err := suite.app.AppCodec().MarshalJSON(&expProposal) + suite.Require().NoError(err) + actualJSON, err := suite.app.AppCodec().MarshalJSON(&proposalRes.Proposal) + suite.Require().NoError(err) + suite.Require().Equal(expJSON, actualJSON) + } else { + suite.Require().Error(err) + suite.Require().Nil(proposalRes) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryProposals() { app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs @@ -451,6 +527,107 @@ func (suite *KeeperTestSuite) TestGRPCQueryVotes() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryVotes() { + app, ctx, queryClient := suite.app, suite.ctx, suite.legacyQueryClient + + addrs := simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(30000000)) + + var ( + req *v1beta1.QueryVotesRequest + expRes *v1beta1.QueryVotesResponse + proposal v1beta2.Proposal + votes v1beta1.Votes + ) + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryVotesRequest{} + }, + false, + }, + { + "zero proposal id request", + func() { + req = &v1beta1.QueryVotesRequest{ + ProposalId: 0, + } + }, + false, + }, + { + "non existed proposals", + func() { + req = &v1beta1.QueryVotesRequest{ + ProposalId: 2, + } + }, + true, + }, + { + "create a proposal and get votes", + func() { + var err error + proposal, err = app.GovKeeper.SubmitProposal(ctx, TestProposal, nil) + suite.Require().NoError(err) + + req = &v1beta1.QueryVotesRequest{ + ProposalId: proposal.ProposalId, + } + }, + true, + }, + { + "request after adding 2 votes", + func() { + proposal.Status = v1beta2.StatusVotingPeriod + app.GovKeeper.SetProposal(ctx, proposal) + + votes = []v1beta1.Vote{ + {ProposalId: proposal.ProposalId, Voter: addrs[0].String(), Options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionAbstain)}, + {ProposalId: proposal.ProposalId, Voter: addrs[1].String(), Options: v1beta1.NewNonSplitVoteOption(v1beta1.OptionYes)}, + } + accAddr1, err1 := sdk.AccAddressFromBech32(votes[0].Voter) + accAddr2, err2 := sdk.AccAddressFromBech32(votes[1].Voter) + suite.Require().NoError(err1) + suite.Require().NoError(err2) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, accAddr1, v1beta2.NewNonSplitVoteOption(v1beta2.OptionAbstain))) + suite.Require().NoError(app.GovKeeper.AddVote(ctx, proposal.ProposalId, accAddr2, v1beta2.NewNonSplitVoteOption(v1beta2.OptionYes))) + + req = &v1beta1.QueryVotesRequest{ + ProposalId: proposal.ProposalId, + } + + expRes = &v1beta1.QueryVotesResponse{ + Votes: votes, + } + }, + true, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + votes, err := queryClient.Votes(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes.GetVotes(), votes.GetVotes()) + } else { + suite.Require().Error(err) + suite.Require().Nil(votes) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryParams() { queryClient := suite.queryClient @@ -533,6 +710,96 @@ func (suite *KeeperTestSuite) TestGRPCQueryParams() { } } +func (suite *KeeperTestSuite) TestLegacyGRPCQueryParams() { + queryClient := suite.legacyQueryClient + + var ( + req *v1beta1.QueryParamsRequest + expRes *v1beta1.QueryParamsResponse + ) + + defaultTallyParams := v1beta1.TallyParams{ + Quorum: sdk.NewDec(0), + Threshold: sdk.NewDec(0), + VetoThreshold: sdk.NewDec(0), + } + + testCases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "empty request", + func() { + req = &v1beta1.QueryParamsRequest{} + }, + false, + }, + { + "deposit params request", + func() { + req = &v1beta1.QueryParamsRequest{ParamsType: v1beta1.ParamDeposit} + depositParams := v1beta1.DefaultDepositParams() + expRes = &v1beta1.QueryParamsResponse{ + DepositParams: depositParams, + TallyParams: defaultTallyParams, + } + }, + true, + }, + { + "voting params request", + func() { + req = &v1beta1.QueryParamsRequest{ParamsType: v1beta1.ParamVoting} + votingParams := v1beta1.DefaultVotingParams() + expRes = &v1beta1.QueryParamsResponse{ + VotingParams: votingParams, + TallyParams: defaultTallyParams, + } + }, + true, + }, + { + "tally params request", + func() { + req = &v1beta1.QueryParamsRequest{ParamsType: v1beta1.ParamTallying} + tallyParams := v1beta1.DefaultTallyParams() + expRes = &v1beta1.QueryParamsResponse{ + TallyParams: tallyParams, + } + }, + true, + }, + { + "invalid request", + func() { + req = &v1beta1.QueryParamsRequest{ParamsType: "wrongPath"} + expRes = &v1beta1.QueryParamsResponse{} + }, + false, + }, + } + + for _, testCase := range testCases { + suite.Run(fmt.Sprintf("Case %s", testCase.msg), func() { + testCase.malleate() + + params, err := queryClient.Params(gocontext.Background(), req) + + if testCase.expPass { + suite.Require().NoError(err) + suite.Require().Equal(expRes.GetDepositParams(), params.GetDepositParams()) + suite.Require().Equal(expRes.GetVotingParams(), params.GetVotingParams()) + suite.Require().Equal(expRes.GetTallyParams(), params.GetTallyParams()) + } else { + suite.Require().Error(err) + suite.Require().Nil(params) + } + }) + } +} + func (suite *KeeperTestSuite) TestGRPCQueryDeposit() { app, ctx, queryClient, addrs := suite.app, suite.ctx, suite.queryClient, suite.addrs diff --git a/x/gov/keeper/keeper_test.go b/x/gov/keeper/keeper_test.go index 51b1f82d2631..6784513c8ad8 100644 --- a/x/gov/keeper/keeper_test.go +++ b/x/gov/keeper/keeper_test.go @@ -10,7 +10,9 @@ import ( "github.com/cosmos/cosmos-sdk/baseapp" "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/keeper" "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2" minttypes "github.com/cosmos/cosmos-sdk/x/mint/types" ) @@ -18,10 +20,11 @@ import ( type KeeperTestSuite struct { suite.Suite - app *simapp.SimApp - ctx sdk.Context - queryClient v1beta2.QueryClient - addrs []sdk.AccAddress + app *simapp.SimApp + ctx sdk.Context + queryClient v1beta2.QueryClient + legacyQueryClient v1beta1.QueryClient + addrs []sdk.AccAddress } func (suite *KeeperTestSuite) SetupTest() { @@ -38,11 +41,15 @@ func (suite *KeeperTestSuite) SetupTest() { queryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) v1beta2.RegisterQueryServer(queryHelper, app.GovKeeper) + legacyQueryHelper := baseapp.NewQueryServerTestHelper(ctx, app.InterfaceRegistry()) + v1beta1.RegisterQueryServer(legacyQueryHelper, keeper.NewLegacyQueryServer(app.GovKeeper)) queryClient := v1beta2.NewQueryClient(queryHelper) + legacyQueryClient := v1beta1.NewQueryClient(legacyQueryHelper) suite.app = app suite.ctx = ctx suite.queryClient = queryClient + suite.legacyQueryClient = legacyQueryClient suite.addrs = simapp.AddTestAddrsIncremental(app, ctx, 2, sdk.NewInt(30000000)) } diff --git a/x/gov/migrations/v046/migrate.go b/x/gov/migrations/v046/migrate.go new file mode 100644 index 000000000000..991e87376338 --- /dev/null +++ b/x/gov/migrations/v046/migrate.go @@ -0,0 +1,119 @@ +package v046 + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" + "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta2" +) + +// ConvertToLegacyProposal takes a new proposal and attempts to convert it to the +// legacy proposal format. This conversion is best effort. New proposal types that +// don't have a legacy message will return a "nil" content. +func ConvertToLegacyProposal(proposal v1beta2.Proposal) (v1beta1.Proposal, error) { + var err error + legacyProposal := v1beta1.Proposal{ + ProposalId: proposal.ProposalId, + Status: v1beta1.ProposalStatus(proposal.Status), + TotalDeposit: types.NewCoins(proposal.TotalDeposit...), + } + + legacyProposal.FinalTallyResult, err = ConvertToLegacyTallyResult(proposal.FinalTallyResult) + if err != nil { + return v1beta1.Proposal{}, err + } + + if proposal.VotingStartTime != nil { + legacyProposal.VotingStartTime = *proposal.VotingStartTime + } + + if proposal.VotingEndTime != nil { + legacyProposal.VotingEndTime = *proposal.VotingEndTime + } + + if proposal.SubmitTime != nil { + legacyProposal.SubmitTime = *proposal.SubmitTime + } + + if proposal.DepositEndTime != nil { + legacyProposal.DepositEndTime = *proposal.DepositEndTime + } + + msgs, err := proposal.GetMsgs() + if err != nil { + return v1beta1.Proposal{}, err + } + for _, msg := range msgs { + if legacyMsg, ok := msg.(*v1beta2.MsgExecLegacyContent); ok { + // check that the content struct can be unmarshalled + _, err := v1beta2.LegacyContentFromMessage(legacyMsg) + if err != nil { + return v1beta1.Proposal{}, err + } + legacyProposal.Content = legacyMsg.Content + } + } + return legacyProposal, nil +} + +func ConvertToLegacyTallyResult(tally *v1beta2.TallyResult) (v1beta1.TallyResult, error) { + yes, ok := types.NewIntFromString(tally.Yes) + if !ok { + return v1beta1.TallyResult{}, fmt.Errorf("unable to convert yes tally string (%s) to int", tally.Yes) + } + no, ok := types.NewIntFromString(tally.No) + if !ok { + return v1beta1.TallyResult{}, fmt.Errorf("unable to convert no tally string (%s) to int", tally.No) + } + veto, ok := types.NewIntFromString(tally.NoWithVeto) + if !ok { + return v1beta1.TallyResult{}, fmt.Errorf("unable to convert no with veto tally string (%s) to int", tally.NoWithVeto) + } + abstain, ok := types.NewIntFromString(tally.Abstain) + if !ok { + return v1beta1.TallyResult{}, fmt.Errorf("unable to convert abstain tally string (%s) to int", tally.Abstain) + } + + return v1beta1.TallyResult{ + Yes: yes, + No: no, + NoWithVeto: veto, + Abstain: abstain, + }, nil +} + +func ConvertToLegacyVote(vote v1beta2.Vote) (v1beta1.Vote, error) { + options, err := ConvertToLegacyVoteOptions(vote.Options) + if err != nil { + return v1beta1.Vote{}, err + } + return v1beta1.Vote{ + ProposalId: vote.ProposalId, + Voter: vote.Voter, + Options: options, + }, nil +} + +func ConvertToLegacyVoteOptions(voteOptions []*v1beta2.WeightedVoteOption) ([]v1beta1.WeightedVoteOption, error) { + options := make([]v1beta1.WeightedVoteOption, len(voteOptions)) + for i, option := range voteOptions { + weight, err := types.NewDecFromStr(option.Weight) + if err != nil { + return options, err + } + options[i] = v1beta1.WeightedVoteOption{ + Option: v1beta1.VoteOption(option.Option), + Weight: weight, + } + } + return options, nil +} + +func ConvertToLegacyDeposit(deposit *v1beta2.Deposit) v1beta1.Deposit { + return v1beta1.Deposit{ + ProposalId: deposit.ProposalId, + Depositor: deposit.Depositor, + Amount: types.NewCoins(deposit.Amount...), + } +} diff --git a/x/gov/module.go b/x/gov/module.go index 3e2002efe342..d3ce2703d09c 100644 --- a/x/gov/module.go +++ b/x/gov/module.go @@ -160,8 +160,8 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { v1beta1.RegisterMsgServer(cfg.MsgServer(), keeper.NewLegacyMsgServerImpl(am.accountKeeper.GetModuleAddress(types.ModuleName).String(), msgServer)) v1beta2.RegisterMsgServer(cfg.MsgServer(), msgServer) - // TODO Register v1beta1 query server. - // https://github.com/cosmos/cosmos-sdk/issues/10951 + legacyQueryServer := keeper.NewLegacyQueryServer(am.keeper) + v1beta1.RegisterQueryServer(cfg.QueryServer(), legacyQueryServer) v1beta2.RegisterQueryServer(cfg.QueryServer(), am.keeper) m := keeper.NewMigrator(am.keeper)