feat: Add support for []string and []int in draft-proposal prompt. (#14483)

This commit is contained in:
Julien Robert 2023-01-05 18:04:56 +01:00 committed by GitHub
parent 17d4ce28f0
commit 701aaa8c32
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 106 additions and 42 deletions

View File

@ -64,6 +64,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Improvements
* (x/group, x/gov) [#14483](https://github.com/cosmos/cosmos-sdk/pull/14483) Add support for `[]string` and `[]int` in `draft-proposal` prompt.
* (protobuf) [#14476](https://github.com/cosmos/cosmos-sdk/pull/14476) Clean up protobuf annotations `{accepts,implements}_interface`.
* (module) [#14415](https://github.com/cosmos/cosmos-sdk/pull/14415) Loosen assertions in SetOrderBeginBlockers() and SetOrderEndBlockers()
* (context)[#14384](https://github.com/cosmos/cosmos-sdk/pull/14384) refactor(context): Pass EventManager to the context as an interface.

View File

@ -31,7 +31,7 @@ import (
)
// ConsensusVersion defines the current x/auth module consensus version.
const ConsensusVersion = 5
const ConsensusVersion = 4
var (
_ module.AppModule = AppModule{}

View File

@ -1464,7 +1464,9 @@ Example Output:
],
"votingStartTime": "2022-03-28T14:25:26.644857113Z",
"votingEndTime": "2022-03-30T14:25:26.644857113Z",
"metadata": "AQ=="
"metadata": "AQ==",
"title": "Proposal Title",
"summary": "Proposal Summary"
},
{
"id": "2",
@ -1486,7 +1488,9 @@ Example Output:
"amount": "10"
}
],
"metadata": "AQ=="
"metadata": "AQ==",
"title": "Proposal Title",
"summary": "Proposal Summary"
}
],
"pagination": {
@ -2009,7 +2013,9 @@ Example Output:
],
"voting_start_time": "2022-03-28T14:25:26.644857113Z",
"voting_end_time": "2022-03-30T14:25:26.644857113Z",
"metadata": "AQ=="
"metadata": "AQ==",
"title": "Proposal Title",
"summary": "Proposal Summary"
}
}
```
@ -2134,7 +2140,9 @@ Example Output:
],
"voting_start_time": "2022-03-28T14:25:26.644857113Z",
"voting_end_time": "2022-03-30T14:25:26.644857113Z",
"metadata": "AQ=="
"metadata": "AQ==",
"title": "Proposal Title",
"summary": "Proposal Summary"
},
{
"id": "2",
@ -2168,7 +2176,9 @@ Example Output:
],
"voting_start_time": null,
"voting_end_time": null,
"metadata": "AQ=="
"metadata": "AQ==",
"title": "Proposal Title",
"summary": "Proposal Summary"
}
],
"pagination": {
@ -2598,6 +2608,11 @@ Location: off-chain as json object stored on IPFS (mirrors [group proposal](../g
}
```
:::note
The `authors` field is an array of strings, this is to allow for multiple authors to be listed in the metadata.
In v0.46, the `authors` field is a comma-separated string. Frontends are encouraged to support both formats for backwards compatibility.
:::
### Vote
Location: on-chain as json within 255 character limit (mirrors [group vote](../group/README.md#metadata))

View File

@ -63,10 +63,15 @@ func Prompt[T any](data T, namePrefix string) (T, error) {
}
for i := 0; i < v.NumField(); i++ {
if v.Field(i).Kind() == reflect.Struct || v.Field(i).Kind() == reflect.Slice {
// if the field is a struct skip
// in a future we can add a recursive call to Prompt
// if the field is a struct skip or not slice of string or int then skip
switch v.Field(i).Kind() {
case reflect.Struct:
// TODO(@julienrbrt) in the future we can add a recursive call to Prompt
continue
case reflect.Slice:
if v.Field(i).Type().Elem().Kind() != reflect.String && v.Field(i).Type().Elem().Kind() != reflect.Int {
continue
}
}
// create prompts
@ -117,9 +122,20 @@ func Prompt[T any](data T, namePrefix string) (T, error) {
// of which on 64-bit machines, which are most common,
// int==int64
v.Field(i).SetInt(resultInt)
case reflect.Slice:
switch v.Field(i).Type().Elem().Kind() {
case reflect.String:
v.Field(i).Set(reflect.ValueOf([]string{result}))
case reflect.Int:
resultInt, err := strconv.ParseInt(result, 10, 0)
if err != nil {
return data, fmt.Errorf("invalid value for int: %w", err)
}
v.Field(i).Set(reflect.ValueOf([]int{int(resultInt)}))
}
default:
// skip other types
// possibly in the future we can add more types (like slices)
// skip any other types
continue
}
}
@ -172,6 +188,7 @@ func (p *proposalType) Prompt(cdc codec.Codec) (*proposal, types.ProposalMetadat
return nil, metadata, fmt.Errorf("failed to marshal proposal message: %w", err)
}
proposal.Messages = append(proposal.Messages, message)
return proposal, metadata, nil
}
@ -256,7 +273,7 @@ func NewCmdDraftProposal() *cobra.Command {
return err
}
fmt.Printf("Your draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.\n")
fmt.Printf("The draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.\n")
return nil
},

View File

@ -3,10 +3,10 @@ package types
// ProposalMetadata is the metadata of a proposal
// This metadata is supposed to live off-chain when submitted in a proposal
type ProposalMetadata struct {
Title string `json:"title"`
Authors string `json:"authors"`
Summary string `json:"summary"`
Details string `json:"details"`
ProposalForumUrl string `json:"proposal_forum_url"` //nolint:revive // named 'Url' instead of 'URL' for avoiding the camel case split
VoteOptionContext string `json:"vote_option_context"`
Title string `json:"title"`
Authors []string `json:"authors"`
Summary string `json:"summary"`
Details string `json:"details"`
ProposalForumUrl string `json:"proposal_forum_url"` //nolint:revive // named 'Url' instead of 'URL' for avoiding the camel case split
VoteOptionContext string `json:"vote_option_context"`
}

View File

@ -848,6 +848,8 @@ proposal:
no_count: "0"
veto_count: "0"
yes_count: "0"
summary: "Summary"
title: "Title"
```
##### proposals-by-group-policy
@ -897,6 +899,8 @@ proposals:
no_count: "0"
veto_count: "0"
yes_count: "0"
summary: "Summary"
title: "Title"
```
##### vote
@ -988,7 +992,7 @@ The `tx` commands allow users to interact with the `group` module.
simd tx group --help
```
##### create-group
#### create-group
The `create-group` command allows users to create a group which is an aggregation of member accounts with associated weights and
an administrator account.
@ -1003,7 +1007,7 @@ Example:
simd tx group create-group cosmos1.. "AQ==" members.json
```
##### update-group-admin
#### update-group-admin
The `update-group-admin` command allows users to update a group's admin.
@ -1017,7 +1021,7 @@ Example:
simd tx group update-group-admin cosmos1.. 1 cosmos1..
```
##### update-group-members
#### update-group-members
The `update-group-members` command allows users to update a group's members.
@ -1031,7 +1035,7 @@ Example:
simd tx group update-group-members cosmos1.. 1 members.json
```
##### update-group-metadata
#### update-group-metadata
The `update-group-metadata` command allows users to update a group's metadata.
@ -1045,7 +1049,7 @@ Example:
simd tx group update-group-metadata cosmos1.. 1 "AQ=="
```
##### create-group-policy
#### create-group-policy
The `create-group-policy` command allows users to create a group policy which is an account associated with a group and a decision policy.
@ -1059,7 +1063,7 @@ Example:
simd tx group create-group-policy cosmos1.. 1 "AQ==" '{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
```
##### create-group-with-policy
#### create-group-with-policy
The `create-group-with-policy` command allows users to create a group which is an aggregation of member accounts with associated weights and an administrator account with decision policy. If the `--group-policy-as-admin` flag is set to `true`, the group policy address becomes the group and group policy admin.
@ -1073,7 +1077,7 @@ Example:
simd tx group create-group-with-policy cosmos1.. "AQ==" "AQ==" members.json '{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"1", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
```
##### update-group-policy-admin
#### update-group-policy-admin
The `update-group-policy-admin` command allows users to update a group policy admin.
@ -1087,7 +1091,7 @@ Example:
simd tx group update-group-policy-admin cosmos1.. cosmos1.. cosmos1..
```
##### update-group-policy-metadata
#### update-group-policy-metadata
The `update-group-policy-metadata` command allows users to update a group policy metadata.
@ -1101,7 +1105,7 @@ Example:
simd tx group update-group-policy-metadata cosmos1.. cosmos1.. "AQ=="
```
##### update-group-policy-decision-policy
#### update-group-policy-decision-policy
The `update-group-policy-decision-policy` command allows users to update a group policy's decision policy.
@ -1115,7 +1119,7 @@ Example:
simd tx group update-group-policy-decision-policy cosmos1.. cosmos1.. '{"@type":"/cosmos.group.v1.ThresholdDecisionPolicy", "threshold":"2", "windows": {"voting_period": "120h", "min_execution_period": "0s"}}'
```
##### create-proposal
#### create-proposal
The `create-proposal` command allows users to submit a new proposal.
@ -1129,7 +1133,7 @@ Example:
simd tx group create-proposal cosmos1.. cosmos1.. msg_tx.json "AQ=="
```
##### withdraw-proposal
#### withdraw-proposal
The `withdraw-proposal` command allows users to withdraw a proposal.
@ -1143,7 +1147,7 @@ Example:
simd tx group withdraw-proposal 1 cosmos1..
```
##### vote
#### vote
The `vote` command allows users to vote on a proposal.
@ -1157,7 +1161,7 @@ Example:
simd tx group vote 1 cosmos1.. CHOICE_YES "AQ=="
```
##### exec
#### exec
The `exec` command allows users to execute a proposal.
@ -1171,7 +1175,7 @@ Example:
simd tx group exec 1
```
##### leave-group
#### leave-group
The `leave-group` command allows group member to leave the group.
@ -1452,9 +1456,11 @@ Example Output:
"voting_period": "432000s"
},
"executorResult": "EXECUTOR_RESULT_NOT_RUN",
"msgs": [
"messages": [
{"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"100000000"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."}
]
],
"title": "Title",
"summary": "Summary",
}
}
```
@ -1501,9 +1507,11 @@ Example Output:
"voting_period": "432000s"
},
"executorResult": "EXECUTOR_RESULT_NOT_RUN",
"msgs": [
"messages": [
{"@type":"/cosmos.bank.v1beta1.MsgSend","amount":[{"denom":"stake","amount":"100000000"}],"fromAddress":"cosmos1..","toAddress":"cosmos1.."}
]
],
"title": "Title",
"summary": "Summary",
}
],
"pagination": {
@ -1911,7 +1919,7 @@ Example Output:
"voting_period": "432000s"
},
"executor_result": "EXECUTOR_RESULT_NOT_RUN",
"msgs": [
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from_address": "cosmos1..",
@ -1923,7 +1931,9 @@ Example Output:
}
]
}
]
],
"title": "Title",
"summary": "Summary",
}
}
```
@ -1970,7 +1980,7 @@ Example Output:
"voting_period": "432000s"
},
"executor_result": "EXECUTOR_RESULT_NOT_RUN",
"msgs": [
"messages": [
{
"@type": "/cosmos.bank.v1beta1.MsgSend",
"from_address": "cosmos1..",
@ -2107,6 +2117,11 @@ Location: off-chain as json object stored on IPFS (mirrors [gov proposal](../gov
}
```
:::note
The `authors` field is an array of strings, this is to allow for multiple authors to be listed in the metadata.
In v0.46, the `authors` field is a comma-separated string. Frontends are encouraged to support both formats for backwards compatibility.
:::
### Vote
Location: on-chain as json within 255 character limit (mirrors [gov vote](../gov/README.md#metadata))

View File

@ -36,7 +36,7 @@ func (p *proposalType) Prompt(cdc codec.Codec) (*Proposal, govtypes.ProposalMeta
if err != nil {
return nil, metadata, fmt.Errorf("failed to set proposal metadata: %w", err)
}
// the metadata must be saved on IPFS, set placeholder
proposal := &Proposal{
Metadata: "ipfs://CID", // the metadata must be saved on IPFS, set placeholder
Title: metadata.Title,
@ -54,6 +54,17 @@ func (p *proposalType) Prompt(cdc codec.Codec) (*Proposal, govtypes.ProposalMeta
}
proposal.GroupPolicyAddress = groupPolicyAddress
// set proposer address
proposerPrompt := promptui.Prompt{
Label: "Enter proposer address",
Validate: client.ValidatePromptAddress,
}
proposerAddress, err := proposerPrompt.Run()
if err != nil {
return nil, metadata, fmt.Errorf("failed to set proposer address: %w", err)
}
proposal.Proposers = []string{proposerAddress}
if p.Msg == nil {
return proposal, metadata, nil
}
@ -69,6 +80,7 @@ func (p *proposalType) Prompt(cdc codec.Codec) (*Proposal, govtypes.ProposalMeta
return nil, metadata, fmt.Errorf("failed to marshal proposal message: %w", err)
}
proposal.Messages = append(proposal.Messages, message)
return proposal, metadata, nil
}
@ -138,7 +150,7 @@ func NewCmdDraftProposal() *cobra.Command {
return err
}
fmt.Printf("Your draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.\n")
fmt.Printf("The draft proposal has successfully been generated.\nProposals should contain off-chain metadata, please upload the metadata JSON to IPFS.\nThen, replace the generated metadata field with the IPFS CID.\n")
return nil
},

View File

@ -1,6 +1,7 @@
package cli
import (
"errors"
"fmt"
"strconv"
@ -581,6 +582,9 @@ Parameters:
// Since the --from flag is not required on this CLI command, we
// ignore it, and just use the 1st proposer in the JSON file.
if prop.Proposers == nil || len(prop.Proposers) == 0 {
return errors.New("no proposers specified in proposal")
}
cmd.Flags().Set(flags.FlagFrom, prop.Proposers[0])
clientCtx, err := client.GetClientTxContext(cmd)

View File

@ -65,7 +65,7 @@ type Proposal struct {
// Messages defines an array of sdk.Msgs proto-JSON-encoded as Anys.
Messages []json.RawMessage `json:"messages,omitempty"`
Metadata string `json:"metadata"`
Proposers []string `json:"proposers,omitempty"`
Proposers []string `json:"proposers"`
Title string `json:"title"`
Summary string `json:"summary"`
}