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 }