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: add draft-proposal for x/group #13353

Merged
merged 7 commits into from Sep 21, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
5 changes: 3 additions & 2 deletions CHANGELOG.md
Expand Up @@ -39,7 +39,8 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Features

* (cli) [#13304](https://github.com/cosmos/cosmos-sdk/pull/13304) Add `tx gov draft-proposal` command for generating proposal JSONs.
* (cli) [#13353](https://github.com/cosmos/cosmos-sdk/pull/13353) Add `tx group draft-proposal` command for generating group proposal JSONs (skeleton).
* (cli) [#13304](https://github.com/cosmos/cosmos-sdk/pull/13304) Add `tx gov draft-proposal` command for generating proposal JSONs (skeleton).
* (cli) [#13207](https://github.com/cosmos/cosmos-sdk/pull/13207) Reduce user's password prompts when calling keyring `List()` function
* (x/authz) [#12648](https://github.com/cosmos/cosmos-sdk/pull/12648) Add an allow list, an optional list of addresses allowed to receive bank assets via authz MsgSend grant.
* (sdk.Coins) [#12627](https://github.com/cosmos/cosmos-sdk/pull/12627) Make a Denoms method on sdk.Coins.
Expand Down Expand Up @@ -487,7 +488,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
* (x/params) [#12724](https://github.com/cosmos/cosmos-sdk/pull/12724) Add `GetParamSetIfExists` function to params `Subspace` to prevent panics on breaking changes.
* [#12668](https://github.com/cosmos/cosmos-sdk/pull/12668) Add `authz_msg_index` event attribute to message events emitted when executing via `MsgExec` through `x/authz`.
* [#12697](https://github.com/cosmos/cosmos-sdk/pull/12697) Upgrade IAVL to v0.19.0 with fast index and error propagation. NOTE: first start will take a while to propagate into new model.
- Note: after upgrading to this version it may take up to 15 minutes to migrate from 0.17 to 0.19. This time is used to create the fast cache introduced into IAVL for performance
* Note: after upgrading to this version it may take up to 15 minutes to migrate from 0.17 to 0.19. This time is used to create the fast cache introduced into IAVL for performance
* [#12784](https://github.com/cosmos/cosmos-sdk/pull/12784) Upgrade Tendermint to 0.34.20.
* (x/bank) [#12674](https://github.com/cosmos/cosmos-sdk/pull/12674) Add convenience function `CreatePrefixedAccountStoreKey()` to construct key to access account's balance for a given denom.

Expand Down
2 changes: 1 addition & 1 deletion go.mod
Expand Up @@ -12,6 +12,7 @@ require (
github.com/armon/go-metrics v0.4.1
github.com/bgentry/speakeasy v0.1.0
github.com/btcsuite/btcd v0.22.1
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e
github.com/cockroachdb/apd/v2 v2.0.2
github.com/coinbase/rosetta-sdk-go v0.8.0
github.com/confio/ics23/go v0.7.0
Expand Down Expand Up @@ -76,7 +77,6 @@ require (
github.com/cenkalti/backoff/v4 v4.1.3 // indirect
github.com/cespare/xxhash v1.1.0 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e // indirect
github.com/cosmos/gorocksdb v1.2.0 // indirect
github.com/cosmos/ledger-go v0.9.2 // indirect
github.com/creachadair/taskgroup v0.3.2 // indirect
Expand Down
2 changes: 1 addition & 1 deletion orm/go.mod
Expand Up @@ -12,6 +12,7 @@ require (
github.com/regen-network/gocuke v0.6.2
github.com/stretchr/testify v1.8.0
github.com/tendermint/tm-db v0.6.7
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b
google.golang.org/grpc v1.49.0
google.golang.org/protobuf v1.28.1
gotest.tools/v3 v3.3.0
Expand Down Expand Up @@ -49,7 +50,6 @@ require (
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 // indirect
go.etcd.io/bbolt v1.3.6 // indirect
golang.org/x/exp v0.0.0-20220916125017-b168a2c6b86b // indirect
golang.org/x/net v0.0.0-20220726230323-06994584191e // indirect
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
golang.org/x/text v0.3.7 // indirect
Expand Down
23 changes: 23 additions & 0 deletions types/tx_msg.go
@@ -1,8 +1,12 @@
package types

import (
"encoding/json"
fmt "fmt"

"github.com/cosmos/gogoproto/proto"

"github.com/cosmos/cosmos-sdk/codec"
cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
)

Expand Down Expand Up @@ -79,3 +83,22 @@ type TxEncoder func(tx Tx) ([]byte, error)
func MsgTypeURL(msg Msg) string {
return "/" + proto.MessageName(msg)
}

// GetMsgFromTypeURL returns a `sdk.Msg` message type from a type URL
func GetMsgFromTypeURL(cdc codec.Codec, input string) (Msg, error) {
julienrbrt marked this conversation as resolved.
Show resolved Hide resolved
var msg Msg
bz, err := json.Marshal(struct {
Type string `json:"@type"`
}{
Type: input,
})
if err != nil {
return nil, err
}

if err := cdc.UnmarshalInterfaceJSON(bz, &msg); err != nil {
return nil, fmt.Errorf("failed to determine sdk.Msg for %s URL : %w", input, err)
}

return msg, nil
}
80 changes: 26 additions & 54 deletions x/gov/client/cli/prompt.go
Expand Up @@ -27,17 +27,6 @@ const (
draftMetadataFileName = "draft_metadata.json"
)

// 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"` // named 'Url' instead of 'URL' for avoiding the camel case split
VoteOptionContext string `json:"vote_option_context"`
}

// Prompt prompts the user for all values of the given type.
// data is the struct to be filled
// namePrefix is the name to be display as "Enter <namePrefix> <field>"
Expand Down Expand Up @@ -115,21 +104,22 @@ func Prompt[T any](data T, namePrefix string) (T, error) {
return data, nil
}

type proposalTypes struct {
Type string
type proposalType struct {
Name string
MsgType string
Msg sdk.Msg
}

// Prompt the proposal type values and return the proposal and its metadata
func (p *proposalTypes) Prompt(cdc codec.Codec) (*proposal, ProposalMetadata, error) {
func (p *proposalType) Prompt(cdc codec.Codec) (*proposal, types.ProposalMetadata, error) {
proposal := &proposal{}

// set metadata
metadata, err := Prompt(ProposalMetadata{}, "proposal")
metadata, err := Prompt(types.ProposalMetadata{}, "proposal")
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.Metadata = "ipfs://CID"

// set deposit
Expand Down Expand Up @@ -160,60 +150,42 @@ func (p *proposalTypes) Prompt(cdc codec.Codec) (*proposal, ProposalMetadata, er
return proposal, metadata, nil
}

var supportedProposalTypes = []proposalTypes{
var suggestedProposalTypes = []proposalType{
{
Type: proposalText,
Name: proposalText,
MsgType: "", // no message for text proposal
},
{
Type: "community-pool-spend",
Name: "community-pool-spend",
MsgType: "/cosmos.distribution.v1beta1.MsgCommunityPoolSpend",
},
{
Type: "software-upgrade",
Name: "software-upgrade",
MsgType: "/cosmos.upgrade.v1beta1.MsgSoftwareUpgrade",
},
{
Type: "cancel-software-upgrade",
Name: "cancel-software-upgrade",
MsgType: "/cosmos.upgrade.v1beta1.MsgCancelUpgrade",
},
{
Type: proposalOther,
Name: proposalOther,
MsgType: "", // user will input the message type
},
}

func getProposalTypes() []string {
types := make([]string, len(supportedProposalTypes))
for i, p := range supportedProposalTypes {
types[i] = p.Type
func getProposalSuggestions() []string {
types := make([]string, len(suggestedProposalTypes))
for i, p := range suggestedProposalTypes {
types[i] = p.Name
}
return types
}

func getProposalMsg(cdc codec.Codec, input string) (sdk.Msg, error) {
var msg sdk.Msg
bz, err := json.Marshal(struct {
Type string `json:"@type"`
}{
Type: input,
})
if err != nil {
return nil, err
}

if err := cdc.UnmarshalInterfaceJSON(bz, &msg); err != nil {
return nil, fmt.Errorf("failed to determined sdk.Msg from %s proposal type : %w", input, err)
}

return msg, nil
}

// NewCmdDraftProposal let a user generate a draft proposal.
func NewCmdDraftProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "draft-proposal",
Short: "Generate a draft proposal json file. The generated proposal json contains only one message.",
Short: "Generate a draft proposal json file. The generated proposal json contains only one message (skeleton).",
SilenceUsage: true,
RunE: func(cmd *cobra.Command, _ []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
Expand All @@ -224,24 +196,24 @@ func NewCmdDraftProposal() *cobra.Command {
// prompt proposal type
proposalTypesPrompt := promptui.Select{
Label: "Select proposal type",
Items: getProposalTypes(),
Items: getProposalSuggestions(),
}

_, proposalType, err := proposalTypesPrompt.Run()
_, selectedProposalType, err := proposalTypesPrompt.Run()
if err != nil {
return fmt.Errorf("failed to prompt proposal types: %w", err)
}

var proposal proposalTypes
for _, p := range supportedProposalTypes {
if strings.EqualFold(p.Type, proposalType) {
var proposal proposalType
for _, p := range suggestedProposalTypes {
if strings.EqualFold(p.Name, selectedProposalType) {
proposal = p
break
}
}

// create any proposal type
if proposal.Type == proposalOther {
if proposal.Name == proposalOther {
// prompt proposal type
msgPrompt := promptui.Select{
Label: "Select proposal message type:",
Expand All @@ -261,23 +233,23 @@ func NewCmdDraftProposal() *cobra.Command {
}

if proposal.MsgType != "" {
proposal.Msg, err = getProposalMsg(clientCtx.Codec, proposal.MsgType)
proposal.Msg, err = sdk.GetMsgFromTypeURL(clientCtx.Codec, proposal.MsgType)
if err != nil {
// should never happen
panic(err)
}
}

prop, metadata, err := proposal.Prompt(clientCtx.Codec)
result, metadata, err := proposal.Prompt(clientCtx.Codec)
if err != nil {
return err
}

if err := writeFile(draftMetadataFileName, metadata); err != nil {
if err := writeFile(draftProposalFileName, result); err != nil {
return err
}

if err := writeFile(draftProposalFileName, prop); err != nil {
if err := writeFile(draftMetadataFileName, metadata); err != nil {
return err
}

Expand Down
12 changes: 12 additions & 0 deletions x/gov/types/metadata.go
@@ -0,0 +1,12 @@
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"` // named 'Url' instead of 'URL' for avoiding the camel case split
VoteOptionContext string `json:"vote_option_context"`
}