From 06b85f9ba7a8c7ef180471ab45bd1992b6556eb1 Mon Sep 17 00:00:00 2001 From: Aaron Craelius Date: Thu, 16 Apr 2020 15:33:57 -0400 Subject: [PATCH] Merge PR #5993: Tx Client Migration: x/upgrade --- x/gov/client/rest/rest.go | 11 ++-- x/gov/client/rest/tx.go | 9 +-- x/upgrade/client/cli/tx.go | 126 +++++++++++++++++++++++++++++++++++- x/upgrade/client/rest/tx.go | 95 ++++++++++++++++++++++++++- 4 files changed, 229 insertions(+), 12 deletions(-) diff --git a/x/gov/client/rest/rest.go b/x/gov/client/rest/rest.go index b00b36b3172..0522566dde9 100644 --- a/x/gov/client/rest/rest.go +++ b/x/gov/client/rest/rest.go @@ -3,8 +3,6 @@ package rest import ( "net/http" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/client/tx" "github.com/cosmos/cosmos-sdk/x/gov/types" @@ -33,9 +31,14 @@ type ProposalRESTHandler struct { Handler func(http.ResponseWriter, *http.Request) } -func RegisterHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router, msgSubmitProposalCtr func() types.MsgSubmitProposalI, phs []ProposalRESTHandler) { +func RegisterHandlers( + cliCtx context.CLIContext, + txg tx.Generator, + r *mux.Router, + newMsgFn func() types.MsgSubmitProposalI, + phs []ProposalRESTHandler) { registerQueryRoutes(cliCtx, r) - registerTxHandlers(cliCtx, m, txg, r, msgSubmitProposalCtr, phs) + registerTxHandlers(cliCtx, txg, r, newMsgFn, phs) } // RegisterRoutes - Central function to define routes that get registered by the main application diff --git a/x/gov/client/rest/tx.go b/x/gov/client/rest/tx.go index 58a069b6616..22d6ff92425 100644 --- a/x/gov/client/rest/tx.go +++ b/x/gov/client/rest/tx.go @@ -4,8 +4,6 @@ import ( "fmt" "net/http" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/gorilla/mux" "github.com/cosmos/cosmos-sdk/client/context" @@ -17,19 +15,18 @@ import ( "github.com/cosmos/cosmos-sdk/x/gov/types" ) -func registerTxHandlers(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, r *mux.Router, newMsgFn func() types.MsgSubmitProposalI, phs []ProposalRESTHandler) { +func registerTxHandlers(cliCtx context.CLIContext, txg tx.Generator, r *mux.Router, newMsgFn func() types.MsgSubmitProposalI, phs []ProposalRESTHandler) { propSubRtr := r.PathPrefix("/gov/proposals").Subrouter() for _, ph := range phs { propSubRtr.HandleFunc(fmt.Sprintf("/%s", ph.SubRoute), ph.Handler).Methods("POST") } - cliCtx = cliCtx.WithMarshaler(m) - r.HandleFunc("/gov/proposals", newPostProposalHandlerFn(cliCtx, m, txg, newMsgFn)).Methods("POST") + r.HandleFunc("/gov/proposals", newPostProposalHandlerFn(cliCtx, txg, newMsgFn)).Methods("POST") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/deposits", RestProposalID), newDepositHandlerFn(cliCtx, txg)).Methods("POST") r.HandleFunc(fmt.Sprintf("/gov/proposals/{%s}/votes", RestProposalID), newVoteHandlerFn(cliCtx, txg)).Methods("POST") } -func newPostProposalHandlerFn(cliCtx context.CLIContext, m codec.Marshaler, txg tx.Generator, newMsgFn func() types.MsgSubmitProposalI) http.HandlerFunc { +func newPostProposalHandlerFn(cliCtx context.CLIContext, txg tx.Generator, newMsgFn func() types.MsgSubmitProposalI) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req PostProposalReq if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { diff --git a/x/upgrade/client/cli/tx.go b/x/upgrade/client/cli/tx.go index 6e325aa9c04..27df5c3ec3c 100644 --- a/x/upgrade/client/cli/tx.go +++ b/x/upgrade/client/cli/tx.go @@ -5,6 +5,9 @@ import ( "fmt" "time" + "github.com/cosmos/cosmos-sdk/client/tx" + gov "github.com/cosmos/cosmos-sdk/x/gov/types" + authclient "github.com/cosmos/cosmos-sdk/x/auth/client" "github.com/cosmos/cosmos-sdk/x/gov/client/cli" @@ -14,7 +17,6 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" - "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) @@ -27,6 +29,128 @@ const ( FlagUpgradeInfo = "info" ) +// NewCmdSubmitUpgradeProposal implements a command handler for submitting a software upgrade proposal transaction. +func NewCmdSubmitUpgradeProposal( + m codec.Marshaler, txg tx.Generator, ar tx.AccountRetriever, + newMsgFn func() gov.MsgSubmitProposalI, +) *cobra.Command { + + cmd := &cobra.Command{ + Use: "software-upgrade [name] (--upgrade-height [height] | --upgrade-time [time]) (--upgrade-info [info]) [flags]", + Args: cobra.ExactArgs(1), + Short: "Submit a software upgrade proposal", + Long: "Submit a software upgrade along with an initial deposit.\n" + + "Please specify a unique name and height OR time for the upgrade to take effect.\n" + + "You may include info to reference a binary download link, in a format compatible with: https://github.com/regen-network/cosmosd", + RunE: func(cmd *cobra.Command, args []string) error { + name := args[0] + content, err := parseArgsToContent(cmd, name) + if err != nil { + return err + } + + inBuf := bufio.NewReader(cmd.InOrStdin()) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + from := cliCtx.GetFromAddress() + + depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return err + } + deposit, err := sdk.ParseCoins(depositStr) + if err != nil { + return err + } + + msg := newMsgFn() + err = msg.SetContent(content) + if err != nil { + return err + } + msg.SetInitialDeposit(deposit) + msg.SetProposer(from) + + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") + cmd.Flags().Int64(FlagUpgradeHeight, 0, "The height at which the upgrade must happen (not to be used together with --upgrade-time)") + cmd.Flags().String(FlagUpgradeTime, "", fmt.Sprintf("The time at which the upgrade must happen (ex. %s) (not to be used together with --upgrade-height)", TimeFormat)) + cmd.Flags().String(FlagUpgradeInfo, "", "Optional info for the planned upgrade such as commit hash, etc.") + + return cmd +} + +// NewCmdSubmitCancelUpgradeProposal implements a command handler for submitting a software upgrade cancel proposal transaction. +func NewCmdSubmitCancelUpgradeProposal( + m codec.Marshaler, + txg tx.Generator, + ar tx.AccountRetriever, + newMsgFn func() gov.MsgSubmitProposalI) *cobra.Command { + cmd := &cobra.Command{ + Use: "cancel-software-upgrade [flags]", + Args: cobra.ExactArgs(0), + Short: "Submit a software upgrade proposal", + Long: "Cancel a software upgrade along with an initial deposit.", + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + cliCtx := context.NewCLIContextWithInput(inBuf).WithMarshaler(m) + txf := tx.NewFactoryFromCLI(inBuf).WithTxGenerator(txg).WithAccountRetriever(ar) + from := cliCtx.GetFromAddress() + + depositStr, err := cmd.Flags().GetString(cli.FlagDeposit) + if err != nil { + return err + } + + deposit, err := sdk.ParseCoins(depositStr) + if err != nil { + return err + } + + title, err := cmd.Flags().GetString(cli.FlagTitle) + if err != nil { + return err + } + + description, err := cmd.Flags().GetString(cli.FlagDescription) + if err != nil { + return err + } + + content := types.NewCancelSoftwareUpgradeProposal(title, description) + + msg := newMsgFn() + err = msg.SetContent(content) + if err != nil { + return err + } + msg.SetInitialDeposit(deposit) + msg.SetProposer(from) + + if err = msg.ValidateBasic(); err != nil { + return err + } + + return tx.GenerateOrBroadcastTx(cliCtx, txf, msg) + }, + } + + cmd.Flags().String(cli.FlagTitle, "", "title of proposal") + cmd.Flags().String(cli.FlagDescription, "", "description of proposal") + cmd.Flags().String(cli.FlagDeposit, "", "deposit of proposal") + + return cmd +} + func parseArgsToContent(cmd *cobra.Command, name string) (gov.Content, error) { title, err := cmd.Flags().GetString(cli.FlagTitle) if err != nil { diff --git a/x/upgrade/client/rest/tx.go b/x/upgrade/client/rest/tx.go index 6b40ae20289..f04e4d07ab7 100644 --- a/x/upgrade/client/rest/tx.go +++ b/x/upgrade/client/rest/tx.go @@ -4,6 +4,8 @@ import ( "net/http" "time" + "github.com/cosmos/cosmos-sdk/client/tx" + "github.com/gorilla/mux" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" @@ -12,10 +14,20 @@ import ( "github.com/cosmos/cosmos-sdk/client/context" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/types/rest" - "github.com/cosmos/cosmos-sdk/x/gov" + gov "github.com/cosmos/cosmos-sdk/x/gov/types" "github.com/cosmos/cosmos-sdk/x/upgrade/types" ) +// nolint +func newRegisterTxRoutes( + cliCtx context.CLIContext, + txg tx.Generator, + newMsgFn func() gov.MsgSubmitProposalI, + r *mux.Router) { + r.HandleFunc("/upgrade/plan", newPostPlanHandler(cliCtx, txg, newMsgFn)).Methods("POST") + r.HandleFunc("/upgrade/cancel", newCancelPlanHandler(cliCtx, txg, newMsgFn)).Methods("POST") +} + func registerTxRoutes(cliCtx context.CLIContext, r *mux.Router) { r.HandleFunc("/upgrade/plan", postPlanHandler(cliCtx)).Methods("POST") r.HandleFunc("/upgrade/cancel", cancelPlanHandler(cliCtx)).Methods("POST") @@ -48,6 +60,87 @@ func ProposalRESTHandler(cliCtx context.CLIContext) govrest.ProposalRESTHandler } } +// nolint +func newPostPlanHandler(cliCtx context.CLIContext, txg tx.Generator, newMsgFn func() gov.MsgSubmitProposalI) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req PlanRequest + + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + var t time.Time + if req.UpgradeTime != "" { + t, err = time.Parse(time.RFC3339, req.UpgradeTime) + if rest.CheckBadRequestError(w, err) { + return + } + } + + plan := types.Plan{Name: req.UpgradeName, Time: t, Height: req.UpgradeHeight, Info: req.UpgradeInfo} + content := types.NewSoftwareUpgradeProposal(req.Title, req.Description, plan) + + msg := newMsgFn() + err = msg.SetContent(content) + if rest.CheckBadRequestError(w, err) { + return + } + msg.SetInitialDeposit(req.Deposit) + msg.SetProposer(fromAddr) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + } +} + +// nolint +func newCancelPlanHandler(cliCtx context.CLIContext, txg tx.Generator, newMsgFn func() gov.MsgSubmitProposalI) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + var req CancelRequest + + if !rest.ReadRESTReq(w, r, cliCtx.Codec, &req) { + return + } + + req.BaseReq = req.BaseReq.Sanitize() + if !req.BaseReq.ValidateBasic(w) { + return + } + + fromAddr, err := sdk.AccAddressFromBech32(req.BaseReq.From) + if rest.CheckBadRequestError(w, err) { + return + } + + content := types.NewCancelSoftwareUpgradeProposal(req.Title, req.Description) + + msg := newMsgFn() + err = msg.SetContent(content) + if rest.CheckBadRequestError(w, err) { + return + } + msg.SetInitialDeposit(req.Deposit) + msg.SetProposer(fromAddr) + if rest.CheckBadRequestError(w, msg.ValidateBasic()) { + return + } + + tx.WriteGeneratedTxResponse(cliCtx, w, txg, req.BaseReq, msg) + } +} + func postPlanHandler(cliCtx context.CLIContext) http.HandlerFunc { return func(w http.ResponseWriter, r *http.Request) { var req PlanRequest