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