Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(group)!: read the decision policy from disk in group CLI #12551

Merged
merged 9 commits into from
Jul 13, 2022
Merged
8 changes: 4 additions & 4 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,6 @@ Ref: https://keepachangelog.com/en/1.0.0/

## [Unreleased]


### API Breaking Changes

* (types) [\#12355](https://github.com/cosmos/cosmos-sdk/pull/12355) Remove the compile-time `types.DBbackend` variable. Removes usage of the same in server/util.go
### Features

* (cli) [#12028](https://github.com/cosmos/cosmos-sdk/pull/12028) Add the `tendermint key-migrate` to perform Tendermint v0.35 DB key migration.
Expand All @@ -65,6 +61,7 @@ Ref: https://keepachangelog.com/en/1.0.0/

### API Breaking Changes

* (types) [\#12355](https://github.com/cosmos/cosmos-sdk/pull/12355) Remove the compile-time `types.DBbackend` variable. Removes usage of the same in server/util.go
* (x/gov) [#12368](https://github.com/cosmos/cosmos-sdk/pull/12369) Gov keeper is now passed by reference instead of copy to make post-construction mutation of Hooks and Proposal Handlers possible at a framework level.
* (simapp) [#12270](https://github.com/cosmos/cosmos-sdk/pull/12270) Remove `invCheckPeriod uint` attribute from `SimApp` struct as per migration of `x/crisis` to app wiring
* (simapp) [#12334](https://github.com/cosmos/cosmos-sdk/pull/12334) Move `simapp.ConvertAddrsToValAddrs` and `simapp.CreateTestPubKeys ` to respectively `simtestutil.ConvertAddrsToValAddrs` and `simtestutil.CreateTestPubKeys` (`testutil/sims`)
Expand All @@ -77,6 +74,9 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/distribution) [#12434](https://github.com/cosmos/cosmos-sdk/pull/12434) `x/distribution` module `SetParams` keeper method definition is now updated to return `error`.
* (x/crisis) [#12445](https://github.com/cosmos/cosmos-sdk/pull/12445) `x/crisis` module `SetConstantFee` keeper method definition is now updated to return `error`.

### CLI Breaking Changes

* (x/group) [#12551](https://github.com/cosmos/cosmos-sdk/pull/12551) read the decision policy from disk in group CLI commands.

### Bug Fixes

Expand Down
151 changes: 69 additions & 82 deletions x/group/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package cli
import (
"fmt"
"strconv"
"strings"

"github.com/spf13/cobra"

Expand Down Expand Up @@ -53,18 +52,12 @@ func TxCmd(name string) *cobra.Command {
// 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]
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.",
Long: `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: fmt.Sprintf(`
%s tx group create-group [admin] [metadata] [members-json-file]

Where members.json contains:

Expand All @@ -81,11 +74,7 @@ Where members.json contains:
"metadata": "some metadata"
}
]
}
`,
version.AppName,
),
),
}`, version.AppName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
Expand Down Expand Up @@ -126,11 +115,8 @@ 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]
Example: fmt.Sprintf(`
%s tx group update-group-members [admin] [group-id] [members-json-file]

Where members.json contains:

Expand All @@ -150,10 +136,7 @@ Where members.json contains:
}

Set a member's weight to "0" to delete it.
`,
version.AppName,
),
),
`, version.AppName),
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
Expand Down Expand Up @@ -277,21 +260,14 @@ func MsgUpdateGroupMetadataCmd() *cobra.Command {
// MsgCreateGroupWithPolicyCmd creates a CLI command for Msg/CreateGroupWithPolicy.
func MsgCreateGroupWithPolicyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group-with-policy [admin] [group-metadata] [group-policy-metadata] [members-json-file] [decision-policy]",
Short: "Create a group with policy which is an aggregation " +
"of member accounts with associated weights, " +
"an administrator account and a decision policy. Note, the '--from' flag is " +
"ignored as it is implied from [admin].",
Long: strings.TrimSpace(
fmt.Sprintf(`Create a group with policy which is an aggregation of member accounts with associated weights,
Use: "create-group-with-policy [admin] [group-metadata] [group-policy-metadata] [members-json-file] [decision-policy-json-file]",
Short: "Create a group with policy which is an aggregation of member accounts with associated weights, an administrator account and decision policy.",
Long: `Create a group with policy which is an aggregation of member accounts with associated weights,
an administrator account and decision policy. 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.
If group-policy-as-admin flag is set to true, the admin of the newly created group and group policy is set with the group policy address itself.

Example:
$ %s tx group create-group-with-policy [admin] [group-metadata] [group-policy-metadata] [members-json-file] \
'{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", \
"windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
If group-policy-as-admin flag is set to true, the admin of the newly created group and group policy is set with the group policy address itself.`,
Example: fmt.Sprintf(`
%s tx group create-group-with-policy [admin] [group-metadata] [group-policy-metadata] members.json policy.json

where members.json contains:

Expand All @@ -309,10 +285,18 @@ where members.json contains:
}
]
}
`,
version.AppName,
),
),

and policy.json contains:

{
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
}
`, version.AppName),
Args: cobra.MinimumNArgs(5),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
Expand All @@ -335,8 +319,8 @@ where members.json contains:
return err
}

var policy group.DecisionPolicy
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[4]), &policy); err != nil {
policy, err := parseDecisionPolicy(clientCtx.Codec, args[4])
if err != nil {
return err
}

Expand Down Expand Up @@ -368,26 +352,32 @@ where members.json contains:
// MsgCreateGroupPolicyCmd creates a CLI command for Msg/CreateGroupPolicy.
func MsgCreateGroupPolicyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "create-group-policy [admin] [group-id] [metadata] [decision-policy]",
Short: "Create a group policy 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 policy 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-policy [admin] [group-id] [metadata] \
'{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", \
"windows": {"voting_period": "120h", "min_execution_period": "0s"}}'

Here, we can use percentage decision policy when needed, where 0 < percentage <= 1.
Ex: '{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"0.5", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}
`,
version.AppName,
),
),
Use: "create-group-policy [admin] [group-id] [metadata] [decision-policy-json-file]",
Short: `Create a group policy 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: fmt.Sprintf(`
%s tx group create-group-policy [admin] [group-id] [metadata] policy.json

where policy.json contains:

{
"@type": "/cosmos.group.v1.ThresholdDecisionPolicy",
"threshold": "1",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
}

Here, we can use percentage decision policy when needed, where 0 < percentage <= 1:

{
"@type": "/cosmos.group.v1.PercentageDecisionPolicy",
"percentage": "0.5",
"windows": {
"voting_period": "120h",
"min_execution_period": "0s"
}
}`, version.AppName),
Args: cobra.ExactArgs(4),
RunE: func(cmd *cobra.Command, args []string) error {
err := cmd.Flags().Set(flags.FlagFrom, args[0])
Expand All @@ -405,8 +395,8 @@ Ex: '{"@type":"/cosmos.group.v1.PercentageDecisionPolicy", "percentage":"0.5", "
return err
}

var policy group.DecisionPolicy
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[3]), &policy); err != nil {
policy, err := parseDecisionPolicy(clientCtx.Codec, args[3])
if err != nil {
return err
}

Expand Down Expand Up @@ -470,7 +460,7 @@ func MsgUpdateGroupPolicyAdminCmd() *cobra.Command {
// MsgUpdateGroupPolicyDecisionPolicyCmd creates a CLI command for Msg/UpdateGroupPolicyDecisionPolicy.
func MsgUpdateGroupPolicyDecisionPolicyCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "update-group-policy-decision-policy [admin] [group-policy-account] [decision-policy]",
Use: "update-group-policy-decision-policy [admin] [group-policy-account] [decision-policy-json-file]",
Short: "Update a group policy's decision policy",
Args: cobra.ExactArgs(3),
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -484,8 +474,8 @@ func MsgUpdateGroupPolicyDecisionPolicyCmd() *cobra.Command {
return err
}

var policy group.DecisionPolicy
if err := clientCtx.Codec.UnmarshalInterfaceJSON([]byte(args[2]), &policy); err != nil {
policy, err := parseDecisionPolicy(clientCtx.Codec, args[2])
if err != nil {
return err
}

Expand Down Expand Up @@ -556,13 +546,11 @@ func MsgSubmitProposalCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "submit-proposal [proposal_json_file]",
Short: "Submit a new proposal",
Long: fmt.Sprintf(`Submit a new proposal.

Long: `Submit a new proposal.
Parameters:
msg_tx_json_file: path to json file with messages that will be executed if the proposal is accepted.

Example:
$ %s tx group submit-proposal path/to/proposal.json
msg_tx_json_file: path to json file with messages that will be executed if the proposal is accepted.`,
Example: fmt.Sprintf(`
%s tx group submit-proposal path/to/proposal.json

Where proposal.json contains:

Expand Down Expand Up @@ -638,7 +626,7 @@ func MsgWithdrawProposalCmd() *cobra.Command {
Parameters:
proposal-id: unique ID of the proposal.
group-policy-admin-or-proposer: either admin of the group policy or one the proposer of the proposal.
(note: --from flag will be ignored here)
Note: --from flag will be ignored here.
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down Expand Up @@ -788,14 +776,13 @@ func MsgExecCmd() *cobra.Command {
func MsgLeaveGroupCmd() *cobra.Command {
cmd := &cobra.Command{
Use: "leave-group [member-address] [group-id]",
Short: "remove member from the group",
Long: ` remove member from the group
Short: "Remove member from the group",
Long: `Remove member from the group

Parameters:
group-id: unique id of the group
member-address: account address of the group member
Note, the '--from' flag is
ignored as it is implied from [member-address]
Note, the '--from' flag is ignored as it is implied from [member-address]
`,
Args: cobra.ExactArgs(2),
RunE: func(cmd *cobra.Command, args []string) error {
Expand Down
19 changes: 19 additions & 0 deletions x/group/client/cli/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package cli

import (
"encoding/json"
"fmt"
"io/ioutil"
"os"

Expand All @@ -10,6 +11,24 @@ import (
"github.com/cosmos/cosmos-sdk/x/group"
)

func parseDecisionPolicy(cdc codec.Codec, decisionPolicyFile string) (group.DecisionPolicy, error) {
if decisionPolicyFile == "" {
return nil, fmt.Errorf("decision policy is required")
}

contents, err := ioutil.ReadFile(decisionPolicyFile)
if err != nil {
return nil, err
}

var policy group.DecisionPolicy
if err := cdc.UnmarshalInterfaceJSON(contents, &policy); err != nil {
return nil, fmt.Errorf("failed to parse decision policy: %w", err)
}

return policy, nil
}

func parseMembers(membersFile string) ([]group.MemberRequest, error) {
members := group.MemberRequests{}

Expand Down
Loading