package keeper import ( "context" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "github.com/cosmos/cosmos-sdk/store/prefix" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/query" v3 "github.com/cosmos/cosmos-sdk/x/gov/migrations/v3" "github.com/cosmos/cosmos-sdk/x/gov/types" v1 "github.com/cosmos/cosmos-sdk/x/gov/types/v1" "github.com/cosmos/cosmos-sdk/x/gov/types/v1beta1" ) var _ v1.QueryServer = Keeper{} // Proposal returns proposal details based on ProposalID func (q Keeper) Proposal(c context.Context, req *v1.QueryProposalRequest) (*v1.QueryProposalResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } if req.ProposalId == 0 { return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } ctx := sdk.UnwrapSDKContext(c) proposal, found := q.GetProposal(ctx, req.ProposalId) if !found { return nil, status.Errorf(codes.NotFound, "proposal %d doesn't exist", req.ProposalId) } return &v1.QueryProposalResponse{Proposal: &proposal}, nil } // Proposals implements the Query/Proposals gRPC method func (q Keeper) Proposals(c context.Context, req *v1.QueryProposalsRequest) (*v1.QueryProposalsResponse, error) { ctx := sdk.UnwrapSDKContext(c) store := ctx.KVStore(q.storeKey) proposalStore := prefix.NewStore(store, types.ProposalsKeyPrefix) filteredProposals, pageRes, err := query.GenericFilteredPaginate( q.cdc, proposalStore, req.Pagination, func(key []byte, p *v1.Proposal) (*v1.Proposal, error) { matchVoter, matchDepositor, matchStatus := true, true, true // match status (if supplied/valid) if v1.ValidProposalStatus(req.ProposalStatus) { matchStatus = p.Status == req.ProposalStatus } // match voter address (if supplied) if len(req.Voter) > 0 { voter, err := sdk.AccAddressFromBech32(req.Voter) if err != nil { return nil, err } _, matchVoter = q.GetVote(ctx, p.Id, voter) } // match depositor (if supplied) if len(req.Depositor) > 0 { depositor, err := sdk.AccAddressFromBech32(req.Depositor) if err != nil { return nil, err } _, matchDepositor = q.GetDeposit(ctx, p.Id, depositor) } if matchVoter && matchDepositor && matchStatus { return p, nil } return nil, nil }, func() *v1.Proposal { return &v1.Proposal{} }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return &v1.QueryProposalsResponse{Proposals: filteredProposals, Pagination: pageRes}, nil } // Vote returns Voted information based on proposalID, voterAddr func (q Keeper) Vote(c context.Context, req *v1.QueryVoteRequest) (*v1.QueryVoteResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } if req.ProposalId == 0 { return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } if req.Voter == "" { return nil, status.Error(codes.InvalidArgument, "empty voter address") } ctx := sdk.UnwrapSDKContext(c) voter, err := sdk.AccAddressFromBech32(req.Voter) if err != nil { return nil, err } vote, found := q.GetVote(ctx, req.ProposalId, voter) if !found { return nil, status.Errorf(codes.InvalidArgument, "voter: %v not found for proposal: %v", req.Voter, req.ProposalId) } return &v1.QueryVoteResponse{Vote: &vote}, nil } // Votes returns single proposal's votes func (q Keeper) Votes(c context.Context, req *v1.QueryVotesRequest) (*v1.QueryVotesResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } if req.ProposalId == 0 { return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } var votes v1.Votes ctx := sdk.UnwrapSDKContext(c) store := ctx.KVStore(q.storeKey) votesStore := prefix.NewStore(store, types.VotesKey(req.ProposalId)) pageRes, err := query.Paginate(votesStore, req.Pagination, func(key []byte, value []byte) error { var vote v1.Vote if err := q.cdc.Unmarshal(value, &vote); err != nil { return err } votes = append(votes, &vote) return nil }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return &v1.QueryVotesResponse{Votes: votes, Pagination: pageRes}, nil } // Params queries all params func (q Keeper) Params(c context.Context, req *v1.QueryParamsRequest) (*v1.QueryParamsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } ctx := sdk.UnwrapSDKContext(c) params := q.GetParams(ctx) response := &v1.QueryParamsResponse{} //nolint:staticcheck switch req.ParamsType { case v1.ParamDeposit: depositParams := v1.NewDepositParams(params.MinDeposit, params.MaxDepositPeriod) response.DepositParams = &depositParams case v1.ParamVoting: votingParams := v1.NewVotingParams(params.VotingPeriod) response.VotingParams = &votingParams case v1.ParamTallying: tallyParams := v1.NewTallyParams(params.Quorum, params.Threshold, params.VetoThreshold) response.TallyParams = &tallyParams default: return nil, status.Errorf(codes.InvalidArgument, "%s is not a valid parameter type", req.ParamsType) } response.Params = ¶ms return response, nil } // Deposit queries single deposit information based on proposalID, depositAddr. func (q Keeper) Deposit(c context.Context, req *v1.QueryDepositRequest) (*v1.QueryDepositResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } if req.ProposalId == 0 { return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } if req.Depositor == "" { return nil, status.Error(codes.InvalidArgument, "empty depositor address") } ctx := sdk.UnwrapSDKContext(c) depositor, err := sdk.AccAddressFromBech32(req.Depositor) if err != nil { return nil, err } deposit, found := q.GetDeposit(ctx, req.ProposalId, depositor) if !found { return nil, status.Errorf(codes.InvalidArgument, "depositer: %v not found for proposal: %v", req.Depositor, req.ProposalId) } return &v1.QueryDepositResponse{Deposit: &deposit}, nil } // Deposits returns single proposal's all deposits func (q Keeper) Deposits(c context.Context, req *v1.QueryDepositsRequest) (*v1.QueryDepositsResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } if req.ProposalId == 0 { return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } var deposits []*v1.Deposit ctx := sdk.UnwrapSDKContext(c) store := ctx.KVStore(q.storeKey) depositStore := prefix.NewStore(store, types.DepositsKey(req.ProposalId)) pageRes, err := query.Paginate(depositStore, req.Pagination, func(key []byte, value []byte) error { var deposit v1.Deposit if err := q.cdc.Unmarshal(value, &deposit); err != nil { return err } deposits = append(deposits, &deposit) return nil }) if err != nil { return nil, status.Error(codes.Internal, err.Error()) } return &v1.QueryDepositsResponse{Deposits: deposits, Pagination: pageRes}, nil } // TallyResult queries the tally of a proposal vote func (q Keeper) TallyResult(c context.Context, req *v1.QueryTallyResultRequest) (*v1.QueryTallyResultResponse, error) { if req == nil { return nil, status.Error(codes.InvalidArgument, "invalid request") } if req.ProposalId == 0 { return nil, status.Error(codes.InvalidArgument, "proposal id can not be 0") } ctx := sdk.UnwrapSDKContext(c) proposal, ok := q.GetProposal(ctx, req.ProposalId) if !ok { return nil, status.Errorf(codes.NotFound, "proposal %d doesn't exist", req.ProposalId) } var tallyResult v1.TallyResult switch { case proposal.Status == v1.StatusDepositPeriod: tallyResult = v1.EmptyTallyResult() case proposal.Status == v1.StatusPassed || proposal.Status == v1.StatusRejected: tallyResult = *proposal.FinalTallyResult default: // proposal is in voting period _, _, tallyResult = q.Tally(ctx, proposal) } return &v1.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, &v1.QueryProposalRequest{ ProposalId: req.ProposalId, }) if err != nil { return nil, err } proposal, err := v3.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, &v1.QueryProposalsRequest{ ProposalStatus: v1.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 = v3.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, &v1.QueryVoteRequest{ ProposalId: req.ProposalId, Voter: req.Voter, }) if err != nil { return nil, err } vote, err := v3.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, &v1.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 = v3.ConvertToLegacyVote(*v) if err != nil { return nil, err } } return &v1beta1.QueryVotesResponse{ Votes: votes, Pagination: resp.Pagination, }, nil } //nolint:staticcheck func (q legacyQueryServer) Params(c context.Context, req *v1beta1.QueryParamsRequest) (*v1beta1.QueryParamsResponse, error) { resp, err := q.keeper.Params(c, &v1.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, &v1.QueryDepositRequest{ ProposalId: req.ProposalId, Depositor: req.Depositor, }) if err != nil { return nil, err } deposit := v3.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, &v1.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] = v3.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, &v1.QueryTallyResultRequest{ ProposalId: req.ProposalId, }) if err != nil { return nil, err } tally, err := v3.ConvertToLegacyTallyResult(resp.Tally) if err != nil { return nil, err } return &v1beta1.QueryTallyResultResponse{Tally: tally}, nil }