feat: Add CLI to group module (#10663)

## Description

Closes: #9899



---

### Author Checklist

*All items are required. Please add a note to the item if the item is not applicable and
please add links to any relevant follow up issues.*

I have...

- [x] included the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] added `!` to the type prefix if API or client breaking change
- [x] targeted the correct branch (see [PR Targeting](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#pr-targeting))
- [x] provided a link to the relevant issue or specification
- [x] followed the guidelines for [building modules](https://github.com/cosmos/cosmos-sdk/blob/master/docs/building-modules)
- [x] included the necessary unit and integration [tests](https://github.com/cosmos/cosmos-sdk/blob/master/CONTRIBUTING.md#testing)
- [ ] added a changelog entry to `CHANGELOG.md`
- [x] included comments for [documenting Go code](https://blog.golang.org/godoc)
- [ ] updated the relevant documentation or specification
- [ ] reviewed "Files changed" and left comments if necessary
- [ ] confirmed all CI checks have passed

### Reviewers Checklist

*All items are required. Please add a note if the item is not applicable and please add
your handle next to the items reviewed if you only reviewed selected items.*

I have...

- [ ] confirmed the correct [type prefix](https://github.com/commitizen/conventional-commit-types/blob/v3.0.0/index.json) in the PR title
- [ ] confirmed `!` in the type prefix if API or client breaking change
- [ ] confirmed all author checklist items have been addressed 
- [ ] reviewed state machine logic
- [ ] reviewed API design and naming
- [ ] reviewed documentation is accurate
- [ ] reviewed tests and test coverage
- [ ] manually tested (if applicable)
This commit is contained in:
Marie Gauthier 2021-12-15 16:17:28 +01:00 committed by GitHub
parent 675be9d6db
commit 914af6044a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 3515 additions and 31 deletions

440
x/group/client/cli/query.go Normal file
View File

@ -0,0 +1,440 @@
package cli
import (
"strconv"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/x/group"
"github.com/spf13/cobra"
)
// QueryCmd returns the cli query commands for the group module.
func QueryCmd(name string) *cobra.Command {
queryCmd := &cobra.Command{
Use: name,
Short: "Querying commands for the group module",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
queryCmd.AddCommand(
QueryGroupInfoCmd(),
QueryGroupAccountInfoCmd(),
QueryGroupMembersCmd(),
QueryGroupsByAdminCmd(),
QueryGroupAccountsByGroupCmd(),
QueryGroupAccountsByAdminCmd(),
QueryProposalCmd(),
QueryProposalsByGroupAccountCmd(),
QueryVoteByProposalVoterCmd(),
QueryVotesByProposalCmd(),
QueryVotesByVoterCmd(),
)
return queryCmd
}
// QueryGroupInfoCmd creates a CLI command for Query/GroupInfo.
func QueryGroupInfoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "group-info [id]",
Short: "Query for group info by group id",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.GroupInfo(cmd.Context(), &group.QueryGroupInfoRequest{
GroupId: groupID,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res.Info)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryGroupAccountInfoCmd creates a CLI command for Query/GroupAccountInfo.
func QueryGroupAccountInfoCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "group-account-info [group-account]",
Short: "Query for group account info by group account address",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.GroupAccountInfo(cmd.Context(), &group.QueryGroupAccountInfoRequest{
Address: args[0],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res.Info)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryGroupMembersCmd creates a CLI command for Query/GroupMembers.
func QueryGroupMembersCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "group-members [id]",
Short: "Query for group members by group id with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.GroupMembers(cmd.Context(), &group.QueryGroupMembersRequest{
GroupId: groupID,
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryGroupsByAdminCmd creates a CLI command for Query/GroupsByAdmin.
func QueryGroupsByAdminCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "groups-by-admin [admin]",
Short: "Query for groups by admin account address with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.GroupsByAdmin(cmd.Context(), &group.QueryGroupsByAdminRequest{
Admin: args[0],
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryGroupAccountsByGroupCmd creates a CLI command for Query/GroupAccountsByGroup.
func QueryGroupAccountsByGroupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "group-accounts-by-group [group-id]",
Short: "Query for group accounts by group id with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.GroupAccountsByGroup(cmd.Context(), &group.QueryGroupAccountsByGroupRequest{
GroupId: groupID,
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryGroupAccountsByAdminCmd creates a CLI command for Query/GroupAccountsByAdmin.
func QueryGroupAccountsByAdminCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "group-accounts-by-admin [admin]",
Short: "Query for group accounts by admin account address with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.GroupAccountsByAdmin(cmd.Context(), &group.QueryGroupAccountsByAdminRequest{
Admin: args[0],
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryProposalCmd creates a CLI command for Query/Proposal.
func QueryProposalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "proposal [id]",
Short: "Query for proposal by id",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.Proposal(cmd.Context(), &group.QueryProposalRequest{
ProposalId: proposalID,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryProposalsByGroupAccountCmd creates a CLI command for Query/ProposalsByGroupAccount.
func QueryProposalsByGroupAccountCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "proposals-by-group-account [group-account]",
Short: "Query for proposals by group account address with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.ProposalsByGroupAccount(cmd.Context(), &group.QueryProposalsByGroupAccountRequest{
Address: args[0],
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryVoteByProposalVoterCmd creates a CLI command for Query/VoteByProposalVoter.
func QueryVoteByProposalVoterCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "vote [proposal-id] [voter]",
Short: "Query for vote by proposal id and voter account address",
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.VoteByProposalVoter(cmd.Context(), &group.QueryVoteByProposalVoterRequest{
ProposalId: proposalID,
Voter: args[1],
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryVotesByProposalCmd creates a CLI command for Query/VotesByProposal.
func QueryVotesByProposalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "votes-by-proposal [proposal-id]",
Short: "Query for votes by proposal id with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.VotesByProposal(cmd.Context(), &group.QueryVotesByProposalRequest{
ProposalId: proposalID,
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}
// QueryVotesByVoterCmd creates a CLI command for Query/VotesByVoter.
func QueryVotesByVoterCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "votes-by-voter [voter]",
Short: "Query for votes by voter account address with pagination flags",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientQueryContext(cmd)
if err != nil {
return err
}
pageReq, err := client.ReadPageRequest(cmd.Flags())
if err != nil {
return err
}
queryClient := group.NewQueryClient(clientCtx)
res, err := queryClient.VotesByVoter(cmd.Context(), &group.QueryVotesByVoterRequest{
Voter: args[0],
Pagination: pageReq,
})
if err != nil {
return err
}
return clientCtx.PrintProto(res)
},
}
flags.AddQueryFlagsToCmd(cmd)
return cmd
}

650
x/group/client/cli/tx.go Normal file
View File

@ -0,0 +1,650 @@
package cli
import (
"encoding/base64"
"fmt"
"strconv"
"strings"
"github.com/spf13/cobra"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/flags"
"github.com/cosmos/cosmos-sdk/client/tx"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
"github.com/cosmos/cosmos-sdk/version"
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
"github.com/cosmos/cosmos-sdk/x/group"
)
const (
FlagExec = "exec"
ExecTry = "try"
)
// TxCmd returns a root CLI command handler for all x/group transaction commands.
func TxCmd(name string) *cobra.Command {
txCmd := &cobra.Command{
Use: name,
Short: "Group transaction subcommands",
DisableFlagParsing: true,
SuggestionsMinimumDistance: 2,
RunE: client.ValidateCmd,
}
txCmd.AddCommand(
MsgCreateGroupCmd(),
MsgUpdateGroupAdminCmd(),
MsgUpdateGroupMetadataCmd(),
MsgUpdateGroupMembersCmd(),
MsgCreateGroupAccountCmd(),
MsgUpdateGroupAccountAdminCmd(),
MsgUpdateGroupAccountDecisionPolicyCmd(),
MsgUpdateGroupAccountMetadataCmd(),
MsgCreateProposalCmd(),
MsgVoteCmd(),
MsgExecCmd(),
)
return txCmd
}
// MsgCreateGroupCmd creates a CLI command for Msg/CreateGroup.
func MsgCreateGroupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group [admin] [metadata] [members-json-file]",
Short: "Create a group which is an aggregation " +
"of member accounts with associated weights and " +
"an administrator account. Note, the '--from' flag is " +
"ignored as it is implied from [admin].",
Long: strings.TrimSpace(
fmt.Sprintf(`Create a group which is an aggregation of member accounts with associated weights and
an administrator account. Note, the '--from' flag is ignored as it is implied from [admin].
Members accounts can be given through a members JSON file that contains an array of members.
Example:
$ %s tx group create-group [admin] [metadata] [members-json-file]
Where members.json contains:
{
"members": [
{
"address": "addr1",
"weight": "1",
"metadata": "some metadata"
},
{
"address": "addr2",
"weight": "1",
"metadata": "some metadata"
}
]
}
`,
version.AppName,
),
),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
members, err := parseMembers(clientCtx, args[2])
if err != nil {
return err
}
metadata, err := base64.StdEncoding.DecodeString(args[1])
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "metadata is malformed, proper base64 string is required")
}
msg := &group.MsgCreateGroup{
Admin: clientCtx.GetFromAddress().String(),
Members: members,
Metadata: metadata,
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupMembersCmd creates a CLI command for Msg/UpdateGroupMembers.
func MsgUpdateGroupMembersCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-members [admin] [group-id] [members-json-file]",
Short: "Update a group's members. Set a member's weight to \"0\" to delete it.",
Long: strings.TrimSpace(
fmt.Sprintf(`Update a group's members
Example:
$ %s tx group update-group-members [admin] [group-id] [members-json-file]
Where members.json contains:
{
"members": [
{
"address": "addr1",
"weight": "1",
"metadata": "some new metadata"
},
{
"address": "addr2",
"weight": "0",
"metadata": "some metadata"
}
]
}
Set a member's weight to "0" to delete it.
`,
version.AppName,
),
),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
members, err := parseMembers(clientCtx, args[2])
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
msg := &group.MsgUpdateGroupMembers{
Admin: clientCtx.GetFromAddress().String(),
MemberUpdates: members,
GroupId: groupID,
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupAdminCmd creates a CLI command for Msg/UpdateGroupAdmin.
func MsgUpdateGroupAdminCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-admin [admin] [group-id] [new-admin]",
Short: "Update a group's admin",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
msg := &group.MsgUpdateGroupAdmin{
Admin: clientCtx.GetFromAddress().String(),
NewAdmin: args[2],
GroupId: groupID,
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupMetadataCmd creates a CLI command for Msg/UpdateGroupMetadata.
func MsgUpdateGroupMetadataCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-metadata [admin] [group-id] [metadata]",
Short: "Update a group's metadata",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
b, err := base64.StdEncoding.DecodeString(args[2])
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "metadata is malformed, proper base64 string is required")
}
msg := &group.MsgUpdateGroupMetadata{
Admin: clientCtx.GetFromAddress().String(),
Metadata: b,
GroupId: groupID,
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgCreateGroupAccountCmd creates a CLI command for Msg/CreateGroupAccount.
func MsgCreateGroupAccountCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group-account [admin] [group-id] [metadata] [decision-policy]",
Short: "Create a group account which is an account " +
"associated with a group and a decision policy. " +
"Note, the '--from' flag is " +
"ignored as it is implied from [admin].",
Long: strings.TrimSpace(
fmt.Sprintf(`Create a group account which is an account associated with a group and a decision policy.
Note, the '--from' flag is ignored as it is implied from [admin].
Example:
$ %s tx group create-group-account [admin] [group-id] [metadata] \
'{"@type":"/cosmos.group.v1beta1.ThresholdDecisionPolicy", "threshold":"1", "timeout":"1s"}'
`,
version.AppName,
),
),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
groupID, err := strconv.ParseUint(args[1], 10, 64)
if err != nil {
return err
}
var policy group.DecisionPolicy
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[3]), &policy); err != nil {
return err
}
b, err := base64.StdEncoding.DecodeString(args[2])
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "metadata is malformed, proper base64 string is required")
}
msg, err := group.NewMsgCreateGroupAccount(
clientCtx.GetFromAddress(),
groupID,
b,
policy,
)
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupAccountAdminCmd creates a CLI command for Msg/UpdateGroupAccountAdmin.
func MsgUpdateGroupAccountAdminCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-account-admin [admin] [group-account] [new-admin]",
Short: "Update a group account admin",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
msg := &group.MsgUpdateGroupAccountAdmin{
Admin: clientCtx.GetFromAddress().String(),
Address: args[1],
NewAdmin: args[2],
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupAccountDecisionPolicyCmd creates a CLI command for Msg/UpdateGroupAccountDecisionPolicy.
func MsgUpdateGroupAccountDecisionPolicyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-account-policy [admin] [group-account] [decision-policy]",
Short: "Update a group account decision policy",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
var policy group.DecisionPolicy
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[2]), &policy); err != nil {
return err
}
accountAddress, err := sdk.AccAddressFromBech32(args[1])
if err != nil {
return err
}
msg, err := group.NewMsgUpdateGroupAccountDecisionPolicyRequest(
clientCtx.GetFromAddress(),
accountAddress,
policy,
)
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgUpdateGroupAccountMetadataCmd creates a CLI command for Msg/MsgUpdateGroupAccountMetadata.
func MsgUpdateGroupAccountMetadataCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-account-metadata [admin] [group-account] [new-metadata]",
Short: "Update a group account metadata",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
b, err := base64.StdEncoding.DecodeString(args[2])
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "metadata is malformed, proper base64 string is required")
}
msg := &group.MsgUpdateGroupAccountMetadata{
Admin: clientCtx.GetFromAddress().String(),
Address: args[1],
Metadata: b,
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgCreateProposalCmd creates a CLI command for Msg/CreateProposal.
func MsgCreateProposalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-proposal [group-account] [proposer[,proposer]*] [msg_tx_json_file] [metadata]",
Short: "Submit a new proposal",
Long: `Submit a new proposal.
Parameters:
group-account: address of the group account
proposer: comma separated (no spaces) list of proposer account addresses. Example: "addr1,addr2"
Metadata: metadata for the proposal
msg_tx_json_file: path to json file with messages that will be executed if the proposal is accepted.
`,
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
proposers := strings.Split(args[1], ",")
for i := range proposers {
proposers[i] = strings.TrimSpace(proposers[i])
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
theTx, err := authclient.ReadTxFromFile(clientCtx, args[2])
if err != nil {
return err
}
msgs := theTx.GetMsgs()
b, err := base64.StdEncoding.DecodeString(args[3])
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "metadata is malformed, proper base64 string is required")
}
execStr, _ := cmd.Flags().GetString(FlagExec)
msg, err := group.NewMsgCreateProposalRequest(
args[0],
proposers,
msgs,
b,
execFromString(execStr),
)
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(FlagExec, "", "Set to 1 to try to execute proposal immediately after creation (proposers signatures are considered as Yes votes)")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgVoteCmd creates a CLI command for Msg/Vote.
func MsgVoteCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "vote [proposal-id] [voter] [choice] [metadata]",
Short: "Vote on a proposal",
Long: `Vote on a proposal.
Parameters:
proposal-id: unique ID of the proposal
voter: voter account addresses.
choice: choice of the voter(s)
CHOICE_UNSPECIFIED: no-op
CHOICE_NO: no
CHOICE_YES: yes
CHOICE_ABSTAIN: abstain
CHOICE_VETO: veto
Metadata: metadata for the vote
`,
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[1])
if err != nil {
return err
}
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
choice, err := group.ChoiceFromString(args[2])
if err != nil {
return err
}
b, err := base64.StdEncoding.DecodeString(args[3])
if err != nil {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, "metadata is malformed, proper base64 string is required")
}
execStr, _ := cmd.Flags().GetString(FlagExec)
msg := &group.MsgVote{
ProposalId: proposalID,
Voter: args[1],
Choice: choice,
Metadata: b,
Exec: execFromString(execStr),
}
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
cmd.Flags().String(FlagExec, "", "Set to 1 to try to execute proposal immediately after voting")
flags.AddTxFlagsToCmd(cmd)
return cmd
}
// MsgExecCmd creates a CLI command for Msg/MsgExec.
func MsgExecCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "exec [proposal-id]",
Short: "Execute a proposal",
Args: cobra.ExactArgs(1),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return err
}
msg := &group.MsgExec{
ProposalId: proposalID,
Signer: clientCtx.GetFromAddress().String(),
}
if err != nil {
return err
}
if err = msg.ValidateBasic(); err != nil {
return fmt.Errorf("message validation failed: %w", err)
}
return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}
flags.AddTxFlagsToCmd(cmd)
return cmd
}

View File

@ -0,0 +1,38 @@
package cli
import (
"io/ioutil"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/x/group"
)
func parseMembers(clientCtx client.Context, membersFile string) ([]group.Member, error) {
members := group.Members{}
if membersFile == "" {
return members.Members, nil
}
contents, err := ioutil.ReadFile(membersFile)
if err != nil {
return nil, err
}
err = clientCtx.Codec.UnmarshalJSON(contents, &members)
if err != nil {
return nil, err
}
return members.Members, nil
}
func execFromString(execStr string) group.Exec {
exec := group.Exec_EXEC_UNSPECIFIED
switch execStr {
case ExecTry:
exec = group.Exec_EXEC_TRY
}
return exec
}

View File

@ -0,0 +1,18 @@
//go:build norace
// +build norace
package testutil
import (
"testing"
"github.com/cosmos/cosmos-sdk/testutil/network"
"github.com/stretchr/testify/suite"
)
func TestIntegrationTestSuite(t *testing.T) {
cfg := network.DefaultConfig()
cfg.NumValidators = 2
suite.Run(t, NewIntegrationTestSuite(cfg))
}

View File

@ -0,0 +1,671 @@
package testutil
import (
"fmt"
"strconv"
"github.com/cosmos/cosmos-sdk/testutil/cli"
"github.com/cosmos/cosmos-sdk/x/group"
client "github.com/cosmos/cosmos-sdk/x/group/client/cli"
tmcli "github.com/tendermint/tendermint/libs/cli"
)
func (s *IntegrationTestSuite) TestQueryGroupInfo() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
}{
{
"group not found",
[]string{"12345", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"not found: invalid request",
0,
},
{
"group id invalid",
[]string{"", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"strconv.ParseUint: parsing \"\": invalid syntax",
0,
},
{
"group found",
[]string{strconv.FormatUint(s.group.GroupId, 10), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryGroupInfoCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var g group.GroupInfo
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &g))
s.Require().Equal(s.group.GroupId, g.GroupId)
s.Require().Equal(s.group.Admin, g.Admin)
s.Require().Equal(s.group.TotalWeight, g.TotalWeight)
s.Require().Equal(s.group.Metadata, g.Metadata)
s.Require().Equal(s.group.Version, g.Version)
}
})
}
}
func (s *IntegrationTestSuite) TestQueryGroupMembers() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectMembers []*group.GroupMember
}{
{
"no group",
[]string{"12345", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupMember{},
},
{
"members found",
[]string{strconv.FormatUint(s.group.GroupId, 10), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupMember{
{
GroupId: s.group.GroupId,
Member: &group.Member{
Address: val.Address.String(),
Weight: "3",
Metadata: []byte{1},
},
},
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryGroupMembersCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryGroupMembersResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.Members), len(tc.expectMembers))
for i := range res.Members {
s.Require().Equal(res.Members[i].GroupId, tc.expectMembers[i].GroupId)
s.Require().Equal(res.Members[i].Member.Address, tc.expectMembers[i].Member.Address)
s.Require().Equal(res.Members[i].Member.Metadata, tc.expectMembers[i].Member.Metadata)
s.Require().Equal(res.Members[i].Member.Weight, tc.expectMembers[i].Member.Weight)
}
}
})
}
}
func (s *IntegrationTestSuite) TestQueryGroupsByAdmin() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectGroups []*group.GroupInfo
}{
{
"invalid admin address",
[]string{"invalid"},
true,
"decoding bech32 failed: invalid bech32 string",
0,
[]*group.GroupInfo{},
},
{
"no group",
[]string{s.network.Validators[1].Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupInfo{},
},
{
"found groups",
[]string{val.Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupInfo{
s.group,
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryGroupsByAdminCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryGroupsByAdminResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.Groups), len(tc.expectGroups))
for i := range res.Groups {
s.Require().Equal(res.Groups[i].GroupId, tc.expectGroups[i].GroupId)
s.Require().Equal(res.Groups[i].Metadata, tc.expectGroups[i].Metadata)
s.Require().Equal(res.Groups[i].Version, tc.expectGroups[i].Version)
s.Require().Equal(res.Groups[i].TotalWeight, tc.expectGroups[i].TotalWeight)
s.Require().Equal(res.Groups[i].Admin, tc.expectGroups[i].Admin)
}
}
})
}
}
func (s *IntegrationTestSuite) TestQueryGroupAccountInfo() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
}{
{
"group account not found",
[]string{val.Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"not found: invalid request",
0,
},
{
"group account found",
[]string{s.groupAccounts[0].Address, fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryGroupAccountInfoCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var g group.GroupAccountInfo
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &g))
s.Require().Equal(s.groupAccounts[0].GroupId, g.GroupId)
s.Require().Equal(s.groupAccounts[0].Address, g.Address)
s.Require().Equal(s.groupAccounts[0].Admin, g.Admin)
s.Require().Equal(s.groupAccounts[0].Metadata, g.Metadata)
s.Require().Equal(s.groupAccounts[0].Version, g.Version)
s.Require().Equal(s.groupAccounts[0].GetDecisionPolicy(), g.GetDecisionPolicy())
}
})
}
}
func (s *IntegrationTestSuite) TestQueryGroupAccountsByGroup() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectGroupAccounts []*group.GroupAccountInfo
}{
{
"invalid group id",
[]string{""},
true,
"strconv.ParseUint: parsing \"\": invalid syntax",
0,
[]*group.GroupAccountInfo{},
},
{
"no group account",
[]string{"12345", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupAccountInfo{},
},
{
"found group accounts",
[]string{strconv.FormatUint(s.group.GroupId, 10), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupAccountInfo{
s.groupAccounts[0],
s.groupAccounts[1],
s.groupAccounts[2],
s.groupAccounts[3],
s.groupAccounts[4],
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryGroupAccountsByGroupCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryGroupAccountsByGroupResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.GroupAccounts), len(tc.expectGroupAccounts))
for i := range res.GroupAccounts {
s.Require().Equal(res.GroupAccounts[i].GroupId, tc.expectGroupAccounts[i].GroupId)
s.Require().Equal(res.GroupAccounts[i].Metadata, tc.expectGroupAccounts[i].Metadata)
s.Require().Equal(res.GroupAccounts[i].Version, tc.expectGroupAccounts[i].Version)
s.Require().Equal(res.GroupAccounts[i].Admin, tc.expectGroupAccounts[i].Admin)
s.Require().Equal(res.GroupAccounts[i].GetDecisionPolicy(), tc.expectGroupAccounts[i].GetDecisionPolicy())
}
}
})
}
}
func (s *IntegrationTestSuite) TestQueryGroupAccountsByAdmin() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectGroupAccounts []*group.GroupAccountInfo
}{
{
"invalid admin address",
[]string{"invalid"},
true,
"decoding bech32 failed: invalid bech32 string",
0,
[]*group.GroupAccountInfo{},
},
{
"no group account",
[]string{s.network.Validators[1].Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupAccountInfo{},
},
{
"found group accounts",
[]string{val.Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.GroupAccountInfo{
s.groupAccounts[0],
s.groupAccounts[1],
s.groupAccounts[2],
s.groupAccounts[3],
s.groupAccounts[4],
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryGroupAccountsByAdminCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryGroupAccountsByAdminResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.GroupAccounts), len(tc.expectGroupAccounts))
for i := range res.GroupAccounts {
s.Require().Equal(res.GroupAccounts[i].GroupId, tc.expectGroupAccounts[i].GroupId)
s.Require().Equal(res.GroupAccounts[i].Metadata, tc.expectGroupAccounts[i].Metadata)
s.Require().Equal(res.GroupAccounts[i].Version, tc.expectGroupAccounts[i].Version)
s.Require().Equal(res.GroupAccounts[i].Admin, tc.expectGroupAccounts[i].Admin)
s.Require().Equal(res.GroupAccounts[i].GetDecisionPolicy(), tc.expectGroupAccounts[i].GetDecisionPolicy())
}
}
})
}
}
func (s *IntegrationTestSuite) TestQueryProposal() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
}{
{
"not found",
[]string{"12345", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"not found",
0,
},
{
"invalid proposal id",
[]string{"", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"strconv.ParseUint: parsing \"\": invalid syntax",
0,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryProposalCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
}
})
}
}
func (s *IntegrationTestSuite) TestQueryProposalsByGroupAccount() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectProposals []*group.Proposal
}{
{
"invalid group account address",
[]string{"invalid"},
true,
"decoding bech32 failed: invalid bech32 string",
0,
[]*group.Proposal{},
},
{
"no group account",
[]string{s.network.Validators[1].Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.Proposal{},
},
{
"found proposals",
[]string{s.groupAccounts[0].Address, fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.Proposal{
s.proposal,
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryProposalsByGroupAccountCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryProposalsByGroupAccountResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.Proposals), len(tc.expectProposals))
for i := range res.Proposals {
s.Require().Equal(res.Proposals[i], tc.expectProposals[i])
}
}
})
}
}
func (s *IntegrationTestSuite) TestQueryVoteByProposalVoter() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
}{
{
"invalid voter address",
[]string{"1", "invalid", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"decoding bech32 failed: invalid bech32",
0,
},
{
"invalid proposal id",
[]string{"", val.Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"strconv.ParseUint: parsing \"\": invalid syntax",
0,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryVoteByProposalVoterCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
}
})
}
}
func (s *IntegrationTestSuite) TestQueryVotesByProposal() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectVotes []*group.Vote
}{
{
"invalid proposal id",
[]string{"", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"strconv.ParseUint: parsing \"\": invalid syntax",
0,
[]*group.Vote{},
},
{
"no votes",
[]string{"12345", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.Vote{},
},
{
"found votes",
[]string{"1", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.Vote{
s.vote,
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryVotesByProposalCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryVotesByProposalResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.Votes), len(tc.expectVotes))
for i := range res.Votes {
s.Require().Equal(res.Votes[i], tc.expectVotes[i])
}
}
})
}
}
func (s *IntegrationTestSuite) TestQueryVotesByVoter() {
val := s.network.Validators[0]
clientCtx := val.ClientCtx
testCases := []struct {
name string
args []string
expectErr bool
expectErrMsg string
expectedCode uint32
expectVotes []*group.Vote
}{
{
"invalid voter address",
[]string{"abcd", fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"decoding bech32 failed: invalid bech32",
0,
[]*group.Vote{},
},
{
"no votes",
[]string{s.groupAccounts[0].Address, fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
true,
"",
0,
[]*group.Vote{},
},
{
"found votes",
[]string{val.Address.String(), fmt.Sprintf("--%s=json", tmcli.OutputFlag)},
false,
"",
0,
[]*group.Vote{
s.vote,
},
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
cmd := client.QueryVotesByVoterCmd()
out, err := cli.ExecTestCLICmd(clientCtx, cmd, tc.args)
if tc.expectErr {
s.Require().Contains(out.String(), tc.expectErrMsg)
} else {
s.Require().NoError(err, out.String())
var res group.QueryVotesByVoterResponse
s.Require().NoError(clientCtx.Codec.UnmarshalJSON(out.Bytes(), &res))
s.Require().Equal(len(res.Votes), len(tc.expectVotes))
for i := range res.Votes {
s.Require().Equal(res.Votes[i], tc.expectVotes[i])
}
}
})
}
}

File diff suppressed because it is too large Load Diff

View File

@ -22,7 +22,7 @@ require (
)
require (
cloud.google.com/go v0.93.3 // indirect
cloud.google.com/go v0.99.0 // indirect
cloud.google.com/go/storage v1.10.0 // indirect
filippo.io/edwards25519 v1.0.0-beta.2 // indirect
github.com/99designs/keyring v1.1.6 // indirect
@ -63,7 +63,7 @@ require (
github.com/google/btree v1.0.1 // indirect
github.com/google/orderedcode v0.0.1 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gax-go/v2 v2.1.0 // indirect
github.com/googleapis/gax-go/v2 v2.1.1 // indirect
github.com/gorilla/handlers v1.5.1 // indirect
github.com/gorilla/websocket v1.4.2 // indirect
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
@ -113,7 +113,7 @@ require (
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/spf13/viper v1.9.0 // indirect
github.com/spf13/viper v1.10.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
github.com/tecbot/gorocksdb v0.0.0-20191217155057-f0fad39f321c // indirect
@ -126,15 +126,16 @@ require (
go.opencensus.io v0.23.0 // indirect
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519 // indirect
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 // indirect
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 // indirect
golang.org/x/text v0.3.7 // indirect
google.golang.org/api v0.56.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
google.golang.org/api v0.62.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4 // indirect
gopkg.in/ini.v1 v1.63.2 // indirect
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa // indirect
gopkg.in/ini.v1 v1.66.2 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b // indirect
nhooyr.io/websocket v1.8.6 // indirect

View File

@ -27,8 +27,12 @@ cloud.google.com/go v0.83.0/go.mod h1:Z7MJUsANfY0pYPdw0lbnivPx4/vhy/e2FEkSkF7vAV
cloud.google.com/go v0.84.0/go.mod h1:RazrYuxIK6Kb7YrzzhPoLmCVzl7Sup4NrbKPg8KHSUM=
cloud.google.com/go v0.87.0/go.mod h1:TpDYlFy7vuLzZMMZ+B6iRiELaY7z/gJPaqbMx6mlWcY=
cloud.google.com/go v0.90.0/go.mod h1:kRX0mNRHe0e2rC6oNakvwQqzyDmg57xJ+SZU1eT2aDQ=
cloud.google.com/go v0.93.3 h1:wPBktZFzYBcCZVARvwVKqH1uEj+aLXofJEtrb4oOsio=
cloud.google.com/go v0.93.3/go.mod h1:8utlLll2EF5XMAV15woO4lSbWQlk8rer9aLOfLh7+YI=
cloud.google.com/go v0.94.1/go.mod h1:qAlAugsXlC+JWO+Bke5vCtc9ONxjQT3drlTTnAplMW4=
cloud.google.com/go v0.97.0/go.mod h1:GF7l59pYBVlXQIBLx3a761cZ41F9bBH3JUlihCt2Udc=
cloud.google.com/go v0.98.0/go.mod h1:ua6Ush4NALrHk5QXDWnjvZHN93OuF0HfuEPq9I1X0cM=
cloud.google.com/go v0.99.0 h1:y/cM2iqGgGi5D5DQZl6D9STN/3dR/Vx5Mp8s752oJTY=
cloud.google.com/go v0.99.0/go.mod h1:w0Xx2nLzqWJPuozYQX+hFfCSI8WioryfRDzkoI/Y2ZA=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
@ -300,7 +304,6 @@ github.com/desertbit/timer v0.0.0-20180107155436-c41aec40b27f/go.mod h1:xH/i4TFM
github.com/dgraph-io/badger/v2 v2.2007.2/go.mod h1:26P/7fbL4kUZVEVKLAKXkBXKOydDmM2p1e+NhhnBCAE=
github.com/dgraph-io/badger/v2 v2.2007.4 h1:TRWBQg8UrlUhaFdco01nO2uXwzKS7zd+HVdwV/GHc4o=
github.com/dgraph-io/badger/v2 v2.2007.4/go.mod h1:vSw/ax2qojzbN6eXHIx6KPKtCSHJN/Uz0X0VPruTIhk=
github.com/dgraph-io/badger/v3 v3.2103.2/go.mod h1:RHo4/GmYcKKh5Lxu63wLEMHJ70Pac2JqZRYGhlyAo2M=
github.com/dgraph-io/ristretto v0.0.3-0.20200630154024-f66de99634de/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.0.3/go.mod h1:KPxhHT9ZxKefz+PCeOGsrHpl1qZ7i70dGTu2u+Ahh6E=
github.com/dgraph-io/ristretto v0.1.0 h1:Jv3CGQHp9OjuMBSne1485aDpUkTKEcUqF+jm/LuerPI=
@ -511,8 +514,6 @@ github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9
github.com/google/certificate-transparency-go v1.0.21/go.mod h1:QeJfpSbVSfYc7RgB3gJFj9cbuQMMchQxrWXz8Ruopmg=
github.com/google/certificate-transparency-go v1.1.1/go.mod h1:FDKqPvSXawb2ecErVRrD+nfy23RCzyl7eqVCEmlT1Zs=
github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v1.12.1/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/flatbuffers v2.0.0+incompatible/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
@ -564,8 +565,9 @@ github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gax-go/v2 v2.1.0 h1:6DWmvNpomjL1+3liNSZbVns3zsYzzCjm6pRBO1tLeso=
github.com/googleapis/gax-go/v2 v2.1.0/go.mod h1:Q3nei7sK6ybPYH7twZdmQpAd1MKb7pfu6SK+H1/DsU0=
github.com/googleapis/gax-go/v2 v2.1.1 h1:dp3bWCh+PPO1zjRRiCSczJav13sBvG4UhNyVTa1KqdU=
github.com/googleapis/gax-go/v2 v2.1.1/go.mod h1:hddJymUZASv3XPyGkUpKj8pPO47Rmb0eJc8R6ouapiM=
github.com/gookit/color v1.4.2/go.mod h1:fqRyamkC1W8uxl+lxCQxOT09l/vYfZ+QeiX3rKQHCoQ=
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
github.com/gordonklaus/ineffassign v0.0.0-20200309095847-7953dde2c7bf/go.mod h1:cuNKsD1zp2v6XfE/orVX2QE1LC+i254ceGcVeDT3pTU=
@ -707,7 +709,6 @@ github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJS
github.com/jgautheron/goconst v1.5.1/go.mod h1:aAosetZ5zaeC/2EfMeRswtxUFBpe2Hr7HzkgX4fanO4=
github.com/jhump/protoreflect v1.6.1/go.mod h1:RZQ/lnuN+zqeRVpQigTwO6o0AJUkxbnSnpuG7toUTG4=
github.com/jhump/protoreflect v1.10.1 h1:iH+UZfsbRE6vpyZH7asAjTPWJf7RJbpZ9j/N3lDlKs0=
github.com/jhump/protoreflect v1.10.1/go.mod h1:7GcYQDdMU/O/BBrl/cX6PNHpXh6cenjd8pneu5yW7Tg=
github.com/jingyugao/rowserrcheck v1.1.1/go.mod h1:4yvlZSDb3IyDTUZJUmpZfm2Hwok+Dtp+nu2qOq+er9c=
github.com/jirfag/go-printf-func-name v0.0.0-20200119135958-7558a9eaa5af/go.mod h1:HEWGJkRDzjJY2sqdDwxccsGicWEf9BQOZsq2tV+xzM0=
github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k=
@ -929,7 +930,6 @@ github.com/neilotoole/errgroup v0.1.6/go.mod h1:Q2nLGf+594h0CLBs/Mbg6qOr7GtqDK7C
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nishanths/exhaustive v0.2.3/go.mod h1:bhIX678Nx8inLM9PbpvK1yv6oGtoP8BfaIeMzgBNKvc=
github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ=
github.com/nishanths/predeclared v0.0.0-20200524104333-86fad755b4d3/go.mod h1:nt3d53pc1VYcphSCIaYAJtnPYnr3Zyn8fMq2wvPGPso=
github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/nxadm/tail v1.4.8 h1:nPr65rt6Y5JFSKQO7qToXr7pePgD6Gwiw05lkbyAQTE=
@ -1170,8 +1170,9 @@ github.com/spf13/viper v1.4.0/go.mod h1:PTJ7Z/lr49W6bUbkmS1V3by4uWynFiR9p7+dSq/y
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.7.1/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns=
github.com/spf13/viper v1.9.0 h1:yR6EXjTp0y0cLN8OZg1CRZmOBdI88UcGkhgyJhu6nZk=
github.com/spf13/viper v1.9.0/go.mod h1:+i6ajR7OX2XaiBkrcZJFK21htRk7eDeLg7+O6bhUPP4=
github.com/spf13/viper v1.10.0 h1:mXH0UwHS4D2HwWZa75im4xIQynLfblmWV7qcWpfv0yk=
github.com/spf13/viper v1.10.0/go.mod h1:SoyBPwAtKDzypXNDFKN5kzH7ppppbGZtls1UpIy5AsM=
github.com/ssgreg/nlreturn/v2 v2.2.1/go.mod h1:E/iiPB78hV7Szg2YfRgyIrk1AD6JVMTRkkxBiELzh2I=
github.com/status-im/keycard-go v0.0.0-20190316090335-8537d3370df4/go.mod h1:RZLeN1LMWmRsyYjvAu+I6Dm9QmlDaIIt+Y+4Kd7Tp+Q=
github.com/streadway/amqp v0.0.0-20190404075320-75d898a42a94/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
@ -1476,8 +1477,9 @@ golang.org/x/oauth2 v0.0.0-20210402161424-2e8d93401602/go.mod h1:KelEdhl1UZF7XfJ
golang.org/x/oauth2 v0.0.0-20210514164344-f6687ab2804c/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210628180205-a41e5a781914/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210805134026-6f1e6394065a/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f h1:Qmd2pbz05z7z6lm0DrgQVVPuBm92jqujBKMHMOlOQEw=
golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@ -1588,13 +1590,15 @@ golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210816183151-1e6c022a8912/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210903071746-97244b99971b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210908233432-aa78b53d3365/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210917161153-d61c044b1678/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211004093028-2c5d950f24ef/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02 h1:7NCfEGl0sfUojmX78nK9pBJuUlSZWEJA/TwASvfiPLo=
golang.org/x/sys v0.0.0-20211113001501-0c823b97ae02/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211124211545-fe61309f8881/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E=
golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@ -1680,7 +1684,6 @@ golang.org/x/tools v0.0.0-20200426102838-f3a5411a4c3b/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200622203043-20e05c1c8ffa/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -1689,7 +1692,6 @@ golang.org/x/tools v0.0.0-20200625211823-6506e20df31f/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200626171337-aa94e735be7f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200630154851-b2d8b0336632/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200706234117-b22de6825cf7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200724022722-7017fd6b1305/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
@ -1765,8 +1767,12 @@ google.golang.org/api v0.48.0/go.mod h1:71Pr1vy+TAZRPkPs/xlCf5SsU8WjuAWv1Pfjbtuk
google.golang.org/api v0.50.0/go.mod h1:4bNT5pAuq5ji4SRZm+5QIkjny9JAyVD/3gaSihNefaw=
google.golang.org/api v0.51.0/go.mod h1:t4HdrdoNgyN5cbEfm7Lum0lcLDLiise1F8qDKX00sOU=
google.golang.org/api v0.54.0/go.mod h1:7C4bFFOvVDGXjfDTAsgGwDgAxRDeQ4X8NvUedIt6z3k=
google.golang.org/api v0.56.0 h1:08F9XVYTLOGeSQb3xI9C0gXMuQanhdGed0cWFhDozbI=
google.golang.org/api v0.55.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.56.0/go.mod h1:38yMfeP1kfjsl8isn0tliTjIb1rJXcQi4UXlbqivdVE=
google.golang.org/api v0.57.0/go.mod h1:dVPlbZyBo2/OjBpmvNdpn2GRm6rPy75jyU7bmhdrMgI=
google.golang.org/api v0.61.0/go.mod h1:xQRti5UdCmoCEqFxcz93fTl338AVqDgyaDRuOZ3hg9I=
google.golang.org/api v0.62.0 h1:PhGymJMXfGBzc4lBRmrx9+1w4w2wEzURHNGF/sD/xGc=
google.golang.org/api v0.62.0/go.mod h1:dKmwPCydfsad4qCH08MSdgWjfHOyfpd4VtDGgRFdavw=
google.golang.org/appengine v1.2.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
@ -1841,8 +1847,17 @@ google.golang.org/genproto v0.0.0-20210805201207-89edb61ffb67/go.mod h1:ob2IJxKr
google.golang.org/genproto v0.0.0-20210813162853-db860fec028c/go.mod h1:cFeNkxwySK631ADgubI+/XFU/xp8FD5KIVV4rj8UC5w=
google.golang.org/genproto v0.0.0-20210821163610-241b8fcbd6c8/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210828152312-66f60bf46e71/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4 h1:ysnBoUyeL/H6RCvNRhWHjKoDEmguI+mPU+qHgK8qv/w=
google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210903162649-d08c68adba83/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210909211513-a8c4777a87af/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210917145530-b395a37504d4/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
google.golang.org/genproto v0.0.0-20210924002016-3dee208752a0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211118181313-81c1377c94b1/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211129164237-f09f9a12af12/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211203200212-54befc351ae9/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211206160659-862468c7d6e0/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa h1:I0YcKz0I7OAhddo7ya8kMnvprhcWM045PmkBdMO9zN0=
google.golang.org/genproto v0.0.0-20211208223120-3a66f561d7aa/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc=
google.golang.org/grpc v1.33.2 h1:EQyQC3sa8M+p6Ulc8yy9SWSS2GVwyRc83gAbG8lrl4o=
google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc=
google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw=
@ -1856,7 +1871,6 @@ google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.25.1-0.20200805231151-a709e31e5d12/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.27.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
@ -1880,8 +1894,9 @@ gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8
gopkg.in/go-playground/validator.v9 v9.29.1/go.mod h1:+c9/zcJMFNgbLvly1L1V+PpxWdVbfP1avr/N00E2vyQ=
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.63.2 h1:tGK/CyBg7SMzb60vP1M03vNZ3VDu3wGQJwn7Sxi9r3c=
gopkg.in/ini.v1 v1.63.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/ini.v1 v1.66.2 h1:XfR1dOYubytKy4Shzc2LHrrGhU0lDCfDGG1yLPmpgsI=
gopkg.in/ini.v1 v1.66.2/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
gopkg.in/natefinch/npipe.v2 v2.0.0-20160621034901-c1b8fa8bdcce/go.mod h1:5AcXVHNjg+BDxry382+8OKon8SEWiKktQR07RKPsv1c=
gopkg.in/olebedev/go-duktape.v3 v3.0.0-20200619000410-60c24ae608a6/go.mod h1:uAJfkITjFhyEEuUfm7bsmCZRbW5WRq8s9EY8HZ6hCns=
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=

View File

@ -16,6 +16,7 @@ import (
"github.com/cosmos/cosmos-sdk/types/module"
simtypes "github.com/cosmos/cosmos-sdk/types/simulation"
"github.com/cosmos/cosmos-sdk/x/group"
"github.com/cosmos/cosmos-sdk/x/group/client/cli"
groupkeeper "github.com/cosmos/cosmos-sdk/x/group/keeper"
)
@ -67,15 +68,13 @@ func (AppModuleBasic) ValidateGenesis(cdc codec.JSONCodec, config sdkclient.TxEn
}
// GetQueryCmd returns the cli query commands for the group module
func (AppModuleBasic) GetQueryCmd() *cobra.Command {
// TODO: return CLI query commands
return nil
func (a AppModuleBasic) GetQueryCmd() *cobra.Command {
return cli.QueryCmd(a.Name())
}
// GetTxCmd returns the transaction commands for the group module
func (AppModuleBasic) GetTxCmd() *cobra.Command {
// TODO: return CLI tx commands
return nil
func (a AppModuleBasic) GetTxCmd() *cobra.Command {
return cli.TxCmd(a.Name())
}
// RegisterGRPCGatewayRoutes registers the gRPC Gateway routes for the group module.

View File

@ -385,3 +385,13 @@ func (t Tally) TotalCounts() (math.Dec, error) {
}
return totalCounts, nil
}
// ChoiceFromString returns a Choice from a string. It returns an error
// if the string is invalid.
func ChoiceFromString(str string) (Choice, error) {
choice, ok := Choice_value[str]
if !ok {
return Choice_CHOICE_UNSPECIFIED, fmt.Errorf("'%s' is not a valid vote choice", str)
}
return Choice(choice), nil
}