2019-05-16 08:25:32 -07:00
|
|
|
package cli
|
2019-02-08 13:45:41 -08:00
|
|
|
|
2018-10-19 11:00:27 -07:00
|
|
|
import (
|
2019-11-14 06:17:21 -08:00
|
|
|
"bufio"
|
2018-11-26 03:50:33 -08:00
|
|
|
"bytes"
|
2019-05-16 08:25:32 -07:00
|
|
|
"encoding/json"
|
2018-10-19 11:00:27 -07:00
|
|
|
"fmt"
|
2018-11-26 03:50:33 -08:00
|
|
|
"io"
|
2018-11-19 09:02:34 -08:00
|
|
|
"io/ioutil"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
|
2019-08-30 06:59:41 -07:00
|
|
|
"github.com/pkg/errors"
|
2018-11-21 15:44:13 -08:00
|
|
|
"github.com/spf13/cobra"
|
2020-01-16 13:46:51 -08:00
|
|
|
tmos "github.com/tendermint/tendermint/libs/os"
|
2019-04-08 10:54:45 -07:00
|
|
|
tmtypes "github.com/tendermint/tendermint/types"
|
2018-12-10 06:27:25 -08:00
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/client"
|
2019-12-11 01:45:26 -08:00
|
|
|
"github.com/cosmos/cosmos-sdk/client/flags"
|
2018-10-19 11:00:27 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/codec"
|
2020-03-25 08:20:36 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/crypto/keyring"
|
2018-10-19 11:00:27 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/server"
|
|
|
|
sdk "github.com/cosmos/cosmos-sdk/types"
|
2019-06-05 16:26:17 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/types/module"
|
2020-01-24 08:40:56 -08:00
|
|
|
authclient "github.com/cosmos/cosmos-sdk/x/auth/client"
|
2020-06-17 11:42:27 -07:00
|
|
|
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
|
2019-05-16 08:25:32 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/genutil"
|
2019-07-24 14:37:03 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/genutil/types"
|
2020-07-06 14:48:54 -07:00
|
|
|
"github.com/cosmos/cosmos-sdk/x/staking/client/cli"
|
2018-10-19 11:00:27 -07:00
|
|
|
)
|
|
|
|
|
2019-05-18 01:42:24 -07:00
|
|
|
// GenTxCmd builds the application's gentx command.
|
2018-10-19 11:00:27 -07:00
|
|
|
// nolint: errcheck
|
2020-07-06 14:48:54 -07:00
|
|
|
func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager,
|
2020-01-30 13:31:16 -08:00
|
|
|
genBalIterator types.GenesisBalancesIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command {
|
2019-05-28 01:44:04 -07:00
|
|
|
ipDefault, _ := server.ExternalIP()
|
2020-07-06 14:48:54 -07:00
|
|
|
fsCreateValidator, defaultsDesc := cli.CreateValidatorMsgFlagSet(ipDefault)
|
2019-05-28 01:44:04 -07:00
|
|
|
|
2018-10-19 11:00:27 -07:00
|
|
|
cmd := &cobra.Command{
|
|
|
|
Use: "gentx",
|
|
|
|
Short: "Generate a genesis tx carrying a self delegation",
|
2019-03-27 11:38:35 -07:00
|
|
|
Args: cobra.NoArgs,
|
2019-05-18 01:42:24 -07:00
|
|
|
Long: fmt.Sprintf(`This command is an alias of the 'tx create-validator' command'.
|
2018-10-19 11:00:27 -07:00
|
|
|
|
2019-05-28 01:44:04 -07:00
|
|
|
It creates a genesis transaction to create a validator.
|
|
|
|
The following default parameters are included:
|
|
|
|
%s`, defaultsDesc),
|
2018-10-19 11:00:27 -07:00
|
|
|
|
|
|
|
RunE: func(cmd *cobra.Command, args []string) error {
|
2020-07-06 14:48:54 -07:00
|
|
|
home, _ := cmd.Flags().GetString(flags.FlagHome)
|
2018-10-19 11:00:27 -07:00
|
|
|
|
|
|
|
config := ctx.Config
|
2020-07-06 14:48:54 -07:00
|
|
|
config.SetRoot(home)
|
2019-05-16 08:25:32 -07:00
|
|
|
nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(ctx.Config)
|
2018-10-19 11:00:27 -07:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to initialize node validator files")
|
2018-10-19 11:00:27 -07:00
|
|
|
}
|
2019-02-01 17:03:57 -08:00
|
|
|
|
2019-02-05 20:57:36 -08:00
|
|
|
// Read --nodeID, if empty take it from priv_validator.json
|
2020-07-06 14:48:54 -07:00
|
|
|
nodeIDString, _ := cmd.Flags().GetString(cli.FlagNodeID)
|
|
|
|
|
|
|
|
if nodeIDString != "" {
|
2019-02-05 20:57:36 -08:00
|
|
|
nodeID = nodeIDString
|
|
|
|
}
|
2019-05-28 01:44:04 -07:00
|
|
|
// Read --pubkey, if empty take it from priv_validator.json
|
2020-07-06 14:48:54 -07:00
|
|
|
valPubKeyString, _ := cmd.Flags().GetString(cli.FlagPubKey)
|
|
|
|
|
|
|
|
if valPubKeyString != "" {
|
2020-01-09 06:04:28 -08:00
|
|
|
valPubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, valPubKeyString)
|
2019-05-28 01:44:04 -07:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to get consensus node public key")
|
2019-05-28 01:44:04 -07:00
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
}
|
2018-12-04 01:57:44 -08:00
|
|
|
|
2019-04-08 10:54:45 -07:00
|
|
|
genDoc, err := tmtypes.GenesisDocFromFile(config.GenesisFile())
|
2018-11-04 20:26:46 -08:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrapf(err, "failed to read genesis doc file %s", config.GenesisFile())
|
2018-11-04 20:26:46 -08:00
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
var genesisState map[string]json.RawMessage
|
2018-12-04 01:57:44 -08:00
|
|
|
if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to unmarshal genesis state")
|
2018-12-04 01:57:44 -08:00
|
|
|
}
|
|
|
|
|
2020-02-18 04:50:13 -08:00
|
|
|
if err = mbm.ValidateGenesis(cdc, genesisState); err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to validate genesis state")
|
2019-03-20 11:02:11 -07:00
|
|
|
}
|
|
|
|
|
2020-07-06 14:48:54 -07:00
|
|
|
keyringBackend, _ := cmd.Flags().GetString(flags.FlagKeyringBackend)
|
|
|
|
|
|
|
|
clientHome, _ := cmd.Flags().GetString(flagClientHome)
|
|
|
|
|
2019-11-14 06:17:21 -08:00
|
|
|
inBuf := bufio.NewReader(cmd.InOrStdin())
|
2020-07-06 14:48:54 -07:00
|
|
|
kb, err := keyring.New(sdk.KeyringServiceName(), keyringBackend, clientHome, inBuf)
|
2018-11-15 21:01:34 -08:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to initialize keybase")
|
2018-11-15 21:01:34 -08:00
|
|
|
}
|
2018-11-26 03:50:33 -08:00
|
|
|
|
2020-07-06 14:48:54 -07:00
|
|
|
name, _ := cmd.Flags().GetString(flags.FlagName)
|
|
|
|
|
2020-04-08 02:38:28 -07:00
|
|
|
key, err := kb.Key(name)
|
2018-12-04 01:57:44 -08:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to read from keybase")
|
2018-11-15 21:01:34 -08:00
|
|
|
}
|
|
|
|
|
2018-12-04 01:57:44 -08:00
|
|
|
// Set flags for creating gentx
|
2020-07-06 14:48:54 -07:00
|
|
|
createValCfg, err := cli.PrepareConfigForTxCreateValidator(config, cmd.Flags(), nodeID, genDoc.ChainID, valPubKey)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error creating configuration to create validator msg")
|
|
|
|
}
|
2018-12-04 01:57:44 -08:00
|
|
|
|
|
|
|
// Fetch the amount of coins staked
|
2020-07-06 14:48:54 -07:00
|
|
|
amount, _ := cmd.Flags().GetString(cli.FlagAmount)
|
|
|
|
|
2018-12-04 01:57:44 -08:00
|
|
|
coins, err := sdk.ParseCoins(amount)
|
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to parse coins")
|
2018-12-04 01:57:44 -08:00
|
|
|
}
|
|
|
|
|
2020-01-30 13:31:16 -08:00
|
|
|
err = genutil.ValidateAccountInGenesis(genesisState, genBalIterator, key.GetAddress(), coins, cdc)
|
2018-12-04 01:57:44 -08:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to validate account in genesis")
|
2018-12-04 01:57:44 -08:00
|
|
|
}
|
|
|
|
|
2020-07-06 14:48:54 -07:00
|
|
|
txBldr, err := authtypes.NewTxBuilderFromFlags(inBuf, cmd.Flags(), clientHome)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error creating tx builder")
|
|
|
|
}
|
|
|
|
txBldr = txBldr.WithTxEncoder(authclient.GetTxEncoder(cdc))
|
|
|
|
|
|
|
|
from, _ := cmd.Flags().GetString(flags.FlagFrom)
|
|
|
|
fromAddress, _, err := client.GetFromFields(txBldr.Keybase(), from, false)
|
|
|
|
if err != nil {
|
|
|
|
return errors.Wrap(err, "error getting from address")
|
|
|
|
}
|
2019-03-25 08:27:24 -07:00
|
|
|
|
2020-07-06 14:48:54 -07:00
|
|
|
clientCtx := client.Context{}.
|
|
|
|
WithInput(inBuf).WithCodec(cdc).WithJSONMarshaler(cdc).
|
|
|
|
WithFromAddress(fromAddress)
|
2019-03-25 08:27:24 -07:00
|
|
|
|
|
|
|
// create a 'create-validator' message
|
2020-07-06 14:48:54 -07:00
|
|
|
txBldr, msg, err := cli.BuildCreateValidatorMsg(clientCtx, createValCfg, txBldr, true)
|
2018-11-21 15:44:13 -08:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to build create-validator message")
|
2018-11-21 15:44:13 -08:00
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
|
2020-03-25 08:20:36 -07:00
|
|
|
if key.GetType() == keyring.TypeOffline || key.GetType() == keyring.TypeMulti {
|
2020-04-22 13:20:16 -07:00
|
|
|
cmd.PrintErrln("Offline key passed in. Use `tx sign` command to sign.")
|
2020-06-01 05:46:03 -07:00
|
|
|
return authclient.PrintUnsignedStdTx(txBldr, clientCtx, []sdk.Msg{msg})
|
2019-02-27 10:31:11 -08:00
|
|
|
}
|
|
|
|
|
2018-11-26 03:50:33 -08:00
|
|
|
// write the unsigned transaction to the buffer
|
|
|
|
w := bytes.NewBuffer([]byte{})
|
2020-06-01 05:46:03 -07:00
|
|
|
clientCtx = clientCtx.WithOutput(w)
|
2019-02-27 10:31:11 -08:00
|
|
|
|
2020-06-01 05:46:03 -07:00
|
|
|
if err = authclient.PrintUnsignedStdTx(txBldr, clientCtx, []sdk.Msg{msg}); err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to print unsigned std tx")
|
2018-10-19 11:00:27 -07:00
|
|
|
}
|
2018-11-21 15:44:13 -08:00
|
|
|
|
2018-11-26 03:50:33 -08:00
|
|
|
// read the transaction
|
|
|
|
stdTx, err := readUnsignedGenTxFile(cdc, w)
|
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to read unsigned gen tx file")
|
2018-10-19 11:00:27 -07:00
|
|
|
}
|
|
|
|
|
2018-11-26 03:50:33 -08:00
|
|
|
// sign the transaction and write it to the output file
|
2020-06-01 05:46:03 -07:00
|
|
|
signedTx, err := authclient.SignStdTx(txBldr, clientCtx, name, stdTx, false, true)
|
2018-11-26 03:50:33 -08:00
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to sign std tx")
|
2018-11-26 03:50:33 -08:00
|
|
|
}
|
2018-11-21 15:44:13 -08:00
|
|
|
|
2018-12-04 01:57:44 -08:00
|
|
|
// Fetch output file name
|
2020-07-06 14:48:54 -07:00
|
|
|
outputDocument, _ := cmd.Flags().GetString(flags.FlagOutputDocument)
|
|
|
|
|
2018-12-06 03:03:58 -08:00
|
|
|
if outputDocument == "" {
|
|
|
|
outputDocument, err = makeOutputFilepath(config.RootDir, nodeID)
|
|
|
|
if err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to create output file path")
|
2018-12-06 03:03:58 -08:00
|
|
|
}
|
2018-10-19 11:00:27 -07:00
|
|
|
}
|
2018-12-04 01:57:44 -08:00
|
|
|
|
2018-11-26 03:50:33 -08:00
|
|
|
if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil {
|
2019-08-30 06:59:41 -07:00
|
|
|
return errors.Wrap(err, "failed to write signed gen tx")
|
2018-11-26 03:50:33 -08:00
|
|
|
}
|
2018-12-04 01:57:44 -08:00
|
|
|
|
2020-04-22 13:20:16 -07:00
|
|
|
cmd.PrintErrf("Genesis transaction written to %q\n", outputDocument)
|
2018-11-26 03:50:33 -08:00
|
|
|
return nil
|
2019-02-27 10:31:11 -08:00
|
|
|
|
2018-10-19 11:00:27 -07:00
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2019-12-23 08:05:47 -08:00
|
|
|
cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory")
|
2019-05-16 08:25:32 -07:00
|
|
|
cmd.Flags().String(flagClientHome, defaultCLIHome, "client's home directory")
|
2019-12-23 08:05:47 -08:00
|
|
|
cmd.Flags().String(flags.FlagName, "", "name of private key with which to sign the gentx")
|
|
|
|
cmd.Flags().String(flags.FlagOutputDocument, "",
|
2018-12-06 03:03:58 -08:00
|
|
|
"write the genesis transaction JSON document to the given file instead of the default location")
|
2019-05-28 01:44:04 -07:00
|
|
|
cmd.Flags().AddFlagSet(fsCreateValidator)
|
2020-07-06 14:48:54 -07:00
|
|
|
cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
|
|
|
|
|
|
|
|
flags.PostCommands(cmd)
|
2019-05-28 01:44:04 -07:00
|
|
|
|
2019-12-23 08:05:47 -08:00
|
|
|
cmd.MarkFlagRequired(flags.FlagName)
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2018-10-19 11:00:27 -07:00
|
|
|
return cmd
|
|
|
|
}
|
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
func makeOutputFilepath(rootDir, nodeID string) (string, error) {
|
|
|
|
writePath := filepath.Join(rootDir, "config", "gentx")
|
2020-01-16 13:46:51 -08:00
|
|
|
if err := tmos.EnsureDir(writePath, 0700); err != nil {
|
2019-05-16 08:25:32 -07:00
|
|
|
return "", err
|
2018-12-04 01:57:44 -08:00
|
|
|
}
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil
|
|
|
|
}
|
2018-12-04 01:57:44 -08:00
|
|
|
|
2020-06-17 11:42:27 -07:00
|
|
|
func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (authtypes.StdTx, error) {
|
|
|
|
var stdTx authtypes.StdTx
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
bytes, err := ioutil.ReadAll(r)
|
2020-05-08 01:46:12 -07:00
|
|
|
if err != nil {
|
2019-05-16 08:25:32 -07:00
|
|
|
return stdTx, err
|
2018-12-04 01:57:44 -08:00
|
|
|
}
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
err = cdc.UnmarshalJSON(bytes, &stdTx)
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
return stdTx, err
|
|
|
|
}
|
2018-12-04 01:57:44 -08:00
|
|
|
|
2020-06-17 11:42:27 -07:00
|
|
|
func writeSignedGenTx(cdc *codec.Codec, outputDocument string, tx authtypes.StdTx) error {
|
2019-05-16 08:25:32 -07:00
|
|
|
outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-06-26 13:30:36 -07:00
|
|
|
defer outputFile.Close()
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
json, err := cdc.MarshalJSON(tx)
|
2020-05-08 01:46:12 -07:00
|
|
|
if err != nil {
|
2019-05-16 08:25:32 -07:00
|
|
|
return err
|
|
|
|
}
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
_, err = fmt.Fprintf(outputFile, "%s\n", json)
|
2020-05-02 12:26:59 -07:00
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
return err
|
2018-12-04 01:57:44 -08:00
|
|
|
}
|
|
|
|
|
2019-05-16 08:25:32 -07:00
|
|
|
// DONTCOVER
|