github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/x/genutil/client/cli/gentx.go (about)

     1  package cli
     2  
     3  import (
     4  	"bufio"
     5  	"bytes"
     6  	"encoding/json"
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"os"
    11  	"path/filepath"
    12  
    13  	cfg "github.com/fibonacci-chain/fbc/libs/tendermint/config"
    14  	"github.com/fibonacci-chain/fbc/libs/tendermint/crypto"
    15  	tmos "github.com/fibonacci-chain/fbc/libs/tendermint/libs/os"
    16  	tmtypes "github.com/fibonacci-chain/fbc/libs/tendermint/types"
    17  	"github.com/pkg/errors"
    18  	"github.com/spf13/cobra"
    19  	flag "github.com/spf13/pflag"
    20  	"github.com/spf13/viper"
    21  
    22  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/context"
    23  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/client/flags"
    24  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec"
    25  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/crypto/keys"
    26  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/server"
    27  	sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types"
    28  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/module"
    29  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth"
    30  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/auth/client/utils"
    31  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/genutil"
    32  	"github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/genutil/types"
    33  )
    34  
    35  // StakingMsgBuildingHelpers helpers for message building gen-tx command
    36  type StakingMsgBuildingHelpers interface {
    37  	CreateValidatorMsgHelpers(ipDefault string) (fs *flag.FlagSet, nodeIDFlag, pubkeyFlag, amountFlag, defaultsDesc string)
    38  	PrepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, chainID string, valPubKey crypto.PubKey)
    39  	BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (auth.TxBuilder, sdk.Msg, error)
    40  }
    41  
    42  // GenTxCmd builds the application's gentx command.
    43  // nolint: errcheck
    44  func GenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, smbh StakingMsgBuildingHelpers,
    45  	genAccIterator types.GenesisAccountsIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command {
    46  
    47  	ipDefault, _ := server.ExternalIP()
    48  	fsCreateValidator, flagNodeID, flagPubKey, flagAmount, defaultsDesc := smbh.CreateValidatorMsgHelpers(ipDefault)
    49  
    50  	cmd := &cobra.Command{
    51  		Use:   "gentx",
    52  		Short: "Generate a genesis tx carrying a self delegation",
    53  		Args:  cobra.NoArgs,
    54  		Long: fmt.Sprintf(`This command is an alias of the 'tx create-validator' command'.
    55  
    56  		It creates a genesis transaction to create a validator. 
    57  		The following default parameters are included: 
    58  		    %s`, defaultsDesc),
    59  
    60  		RunE: func(cmd *cobra.Command, args []string) error {
    61  
    62  			config := ctx.Config
    63  			config.SetRoot(viper.GetString(flags.FlagHome))
    64  			nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(ctx.Config)
    65  			if err != nil {
    66  				return errors.Wrap(err, "failed to initialize node validator files")
    67  			}
    68  
    69  			// Read --nodeID, if empty take it from priv_validator.json
    70  			if nodeIDString := viper.GetString(flagNodeID); nodeIDString != "" {
    71  				nodeID = nodeIDString
    72  			}
    73  			// Read --pubkey, if empty take it from priv_validator.json
    74  			if valPubKeyString := viper.GetString(flagPubKey); valPubKeyString != "" {
    75  				valPubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, valPubKeyString)
    76  				if err != nil {
    77  					return errors.Wrap(err, "failed to get consensus node public key")
    78  				}
    79  			}
    80  
    81  			genDoc, err := tmtypes.GenesisDocFromFile(config.GenesisFile())
    82  			if err != nil {
    83  				return errors.Wrapf(err, "failed to read genesis doc file %s", config.GenesisFile())
    84  			}
    85  
    86  			var genesisState map[string]json.RawMessage
    87  			if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil {
    88  				return errors.Wrap(err, "failed to unmarshal genesis state")
    89  			}
    90  
    91  			if err = mbm.ValidateGenesis(genesisState); err != nil {
    92  				return errors.Wrap(err, "failed to validate genesis state")
    93  			}
    94  
    95  			inBuf := bufio.NewReader(cmd.InOrStdin())
    96  			kb, err := keys.NewKeyring(sdk.KeyringServiceName(),
    97  				viper.GetString(flags.FlagKeyringBackend), viper.GetString(flagClientHome), inBuf)
    98  			if err != nil {
    99  				return errors.Wrap(err, "failed to initialize keybase")
   100  			}
   101  
   102  			name := viper.GetString(flags.FlagName)
   103  			key, err := kb.Get(name)
   104  			if err != nil {
   105  				return errors.Wrap(err, "failed to read from keybase")
   106  			}
   107  
   108  			// Set flags for creating gentx
   109  			viper.Set(flags.FlagHome, viper.GetString(flagClientHome))
   110  			smbh.PrepareFlagsForTxCreateValidator(config, nodeID, genDoc.ChainID, valPubKey)
   111  
   112  			// Fetch the amount of coins staked
   113  			amount := viper.GetString(flagAmount)
   114  			coins, err := sdk.ParseCoins(amount)
   115  			if err != nil {
   116  				return errors.Wrap(err, "failed to parse coins")
   117  			}
   118  
   119  			err = genutil.ValidateAccountInGenesis(genesisState, genAccIterator, key.GetAddress(), coins, cdc)
   120  			if err != nil {
   121  				return errors.Wrap(err, "failed to validate account in genesis")
   122  			}
   123  
   124  			txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc))
   125  			cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc)
   126  
   127  			// Set the generate-only flag here after the CLI context has
   128  			// been created. This allows the from name/key to be correctly populated.
   129  			//
   130  			// TODO: Consider removing the manual setting of generate-only in
   131  			// favor of a 'gentx' flag in the create-validator command.
   132  			viper.Set(flags.FlagGenerateOnly, true)
   133  
   134  			// create a 'create-validator' message
   135  			txBldr, msg, err := smbh.BuildCreateValidatorMsg(cliCtx, txBldr)
   136  			if err != nil {
   137  				return errors.Wrap(err, "failed to build create-validator message")
   138  			}
   139  
   140  			if key.GetType() == keys.TypeOffline || key.GetType() == keys.TypeMulti {
   141  				fmt.Println("Offline key passed in. Use `tx sign` command to sign:")
   142  				return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg})
   143  			}
   144  
   145  			// write the unsigned transaction to the buffer
   146  			w := bytes.NewBuffer([]byte{})
   147  			cliCtx = cliCtx.WithOutput(w)
   148  
   149  			if err = utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}); err != nil {
   150  				return errors.Wrap(err, "failed to print unsigned std tx")
   151  			}
   152  
   153  			// read the transaction
   154  			stdTx, err := readUnsignedGenTxFile(cdc, w)
   155  			if err != nil {
   156  				return errors.Wrap(err, "failed to read unsigned gen tx file")
   157  			}
   158  
   159  			// sign the transaction and write it to the output file
   160  			signedTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, false, true)
   161  			if err != nil {
   162  				return errors.Wrap(err, "failed to sign std tx")
   163  			}
   164  
   165  			// Fetch output file name
   166  			outputDocument := viper.GetString(flags.FlagOutputDocument)
   167  			if outputDocument == "" {
   168  				outputDocument, err = makeOutputFilepath(config.RootDir, nodeID)
   169  				if err != nil {
   170  					return errors.Wrap(err, "failed to create output file path")
   171  				}
   172  			}
   173  
   174  			if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil {
   175  				return errors.Wrap(err, "failed to write signed gen tx")
   176  			}
   177  
   178  			fmt.Fprintf(os.Stderr, "Genesis transaction written to %q\n", outputDocument)
   179  			return nil
   180  
   181  		},
   182  	}
   183  
   184  	cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory")
   185  	cmd.Flags().String(flagClientHome, defaultCLIHome, "client's home directory")
   186  	cmd.Flags().String(flags.FlagName, "", "name of private key with which to sign the gentx")
   187  	cmd.Flags().String(flags.FlagOutputDocument, "",
   188  		"write the genesis transaction JSON document to the given file instead of the default location")
   189  	cmd.Flags().AddFlagSet(fsCreateValidator)
   190  	cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)")
   191  	viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend))
   192  
   193  	cmd.MarkFlagRequired(flags.FlagName)
   194  	return cmd
   195  }
   196  
   197  func makeOutputFilepath(rootDir, nodeID string) (string, error) {
   198  	writePath := filepath.Join(rootDir, "config", "gentx")
   199  	if err := tmos.EnsureDir(writePath, 0700); err != nil {
   200  		return "", err
   201  	}
   202  	return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil
   203  }
   204  
   205  func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (*auth.StdTx, error) {
   206  	var stdTx auth.StdTx
   207  	bytes, err := ioutil.ReadAll(r)
   208  	if err != nil {
   209  		return nil, err
   210  	}
   211  	err = cdc.UnmarshalJSON(bytes, &stdTx)
   212  	return &stdTx, err
   213  }
   214  
   215  func writeSignedGenTx(cdc *codec.Codec, outputDocument string, tx *auth.StdTx) error {
   216  	outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644)
   217  	if err != nil {
   218  		return err
   219  	}
   220  	defer outputFile.Close()
   221  	json, err := cdc.MarshalJSON(tx)
   222  	if err != nil {
   223  		return err
   224  	}
   225  	_, err = fmt.Fprintf(outputFile, "%s\n", json)
   226  	return err
   227  }
   228  
   229  // DONTCOVER