cosmos-sdk/x/gov/client/cli/query.go

704 lines
18 KiB
Go

package cli
import (
"fmt"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/version"
gcutils "github.com/cosmos/cosmos-sdk/x/gov/client/utils"
"github.com/cosmos/cosmos-sdk/x/gov/types"
)
// GetQueryCmd returns the cli query commands for this module
func GetQueryCmd() *cobra.Command {
// Group gov queries under a subcommand
govQueryCmd := &cobra.Command{
Use: types.ModuleName,
Short: "Querying commands for the governance module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
govQueryCmd.AddCommand(
GetCmdQueryProposal(),
GetCmdQueryProposals(),
GetCmdQueryVote(),
GetCmdQueryVotes(),
GetCmdQueryParam(),
GetCmdQueryParams(),
GetCmdQueryProposer(),
GetCmdQueryDeposit(),
GetCmdQueryDeposits(),
GetCmdQueryTally(),
)
return govQueryCmd
}
// GetCmdQueryProposal implements the query proposal command.
func GetCmdQueryProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "proposal [proposal-id]",
Args: cobra.ExactArgs(1),
Short: "Query details of a single proposal",
Long: strings.TrimSpace(
fmt.Sprintf(`Query details for a proposal. You can find the
proposal-id by running "%s query gov proposals".
Example:
$ %s query gov proposal 1
`,
version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0])
}
// Query the proposal
res, err := queryClient.Proposal(
cmd.Context(),
&types.QueryProposalRequest{ProposalId: proposalID},
)
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Proposal)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryProposals implements a query proposals command. Command to Get a
// Proposal Information.
func GetCmdQueryProposals() *cobra.Command {
cmd := &cobra.Command{
Use: "proposals",
Short: "Query proposals with optional filters",
Long: strings.TrimSpace(
fmt.Sprintf(`Query for a all paginated proposals that match optional filters:
Example:
$ %s query gov proposals --depositor cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
$ %s query gov proposals --voter cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
$ %s query gov proposals --status (DepositPeriod|VotingPeriod|Passed|Rejected)
$ %s query gov proposals --page=2 --limit=100
`,
version.AppName, version.AppName, version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
bechDepositorAddr, _ := cmd.Flags().GetString(flagDepositor)
bechVoterAddr, _ := cmd.Flags().GetString(flagVoter)
strProposalStatus, _ := cmd.Flags().GetString(flagStatus)
var proposalStatus types.ProposalStatus
if len(bechDepositorAddr) != 0 {
_, err := sdk.AccAddressFromBech32(bechDepositorAddr)
if err != nil {
return err
}
}
if len(bechVoterAddr) != 0 {
_, err := sdk.AccAddressFromBech32(bechVoterAddr)
if err != nil {
return err
}
}
if len(strProposalStatus) != 0 {
proposalStatus1, err := types.ProposalStatusFromString(gcutils.NormalizeProposalStatus(strProposalStatus))
proposalStatus = proposalStatus1
if err != nil {
return err
}
}
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.Proposals(
cmd.Context(),
&types.QueryProposalsRequest{
ProposalStatus: proposalStatus,
Voter: bechVoterAddr,
Depositor: bechDepositorAddr,
Pagination: pageReq,
},
)
if err != nil {
return err
}
if len(res.GetProposals()) == 0 {
return fmt.Errorf("no proposals found")
}
return clientCtx.PrintProto(res)
},
}
cmd.Flags().String(flagDepositor, "", "(optional) filter by proposals deposited on by depositor")
cmd.Flags().String(flagVoter, "", "(optional) filter by proposals voted on by voted")
cmd.Flags().String(flagStatus, "", "(optional) filter proposals by proposal status, status: deposit_period/voting_period/passed/rejected")
flags.AddPaginationFlagsToCmd(cmd, "proposals")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryVote implements the query proposal vote command. Command to Get a
// Proposal Information.
func GetCmdQueryVote() *cobra.Command {
cmd := &cobra.Command{
Use: "vote [proposal-id] [voter-addr]",
Args: cobra.ExactArgs(2),
Short: "Query details of a single vote",
Long: strings.TrimSpace(
fmt.Sprintf(`Query details for a single vote on a proposal given its identifier.
Example:
$ %s query gov vote 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0])
}
// check to see if the proposal is in the store
ctx := cmd.Context()
_, err = queryClient.Proposal(
ctx,
&types.QueryProposalRequest{ProposalId: proposalID},
)
if err != nil {
return fmt.Errorf("failed to fetch proposal-id %d: %s", proposalID, err)
}
voterAddr, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}
res, err := queryClient.Vote(
ctx,
&types.QueryVoteRequest{ProposalId: proposalID, Voter: args[1]},
)
if err != nil {
return err
}
vote := res.GetVote()
if vote.Empty() {
params := types.NewQueryVoteParams(proposalID, voterAddr)
resByTxQuery, err := gcutils.QueryVoteByTxQuery(clientCtx, params)
if err != nil {
return err
}
if err := clientCtx.Codec.UnmarshalJSON(resByTxQuery, &vote); err != nil {
return err
}
}
return clientCtx.PrintProto(&res.Vote)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryVotes implements the command to query for proposal votes.
func GetCmdQueryVotes() *cobra.Command {
cmd := &cobra.Command{
Use: "votes [proposal-id]",
Args: cobra.ExactArgs(1),
Short: "Query votes on a proposal",
Long: strings.TrimSpace(
fmt.Sprintf(`Query vote details for a single proposal by its identifier.
Example:
$ %[1]s query gov votes 1
$ %[1]s query gov votes 1 --page=2 --limit=100
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0])
}
// check to see if the proposal is in the store
ctx := cmd.Context()
proposalRes, err := queryClient.Proposal(
ctx,
&types.QueryProposalRequest{ProposalId: proposalID},
)
if err != nil {
return fmt.Errorf("failed to fetch proposal-id %d: %s", proposalID, err)
}
propStatus := proposalRes.GetProposal().Status
if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) {
page, _ := cmd.Flags().GetInt(flags.FlagPage)
limit, _ := cmd.Flags().GetInt(flags.FlagLimit)
params := types.NewQueryProposalVotesParams(proposalID, page, limit)
resByTxQuery, err := gcutils.QueryVotesByTxQuery(clientCtx, params)
if err != nil {
return err
}
var votes types.Votes
// TODO migrate to use JSONCodec (implement MarshalJSONArray
// or wrap lists of proto.Message in some other message)
clientCtx.LegacyAmino.MustUnmarshalJSON(resByTxQuery, &votes)
return clientCtx.PrintObjectLegacy(votes)
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.Votes(
ctx,
&types.QueryVotesRequest{ProposalId: proposalID, Pagination: pageReq},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddPaginationFlagsToCmd(cmd, "votes")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryDeposit implements the query proposal deposit command. Command to
// get a specific Deposit Information
func GetCmdQueryDeposit() *cobra.Command {
cmd := &cobra.Command{
Use: "deposit [proposal-id] [depositer-addr]",
Args: cobra.ExactArgs(2),
Short: "Query details of a deposit",
Long: strings.TrimSpace(
fmt.Sprintf(`Query details for a single proposal deposit on a proposal by its identifier.
Example:
$ %s query gov deposit 1 cosmos1skjwj5whet0lpe65qaq4rpq03hjxlwd9nf39lk
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0])
}
// check to see if the proposal is in the store
ctx := cmd.Context()
proposalRes, err := queryClient.Proposal(
ctx,
&types.QueryProposalRequest{ProposalId: proposalID},
)
if err != nil {
return fmt.Errorf("failed to fetch proposal-id %d: %s", proposalID, err)
}
depositorAddr, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}
var deposit types.Deposit
propStatus := proposalRes.Proposal.Status
if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) {
params := types.NewQueryDepositParams(proposalID, depositorAddr)
resByTxQuery, err := gcutils.QueryDepositByTxQuery(clientCtx, params)
if err != nil {
return err
}
clientCtx.Codec.MustUnmarshalJSON(resByTxQuery, &deposit)
return clientCtx.PrintProto(&deposit)
}
res, err := queryClient.Deposit(
ctx,
&types.QueryDepositRequest{ProposalId: proposalID, Depositor: args[1]},
)
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Deposit)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryDeposits implements the command to query for proposal deposits.
func GetCmdQueryDeposits() *cobra.Command {
cmd := &cobra.Command{
Use: "deposits [proposal-id]",
Args: cobra.ExactArgs(1),
Short: "Query deposits on a proposal",
Long: strings.TrimSpace(
fmt.Sprintf(`Query details for all deposits on a proposal.
You can find the proposal-id by running "%s query gov proposals".
Example:
$ %s query gov deposits 1
`,
version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0])
}
// check to see if the proposal is in the store
ctx := cmd.Context()
proposalRes, err := queryClient.Proposal(
ctx,
&types.QueryProposalRequest{ProposalId: proposalID},
)
if err != nil {
return fmt.Errorf("failed to fetch proposal-id %d: %s", proposalID, err)
}
propStatus := proposalRes.GetProposal().Status
if !(propStatus == types.StatusVotingPeriod || propStatus == types.StatusDepositPeriod) {
params := types.NewQueryProposalParams(proposalID)
resByTxQuery, err := gcutils.QueryDepositsByTxQuery(clientCtx, params)
if err != nil {
return err
}
var dep types.Deposits
// TODO migrate to use JSONCodec (implement MarshalJSONArray
// or wrap lists of proto.Message in some other message)
clientCtx.LegacyAmino.MustUnmarshalJSON(resByTxQuery, &dep)
return clientCtx.PrintObjectLegacy(dep)
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
res, err := queryClient.Deposits(
ctx,
&types.QueryDepositsRequest{ProposalId: proposalID, Pagination: pageReq},
)
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddPaginationFlagsToCmd(cmd, "deposits")
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryTally implements the command to query for proposal tally result.
func GetCmdQueryTally() *cobra.Command {
cmd := &cobra.Command{
Use: "tally [proposal-id]",
Args: cobra.ExactArgs(1),
Short: "Get the tally of a proposal vote",
Long: strings.TrimSpace(
fmt.Sprintf(`Query tally of votes on a proposal. You can find
the proposal-id by running "%s query gov proposals".
Example:
$ %s query gov tally 1
`,
version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0])
}
// check to see if the proposal is in the store
ctx := cmd.Context()
_, err = queryClient.Proposal(
ctx,
&types.QueryProposalRequest{ProposalId: proposalID},
)
if err != nil {
return fmt.Errorf("failed to fetch proposal-id %d: %s", proposalID, err)
}
// Query store
res, err := queryClient.TallyResult(
ctx,
&types.QueryTallyResultRequest{ProposalId: proposalID},
)
if err != nil {
return err
}
return clientCtx.PrintProto(&res.Tally)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryParams implements the query params command.
func GetCmdQueryParams() *cobra.Command {
cmd := &cobra.Command{
Use: "params",
Short: "Query the parameters of the governance process",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the all the parameters for the governance process.
Example:
$ %s query gov params
`,
version.AppName,
),
),
Args: cobra.NoArgs,
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// Query store for all 3 params
ctx := cmd.Context()
votingRes, err := queryClient.Params(
ctx,
&types.QueryParamsRequest{ParamsType: "voting"},
)
if err != nil {
return err
}
tallyRes, err := queryClient.Params(
ctx,
&types.QueryParamsRequest{ParamsType: "tallying"},
)
if err != nil {
return err
}
depositRes, err := queryClient.Params(
ctx,
&types.QueryParamsRequest{ParamsType: "deposit"},
)
if err != nil {
return err
}
params := types.NewParams(
votingRes.GetVotingParams(),
tallyRes.GetTallyParams(),
depositRes.GetDepositParams(),
)
return clientCtx.PrintObjectLegacy(params)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryParam implements the query param command.
func GetCmdQueryParam() *cobra.Command {
cmd := &cobra.Command{
Use: "param [param-type]",
Args: cobra.ExactArgs(1),
Short: "Query the parameters (voting|tallying|deposit) of the governance process",
Long: strings.TrimSpace(
fmt.Sprintf(`Query the all the parameters for the governance process.
Example:
$ %s query gov param voting
$ %s query gov param tallying
$ %s query gov param deposit
`,
version.AppName, version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := types.NewQueryClient(clientCtx)
// Query store
res, err := queryClient.Params(
cmd.Context(),
&types.QueryParamsRequest{ParamsType: args[0]},
)
if err != nil {
return err
}
var out fmt.Stringer
switch args[0] {
case "voting":
out = res.GetVotingParams()
case "tallying":
out = res.GetTallyParams()
case "deposit":
out = res.GetDepositParams()
default:
return fmt.Errorf("argument must be one of (voting|tallying|deposit), was %s", args[0])
}
return clientCtx.PrintObjectLegacy(out)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// GetCmdQueryProposer implements the query proposer command.
func GetCmdQueryProposer() *cobra.Command {
cmd := &cobra.Command{
Use: "proposer [proposal-id]",
Args: cobra.ExactArgs(1),
Short: "Query the proposer of a governance proposal",
Long: strings.TrimSpace(
fmt.Sprintf(`Query which address proposed a proposal with a given ID.
Example:
$ %s query gov proposer 1
`,
version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
// validate that the proposalID is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s is not a valid uint", args[0])
}
prop, err := gcutils.QueryProposerByTxQuery(clientCtx, proposalID)
if err != nil {
return err
}
return clientCtx.PrintObjectLegacy(prop)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}