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