Skip to content

Commit

Permalink
feat!: have tx gov submit-proposal accept either new or legacy syntax
Browse files Browse the repository at this point in the history
Have submit-legacy-proposal be an alias for submit-proposal.
Invocations of the legacy syntax should either upgrade to the
new syntax, or explicitly use submit-legacy-proposal. When
all legacy usages have so migrated, this change can be dropped.
See Agoric/agoric-sdk#8871.
  • Loading branch information
JimLarson authored and JeancarloBarrios committed Sep 28, 2024
1 parent 2fa15da commit 3e9a308
Showing 1 changed file with 128 additions and 45 deletions.
173 changes: 128 additions & 45 deletions x/gov/client/cli/tx.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,30 +62,32 @@ func NewTxCmd(legacyPropCmds []*cobra.Command) *cobra.Command {
RunE: client.ValidateCmd,
}

cmdSubmitLegacyProp := NewCmdSubmitLegacyProposal()
cmdSubmitProp := NewCmdSubmitProposal()
for _, propCmd := range legacyPropCmds {
flags.AddTxFlagsToCmd(propCmd)
cmdSubmitLegacyProp.AddCommand(propCmd)
cmdSubmitProp.AddCommand(propCmd)
}

govTxCmd.AddCommand(
NewCmdWeightedVote(),
NewCmdSubmitProposal(),
cmdSubmitProp,
NewCmdDraftProposal(),

// Deprecated
cmdSubmitLegacyProp,
)

return govTxCmd
}

// NewCmdSubmitProposal implements submitting a proposal transaction command.
// NOTE: This command has been modified from its original to subsume both
// the "legacy" and the new (as of v0.46) invocation patterns. This modification
// will be dropped once all legacy call sites have been updated to either
// use the new pattern or call the legacy command explicitly.
func NewCmdSubmitProposal() *cobra.Command {
cmd := &cobra.Command{
Use: "submit-proposal <path/to/proposal.json>",
Short: "Submit a proposal along with some messages, metadata and deposit",
Args: cobra.ExactArgs(1),
Use: "submit-proposal [path/to/proposal.json]",
Short: "Submit a proposal along with some messages, metadata and deposit",
Aliases: []string{"submit-legacy-proposal"},
Args: cobra.MaximumNArgs(1),
Long: strings.TrimSpace(
fmt.Sprintf(`Submit a proposal along with some messages, metadata and deposit.
They should be defined in a JSON file.
Expand Down Expand Up @@ -123,8 +125,28 @@ metadata example:
"proposal_forum_url": "",
"vote_option_context": "",
}
Legacy Syntax:
Submit a legacy proposal along with an initial deposit.
Proposal title, description, type and deposit can be given directly or through a proposal JSON file.
Example:
$ %s tx gov submit-legacy-proposal --proposal="path/to/proposal.json" --from mykey
Where proposal.json contains:
{
"title": "Test Proposal",
"description": "My awesome proposal",
"type": "Text",
"deposit": "10test"
}
Which is equivalent to:
$ %s tx gov submit-legacy-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey
`,
version.AppName,
version.AppName, version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
Expand All @@ -133,17 +155,39 @@ metadata example:
return err
}

proposal, msgs, deposit, err := parseSubmitProposal(clientCtx.Codec, args[0])
// try to interpret as a legacy submit-proposal call
proposal, err := parseSubmitLegacyProposalFlags(cmd.Flags())
if err == nil {
amount, err := sdk.ParseCoinsNormalized(proposal.Deposit)
if err != nil {
return err
}

content, ok := v1beta1.ContentFromProposalType(proposal.Title, proposal.Description, proposal.Type)
if !ok {
return fmt.Errorf("failed to create proposal content: unknown proposal type %s", proposal.Type)
}

msg, err := v1beta1.NewMsgSubmitProposal(content, amount, clientCtx.GetFromAddress())
if err != nil {
return fmt.Errorf("invalid message: %w", err)
}

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
}

// otherwise try to interpret as a new (0.46) submit-proposal
err = cobra.ExactArgs(1)(cmd, args)
if err != nil {
return err
}

addr, err := clientCtx.AddressCodec.BytesToString(clientCtx.GetFromAddress())
msgs, metadata, deposit, err := parseSubmitProposal(clientCtx.Codec, args[0])
if err != nil {
return err
}

msg, err := v1.NewMsgSubmitProposal(msgs, deposit, addr, proposal.Metadata, proposal.Title, proposal.Summary, proposal.proposalType)
msg, err := v1.NewMsgSubmitProposal(msgs, deposit, clientCtx.GetFromAddress().String(), metadata)
if err != nil {
return fmt.Errorf("invalid message: %w", err)
}
Expand All @@ -152,37 +196,83 @@ metadata example:
},
}

cmd.Flags().String(FlagTitle, "", "The proposal title")
cmd.Flags().String(FlagDescription, "", "The proposal description")
cmd.Flags().String(FlagProposalType, "", "The proposal Type")
cmd.Flags().String(FlagDeposit, "", "The proposal deposit")
cmd.Flags().String(FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)")
flags.AddTxFlagsToCmd(cmd)

return cmd
}

// NewCmdSubmitLegacyProposal implements submitting a proposal transaction command.
// Deprecated: please use NewCmdSubmitProposal instead.
// Preserved for tests.
func NewCmdSubmitLegacyProposal() *cobra.Command {
return NewCmdSubmitProposal()
}

// NewCmdDeposit implements depositing tokens for an active proposal.
func NewCmdDeposit() *cobra.Command {
cmd := &cobra.Command{
Use: "submit-legacy-proposal",
Aliases: []string{"exec-legacy-content"},
Short: "Submit a legacy proposal along with an initial deposit",
Use: "deposit [proposal-id] [deposit]",
Args: cobra.ExactArgs(2),
Short: "Deposit tokens for an active proposal",
Long: strings.TrimSpace(
fmt.Sprintf(`Submit a legacy proposal along with an initial deposit.
Proposal title, description, type and deposit can be given directly or through a proposal JSON file.
fmt.Sprintf(`Submit a deposit for an active proposal. You can
find the proposal-id by running "%s query gov proposals".
Example:
$ %s tx gov submit-legacy-proposal --proposal="path/to/proposal.json" --from mykey
$ %s tx gov deposit 1 10stake --from mykey
`,
version.AppName, version.AppName,
),
),
RunE: func(cmd *cobra.Command, args []string) error {
clientCtx, err := client.GetClientTxContext(cmd)
if err != nil {
return err
}

Where proposal.json contains:
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("proposal-id %s not a valid uint, please input a valid proposal-id", args[0])
}

{
"title": "Test Proposal",
"description": "My awesome proposal",
"type": "Text",
"deposit": "10test"
// Get depositor address
from := clientCtx.GetFromAddress()

// Get amount of coins
amount, err := sdk.ParseCoinsNormalized(args[1])
if err != nil {
return err
}

msg := v1.NewMsgDeposit(from, proposalID, amount)

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

flags.AddTxFlagsToCmd(cmd)

return cmd
}

Which is equivalent to:
// NewCmdVote implements creating a new vote command.
func NewCmdVote() *cobra.Command {
cmd := &cobra.Command{
Use: "vote [proposal-id] [option]",
Args: cobra.ExactArgs(2),
Short: "Vote for an active proposal, options: yes/no/no_with_veto/abstain",
Long: strings.TrimSpace(
fmt.Sprintf(`Submit a vote for an active proposal. You can
find the proposal-id by running "%s query gov proposals".
$ %s tx gov submit-legacy-proposal --title="Test Proposal" --description="My awesome proposal" --type="Text" --deposit="10test" --from mykey
Example:
$ %s tx gov vote 1 yes --from mykey
`,
version.AppName, version.AppName,
),
Expand All @@ -192,41 +282,34 @@ $ %s tx gov submit-legacy-proposal --title="Test Proposal" --description="My awe
if err != nil {
return err
}
// Get voting address
from := clientCtx.GetFromAddress()

proposal, err := parseSubmitLegacyProposal(cmd.Flags())
// validate that the proposal id is a uint
proposalID, err := strconv.ParseUint(args[0], 10, 64)
if err != nil {
return fmt.Errorf("failed to parse proposal: %w", err)
return fmt.Errorf("proposal-id %s not a valid int, please input a valid proposal-id", args[0])
}

amount, err := sdk.ParseCoinsNormalized(proposal.Deposit)
// Find out which vote option user chose
byteVoteOption, err := v1.VoteOptionFromString(govutils.NormalizeVoteOption(args[1]))
if err != nil {
return err
}

content, ok := v1beta1.ContentFromProposalType(proposal.Title, proposal.Description, proposal.Type)
if !ok {
return fmt.Errorf("failed to create proposal content: unknown proposal type %s", proposal.Type)
}

proposer, err := clientCtx.AddressCodec.BytesToString(clientCtx.GetFromAddress())
metadata, err := cmd.Flags().GetString(flagMetadata)
if err != nil {
return err
}

msg, err := v1beta1.NewMsgSubmitProposal(content, amount, proposer)
if err != nil {
return fmt.Errorf("invalid message: %w", err)
}
// Build vote message and run basic validation
msg := v1.NewMsgVote(from, proposalID, byteVoteOption, metadata)

return tx.GenerateOrBroadcastTxCLI(clientCtx, cmd.Flags(), msg)
},
}

cmd.Flags().String(FlagTitle, "", "The proposal title")
cmd.Flags().String(FlagDescription, "", "The proposal description")
cmd.Flags().String(FlagProposalType, "", "The proposal Type")
cmd.Flags().String(FlagDeposit, "", "The proposal deposit")
cmd.Flags().String(FlagProposal, "", "Proposal file path (if this path is given, other proposal flags are ignored)")
cmd.Flags().String(flagMetadata, "", "Specify metadata of the vote")
flags.AddTxFlagsToCmd(cmd)

return cmd
Expand Down

0 comments on commit 3e9a308

Please sign in to comment.