Merge PR #2874: gaiad gentx subcommands refactoring

* gaiad gentx subcommands refactoring

- Replace STDIN/STDOUT redirection in `gaiad gentx` with subcommands
  command line options to redirect streams to file since viper does
  not handle redirection well.
- Use `BuildCreateValidatorMsg` to build a `MsgCreateValidator` rather
  than redirecting to `gaiacli tx stake create-validator`.
- `PrintUnsignedStdTx` now takes an `io.Writer` object.
- Mark `--pubkey`, `--amount` and `--moniker` as required flags
  instead of validating them manually.
- Use stake.NewDescription() to make a new Description - ref #2835

* Refresh PENDING.md
This commit is contained in:
Alessio Treglia 2018-11-21 23:44:13 +00:00 committed by Christopher Goes
parent 1ea0e4c457
commit 3e68e44063
9 changed files with 128 additions and 94 deletions

View File

@ -10,6 +10,7 @@ BREAKING CHANGES
* [cli] [\#2786](https://github.com/cosmos/cosmos-sdk/pull/2786) Fix redelegation command flow
* [cli] [\#2829](https://github.com/cosmos/cosmos-sdk/pull/2829) add-genesis-account command now validates state when adding accounts
* [cli] [\#2804](https://github.com/cosmos/cosmos-sdk/issues/2804) Check whether key exists before passing it on to `tx create-validator`.
* [cli] [\#2874](https://github.com/cosmos/cosmos-sdk/pull/2874) `gaiacli tx sign` takes an optional `--output-document` flag to support output redirection.
* Gaia

View File

@ -3,6 +3,7 @@ package utils
import (
"bytes"
"fmt"
"io"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
@ -88,7 +89,7 @@ func CalculateGas(queryFunc func(string, common.HexBytes) ([]byte, error), cdc *
// PrintUnsignedStdTx builds an unsigned StdTx and prints it to os.Stdout.
// Don't perform online validation or lookups if offline is true.
func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, offline bool) (err error) {
func PrintUnsignedStdTx(w io.Writer, txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msgs []sdk.Msg, offline bool) (err error) {
var stdTx auth.StdTx
if offline {
stdTx, err = buildUnsignedStdTxOffline(txBldr, cliCtx, msgs)
@ -100,7 +101,7 @@ func PrintUnsignedStdTx(txBldr authtxb.TxBuilder, cliCtx context.CLIContext, msg
}
json, err := txBldr.Codec.MarshalJSON(stdTx)
if err == nil {
fmt.Printf("%s\n", json)
fmt.Fprintf(w, "%s\n", json)
}
return
}

View File

@ -6,17 +6,21 @@ import (
"os"
"path/filepath"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/utils"
"github.com/cosmos/cosmos-sdk/cmd/gaia/app"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/server"
sdk "github.com/cosmos/cosmos-sdk/types"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/stake/client/cli"
stakeTypes "github.com/cosmos/cosmos-sdk/x/stake/types"
"github.com/spf13/cobra"
"github.com/spf13/viper"
cfg "github.com/tendermint/tendermint/config"
"github.com/tendermint/tendermint/crypto"
tmcli "github.com/tendermint/tendermint/libs/cli"
@ -80,7 +84,13 @@ following delegation and commission default parameters:
}
// Run gaiad tx create-validator
prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey)
createValidatorCmd := cli.GetCmdCreateValidator(cdc)
cliCtx, txBldr, msg, err := cli.BuildCreateValidatorMsg(
context.NewCLIContext().WithCodec(cdc),
authtxb.NewTxBuilderFromCLI().WithCodec(cdc),
)
if err != nil {
return err
}
w, err := ioutil.TempFile("", "gentx")
if err != nil {
@ -88,18 +98,19 @@ following delegation and commission default parameters:
}
unsignedGenTxFilename := w.Name()
defer os.Remove(unsignedGenTxFilename)
os.Stdout = w
if err = createValidatorCmd.RunE(nil, args); err != nil {
if err := utils.PrintUnsignedStdTx(w, txBldr, cliCtx, []sdk.Msg{msg}, true); err != nil {
return err
}
w.Close()
prepareFlagsForTxSign()
signCmd := authcmd.GetSignCommand(cdc)
if w, err = prepareOutputFile(config.RootDir, nodeID); err != nil {
outputDocument, err := makeOutputFilepath(config.RootDir, nodeID)
if err != nil {
return err
}
os.Stdout = w
viper.Set("output-document", outputDocument)
return signCmd.RunE(nil, []string{unsignedGenTxFilename})
},
}
@ -145,11 +156,10 @@ func prepareFlagsForTxSign() {
viper.Set("offline", true)
}
func prepareOutputFile(rootDir, nodeID string) (w *os.File, err error) {
func makeOutputFilepath(rootDir, nodeID string) (string, error) {
writePath := filepath.Join(rootDir, "config", "gentx")
if err = common.EnsureDir(writePath, 0700); err != nil {
return
if err := common.EnsureDir(writePath, 0700); err != nil {
return "", err
}
filename := filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID))
return os.Create(filename)
return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil
}

View File

@ -3,9 +3,7 @@ package cli
import (
"fmt"
"io/ioutil"
"github.com/pkg/errors"
"github.com/spf13/viper"
"os"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
@ -13,7 +11,9 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/x/auth"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/pkg/errors"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"github.com/tendermint/go-amino"
)
@ -22,6 +22,7 @@ const (
flagValidateSigs = "validate-signatures"
flagOffline = "offline"
flagSigOnly = "signature-only"
flagOutfile = "output-document"
)
// GetSignCommand returns the sign command
@ -52,6 +53,8 @@ recommended to set such parameters manually.`,
cmd.Flags().Bool(flagValidateSigs, false, "Print the addresses that must sign the transaction, "+
"those who have already signed it, and make sure that signatures are in the correct order.")
cmd.Flags().Bool(flagOffline, false, "Offline mode. Do not query local cache.")
cmd.Flags().String(flagOutfile, "",
"The document will be written to the given file instead of STDOUT")
// Add the flags here and return the command
return client.PostCommands(cmd)[0]
@ -107,7 +110,20 @@ func makeSignCmd(cdc *amino.Codec) func(cmd *cobra.Command, args []string) error
if err != nil {
return err
}
fmt.Printf("%s\n", json)
if viper.GetString(flagOutfile) == "" {
fmt.Printf("%s\n", json)
return
}
fp, err := os.OpenFile(
viper.GetString(flagOutfile), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644,
)
if err != nil {
return err
}
defer fp.Close()
fmt.Fprintf(fp, "%s\n", json)
return
}
}

View File

@ -8,6 +8,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
bankClient "github.com/cosmos/cosmos-sdk/x/bank/client"
"os"
"github.com/pkg/errors"
"github.com/spf13/cobra"
@ -66,7 +67,7 @@ func SendTxCmd(cdc *codec.Codec) *cobra.Command {
// build and sign the transaction, then broadcast to Tendermint
msg := bankClient.CreateMsg(from, to, coins)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})

View File

@ -2,6 +2,7 @@ package cli
import (
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/client/context"
"github.com/cosmos/cosmos-sdk/client/utils"
@ -103,7 +104,7 @@ $ gaiacli gov submit-proposal --title="Test Proposal" --description="My awesome
}
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
// Build and sign the transaction, then broadcast to Tendermint
@ -183,7 +184,7 @@ func GetCmdDeposit(cdc *codec.Codec) *cobra.Command {
}
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
// Build and sign the transaction, then broadcast to a Tendermint
@ -229,7 +230,7 @@ func GetCmdVote(cdc *codec.Codec) *cobra.Command {
}
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
fmt.Printf("Vote[Voter:%s,ProposalID:%d,Option:%s]",

View File

@ -2,6 +2,7 @@ package cli
import (
"encoding/hex"
"os"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
@ -41,7 +42,7 @@ func IBCTransferCmd(cdc *codec.Codec) *cobra.Command {
return err
}
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})

View File

@ -7,6 +7,7 @@ import (
sdk "github.com/cosmos/cosmos-sdk/types"
authtxb "github.com/cosmos/cosmos-sdk/x/auth/client/txbuilder"
"github.com/cosmos/cosmos-sdk/x/slashing"
"os"
"github.com/spf13/cobra"
)
@ -30,7 +31,7 @@ func GetCmdUnjail(cdc *codec.Codec) *cobra.Command {
msg := slashing.NewMsgUnjail(sdk.ValAddress(valAddr))
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
},

View File

@ -2,6 +2,7 @@ package cli
import (
"fmt"
"os"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/context"
@ -26,76 +27,13 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
WithCodec(cdc).
WithAccountDecoder(cdc)
amounstStr := viper.GetString(FlagAmount)
if amounstStr == "" {
return fmt.Errorf("Must specify amount to stake using --amount")
}
amount, err := sdk.ParseCoin(amounstStr)
cliCtx, txBldr, msg, err := BuildCreateValidatorMsg(cliCtx, txBldr)
if err != nil {
return err
}
valAddr, err := cliCtx.GetFromAddress()
if err != nil {
return err
}
pkStr := viper.GetString(FlagPubKey)
if len(pkStr) == 0 {
return fmt.Errorf("must use --pubkey flag")
}
pk, err := sdk.GetConsPubKeyBech32(pkStr)
if err != nil {
return err
}
if viper.GetString(FlagMoniker) == "" {
return fmt.Errorf("please enter a moniker for the validator using --moniker")
}
description := stake.Description{
Moniker: viper.GetString(FlagMoniker),
Identity: viper.GetString(FlagIdentity),
Website: viper.GetString(FlagWebsite),
Details: viper.GetString(FlagDetails),
}
// get the initial validator commission parameters
rateStr := viper.GetString(FlagCommissionRate)
maxRateStr := viper.GetString(FlagCommissionMaxRate)
maxChangeRateStr := viper.GetString(FlagCommissionMaxChangeRate)
commissionMsg, err := buildCommissionMsg(rateStr, maxRateStr, maxChangeRateStr)
if err != nil {
return err
}
var msg sdk.Msg
if viper.GetString(FlagAddressDelegator) != "" {
delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
if err != nil {
return err
}
msg = stake.NewMsgCreateValidatorOnBehalfOf(
delAddr, sdk.ValAddress(valAddr), pk, amount, description, commissionMsg,
)
} else {
msg = stake.NewMsgCreateValidator(
sdk.ValAddress(valAddr), pk, amount, description, commissionMsg,
)
}
if viper.GetBool(FlagGenesisFormat) {
ip := viper.GetString(FlagIP)
nodeID := viper.GetString(FlagNodeID)
if nodeID != "" && ip != "" {
txBldr = txBldr.WithMemo(fmt.Sprintf("%s@%s:26656", nodeID, ip))
}
}
if viper.GetBool(FlagGenesisFormat) || cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, true)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, true)
}
// build and sign the transaction, then broadcast to Tendermint
@ -112,6 +50,9 @@ func GetCmdCreateValidator(cdc *codec.Codec) *cobra.Command {
cmd.Flags().String(FlagIP, "", fmt.Sprintf("Node's public IP. It takes effect only when used in combination with --%s", FlagGenesisFormat))
cmd.Flags().String(FlagNodeID, "", "Node's ID")
cmd.MarkFlagRequired(client.FlagFrom)
cmd.MarkFlagRequired(FlagAmount)
cmd.MarkFlagRequired(FlagPubKey)
cmd.MarkFlagRequired(FlagMoniker)
return cmd
}
@ -154,7 +95,7 @@ func GetCmdEditValidator(cdc *codec.Codec) *cobra.Command {
msg := stake.NewMsgEditValidator(sdk.ValAddress(valAddr), description, newRate)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
// build and sign the transaction, then broadcast to Tendermint
@ -197,7 +138,7 @@ func GetCmdDelegate(cdc *codec.Codec) *cobra.Command {
msg := stake.NewMsgDelegate(delAddr, valAddr, amount)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
// build and sign the transaction, then broadcast to Tendermint
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
@ -252,7 +193,7 @@ func GetCmdRedelegate(storeName string, cdc *codec.Codec) *cobra.Command {
msg := stake.NewMsgBeginRedelegate(delAddr, valSrcAddr, valDstAddr, sharesAmount)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
// build and sign the transaction, then broadcast to Tendermint
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
@ -300,7 +241,7 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
msg := stake.NewMsgBeginUnbonding(delAddr, valAddr, sharesAmount)
if cliCtx.GenerateOnly {
return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}, false)
return utils.PrintUnsignedStdTx(os.Stdout, txBldr, cliCtx, []sdk.Msg{msg}, false)
}
// build and sign the transaction, then broadcast to Tendermint
return utils.CompleteAndBroadcastTxCli(txBldr, cliCtx, []sdk.Msg{msg})
@ -312,3 +253,64 @@ func GetCmdUnbond(storeName string, cdc *codec.Codec) *cobra.Command {
return cmd
}
// BuildCreateValidatorMsg makes a new MsgCreateValidator.
func BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr authtxb.TxBuilder) (context.CLIContext, authtxb.TxBuilder, sdk.Msg, error) {
amounstStr := viper.GetString(FlagAmount)
amount, err := sdk.ParseCoin(amounstStr)
if err != nil {
return cliCtx, txBldr, nil, err
}
valAddr, err := cliCtx.GetFromAddress()
if err != nil {
return cliCtx, txBldr, nil, err
}
pkStr := viper.GetString(FlagPubKey)
pk, err := sdk.GetConsPubKeyBech32(pkStr)
if err != nil {
return cliCtx, txBldr, nil, err
}
description := stake.NewDescription(
viper.GetString(FlagMoniker),
viper.GetString(FlagIdentity),
viper.GetString(FlagWebsite),
viper.GetString(FlagDetails),
)
// get the initial validator commission parameters
rateStr := viper.GetString(FlagCommissionRate)
maxRateStr := viper.GetString(FlagCommissionMaxRate)
maxChangeRateStr := viper.GetString(FlagCommissionMaxChangeRate)
commissionMsg, err := buildCommissionMsg(rateStr, maxRateStr, maxChangeRateStr)
if err != nil {
return cliCtx, txBldr, nil, err
}
var msg sdk.Msg
if viper.GetString(FlagAddressDelegator) != "" {
delAddr, err := sdk.AccAddressFromBech32(viper.GetString(FlagAddressDelegator))
if err != nil {
return cliCtx, txBldr, nil, err
}
msg = stake.NewMsgCreateValidatorOnBehalfOf(
delAddr, sdk.ValAddress(valAddr), pk, amount, description, commissionMsg,
)
} else {
msg = stake.NewMsgCreateValidator(
sdk.ValAddress(valAddr), pk, amount, description, commissionMsg,
)
}
if viper.GetBool(FlagGenesisFormat) {
ip := viper.GetString(FlagIP)
nodeID := viper.GetString(FlagNodeID)
if nodeID != "" && ip != "" {
txBldr = txBldr.WithMemo(fmt.Sprintf("%s@%s:26656", nodeID, ip))
}
}
return cliCtx, txBldr, msg, nil
}