From 06e748a588e4b536cf9dc6f12e2d8e9e15a94f12 Mon Sep 17 00:00:00 2001 From: Tomas Tauber <2410580+tomtau@users.noreply.github.com> Date: Mon, 7 Sep 2020 18:07:03 +0800 Subject: [PATCH] Problem: base denomination can't be parsed with decimal point (fixes #16) Solution: - decimal point is something for the future: https://github.com/cosmos/cosmos-sdk/issues/7113 - for the moment -- configured "human" denomination ("cro") + base ("basecro" / "carson") -- configs/tx use "basecro" - custom commands that use "human" denomination and convert it to the base - custom init that changes bond_denom + gov minimum deposit to use the base denomination --- app/prefix.go | 9 ++ app/prefix_test.go | 42 ++++++ cmd/chain-maincli/main.go | 55 +++++++- cmd/chain-maind/genaccounts.go | 18 ++- cmd/chain-maind/gentx.go | 244 +++++++++++++++++++++++++++++++++ cmd/chain-maind/init.go | 167 ++++++++++++++++++++++ cmd/chain-maind/main.go | 4 +- go.mod | 4 + 8 files changed, 535 insertions(+), 8 deletions(-) create mode 100644 app/prefix_test.go create mode 100644 cmd/chain-maind/gentx.go create mode 100644 cmd/chain-maind/init.go diff --git a/app/prefix.go b/app/prefix.go index 725d89a21..1e476ca39 100644 --- a/app/prefix.go +++ b/app/prefix.go @@ -11,6 +11,8 @@ var ( ValidatorPubKeyPrefix = "crocnclpub" ConsNodeAddressPrefix = "crocnclcons" ConsNodePubKeyPrefix = "crocnclconspub" + HumanCoinUnit = "cro" + BaseCoinUnit = "basecro" // 10^-8 AKA "carson" ) func SetConfig() { @@ -18,5 +20,12 @@ func SetConfig() { config.SetBech32PrefixForAccount(AccountAddressPrefix, AccountPubKeyPrefix) config.SetBech32PrefixForValidator(ValidatorAddressPrefix, ValidatorPubKeyPrefix) config.SetBech32PrefixForConsensusNode(ConsNodeAddressPrefix, ConsNodePubKeyPrefix) + + croUnit := sdk.OneDec() + sdk.RegisterDenom(HumanCoinUnit, croUnit) + + carsonUnit := sdk.NewDecWithPrec(1, 8) // 10^-8 (carson) + sdk.RegisterDenom(BaseCoinUnit, carsonUnit) + config.Seal() } diff --git a/app/prefix_test.go b/app/prefix_test.go new file mode 100644 index 000000000..04d2d068e --- /dev/null +++ b/app/prefix_test.go @@ -0,0 +1,42 @@ +package app_test + +import ( + "testing" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/crypto-com/chain-main/app" + "github.com/stretchr/testify/require" +) + +func TestConversion(t *testing.T) { + app.SetConfig() + + testCases := []struct { + input sdk.Coin + denom string + result sdk.Coin + expErr bool + }{ + {sdk.NewCoin("foo", sdk.ZeroInt()), app.HumanCoinUnit, sdk.Coin{}, true}, + {sdk.NewCoin(app.HumanCoinUnit, sdk.ZeroInt()), "foo", sdk.Coin{}, true}, + {sdk.NewCoin(app.HumanCoinUnit, sdk.ZeroInt()), "FOO", sdk.Coin{}, true}, + + {sdk.NewCoin(app.HumanCoinUnit, sdk.NewInt(5)), app.BaseCoinUnit, sdk.NewCoin(app.BaseCoinUnit, sdk.NewInt(500000000)), false}, // cro => carson + + {sdk.NewCoin(app.BaseCoinUnit, sdk.NewInt(500000000)), app.HumanCoinUnit, sdk.NewCoin(app.HumanCoinUnit, sdk.NewInt(5)), false}, // carson => cro + + } + + for i, tc := range testCases { + res, err := sdk.ConvertCoin(tc.input, tc.denom) + require.Equal( + t, tc.expErr, err != nil, + "unexpected error; tc: #%d, input: %s, denom: %s", i+1, tc.input, tc.denom, + ) + require.Equal( + t, tc.result, res, + "invalid result; tc: #%d, input: %s, denom: %s", i+1, tc.input, tc.denom, + ) + } + +} diff --git a/cmd/chain-maincli/main.go b/cmd/chain-maincli/main.go index 48b996324..2e9de6b70 100644 --- a/cmd/chain-maincli/main.go +++ b/cmd/chain-maincli/main.go @@ -1,6 +1,7 @@ package main import ( + "bufio" "fmt" "os" "path" @@ -10,21 +11,24 @@ import ( "github.com/cosmos/cosmos-sdk/client/keys" "github.com/cosmos/cosmos-sdk/client/lcd" "github.com/cosmos/cosmos-sdk/client/rpc" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli" authrest "github.com/cosmos/cosmos-sdk/x/auth/client/rest" "github.com/cosmos/cosmos-sdk/x/bank" - bankcmd "github.com/cosmos/cosmos-sdk/x/bank/client/cli" + //"github.com/gogo/protobuf/codec" "github.com/spf13/cobra" "github.com/spf13/viper" - "github.com/tendermint/go-amino" + amino "github.com/tendermint/go-amino" "github.com/tendermint/tendermint/libs/cli" + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" "github.com/crypto-com/chain-main/app" - // this line is used by starport scaffolding + // this line is used by starport scaffolding ) func main() { @@ -99,6 +103,47 @@ func queryCmd(cdc *amino.Codec) *cobra.Command { return queryCmd } +// SendTxCmd will create a send tx and sign it with the given key. +// and convert CRO to carson +func CustomSendTxCmd(cdc *amino.Codec) *cobra.Command { + cmd := &cobra.Command{ + Use: "send [from_key_or_address] [to_address] [amount]", + Short: "Create and sign a send tx", + Args: cobra.ExactArgs(3), + RunE: func(cmd *cobra.Command, args []string) error { + inBuf := bufio.NewReader(cmd.InOrStdin()) + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInputAndFrom(inBuf, args[0]).WithCodec(cdc) + + to, err := sdk.AccAddressFromBech32(args[1]) + if err != nil { + return err + } + + // parse coins trying to be sent + coins, err := sdk.ParseCoins(args[2]) + if err != nil { + return err + } + for i := 0; i < len(coins); i++ { + coin, err := sdk.ConvertCoin(coins[i], app.BaseCoinUnit) + if err != nil { + return err + } + coins[i] = coin + } + + // build and sign the transaction, then broadcast to Tendermint + msg := bank.NewMsgSend(cliCtx.GetFromAddress(), to, coins) + return utils.GenerateOrBroadcastMsgs(cliCtx, txBldr, []sdk.Msg{msg}) + }, + } + + cmd = flags.PostCommands(cmd)[0] + + return cmd +} + func txCmd(cdc *amino.Codec) *cobra.Command { txCmd := &cobra.Command{ Use: "tx", @@ -106,7 +151,7 @@ func txCmd(cdc *amino.Codec) *cobra.Command { } txCmd.AddCommand( - bankcmd.SendTxCmd(cdc), + CustomSendTxCmd(cdc), flags.LineBreak, authcmd.GetSignCommand(cdc), authcmd.GetMultiSignCommand(cdc), @@ -141,7 +186,7 @@ func registerRoutes(rs *lcd.RestServer) { client.RegisterRoutes(rs.CliCtx, rs.Mux) authrest.RegisterTxRoutes(rs.CliCtx, rs.Mux) app.ModuleBasics.RegisterRESTRoutes(rs.CliCtx, rs.Mux) - // this line is used by starport scaffolding # 2 + // this line is used by starport scaffolding # 2 } func initConfig(cmd *cobra.Command) error { diff --git a/cmd/chain-maind/genaccounts.go b/cmd/chain-maind/genaccounts.go index 90df73f4c..11a64a7ee 100644 --- a/cmd/chain-maind/genaccounts.go +++ b/cmd/chain-maind/genaccounts.go @@ -5,14 +5,15 @@ import ( "errors" "fmt" + "github.com/crypto-com/chain-main/app" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/tendermint/tendermint/libs/cli" "github.com/cosmos/cosmos-sdk/client/flags" - "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" @@ -72,6 +73,13 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa if err != nil { return fmt.Errorf("failed to parse coins: %w", err) } + for i := 0; i < len(coins); i++ { + coin, err := sdk.ConvertCoin(coins[i], app.BaseCoinUnit) + if err != nil { + return fmt.Errorf("failed to convert coins: %w", err) + } + coins[i] = coin + } vestingStart := viper.GetInt64(flagVestingStart) vestingEnd := viper.GetInt64(flagVestingEnd) @@ -80,6 +88,14 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa return fmt.Errorf("failed to parse vesting amount: %w", err) } + for i := 0; i < len(vestingAmt); i++ { + coin, err := sdk.ConvertCoin(vestingAmt[i], app.BaseCoinUnit) + if err != nil { + return fmt.Errorf("failed to convert coins: %w", err) + } + vestingAmt[i] = coin + } + // create concrete account type based on input parameters var genAccount authexported.GenesisAccount diff --git a/cmd/chain-maind/gentx.go b/cmd/chain-maind/gentx.go new file mode 100644 index 000000000..7146cfa67 --- /dev/null +++ b/cmd/chain-maind/gentx.go @@ -0,0 +1,244 @@ +package main + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" + "io/ioutil" + "os" + "path/filepath" + + staking "github.com/cosmos/cosmos-sdk/x/staking/types" + "github.com/crypto-com/chain-main/app" + "github.com/pkg/errors" + "github.com/spf13/cobra" + flag "github.com/spf13/pflag" + "github.com/spf13/viper" + cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/crypto" + tmos "github.com/tendermint/tendermint/libs/os" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client/context" + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/crypto/keys" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/auth/client/utils" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/genutil/types" +) + +// StakingMsgBuildingHelpers helpers for message building gen-tx command +type StakingMsgBuildingHelpers interface { + CreateValidatorMsgHelpers(ipDefault string) (fs *flag.FlagSet, nodeIDFlag, pubkeyFlag, amountFlag, defaultsDesc string) + PrepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, chainID string, valPubKey crypto.PubKey) + BuildCreateValidatorMsg(cliCtx context.CLIContext, txBldr auth.TxBuilder) (auth.TxBuilder, sdk.Msg, error) +} + +// GenTxCmd builds the application's gentx command. (converts CRO to Carson) +// nolint: errcheck +func CustomGenTxCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, smbh StakingMsgBuildingHelpers, + genAccIterator types.GenesisAccountsIterator, defaultNodeHome, defaultCLIHome string) *cobra.Command { + + ipDefault, _ := server.ExternalIP() + fsCreateValidator, flagNodeID, flagPubKey, flagAmount, defaultsDesc := smbh.CreateValidatorMsgHelpers(ipDefault) + + cmd := &cobra.Command{ + Use: "gentx", + Short: "Generate a genesis tx carrying a self delegation", + Args: cobra.NoArgs, + Long: fmt.Sprintf(`This command is an alias of the 'tx create-validator' command'. + + It creates a genesis transaction to create a validator. + The following default parameters are included: + %s`, defaultsDesc), + + RunE: func(cmd *cobra.Command, args []string) error { + + config := ctx.Config + config.SetRoot(viper.GetString(flags.FlagHome)) + nodeID, valPubKey, err := genutil.InitializeNodeValidatorFiles(ctx.Config) + if err != nil { + return errors.Wrap(err, "failed to initialize node validator files") + } + + // Read --nodeID, if empty take it from priv_validator.json + if nodeIDString := viper.GetString(flagNodeID); nodeIDString != "" { + nodeID = nodeIDString + } + // Read --pubkey, if empty take it from priv_validator.json + if valPubKeyString := viper.GetString(flagPubKey); valPubKeyString != "" { + valPubKey, err = sdk.GetPubKeyFromBech32(sdk.Bech32PubKeyTypeConsPub, valPubKeyString) + if err != nil { + return errors.Wrap(err, "failed to get consensus node public key") + } + } + + genDoc, err := tmtypes.GenesisDocFromFile(config.GenesisFile()) + if err != nil { + return errors.Wrapf(err, "failed to read genesis doc file %s", config.GenesisFile()) + } + + var genesisState map[string]json.RawMessage + if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil { + return errors.Wrap(err, "failed to unmarshal genesis state") + } + + if err = mbm.ValidateGenesis(genesisState); err != nil { + return errors.Wrap(err, "failed to validate genesis state") + } + + inBuf := bufio.NewReader(cmd.InOrStdin()) + kb, err := keys.NewKeyring(sdk.KeyringServiceName(), + viper.GetString(flags.FlagKeyringBackend), viper.GetString(flagClientHome), inBuf) + if err != nil { + return errors.Wrap(err, "failed to initialize keybase") + } + + name := viper.GetString(flags.FlagName) + key, err := kb.Get(name) + if err != nil { + return errors.Wrap(err, "failed to read from keybase") + } + + // Set flags for creating gentx + viper.Set(flags.FlagHome, viper.GetString(flagClientHome)) + smbh.PrepareFlagsForTxCreateValidator(config, nodeID, genDoc.ChainID, valPubKey) + + // Fetch the amount of coins staked + amount := viper.GetString(flagAmount) + coins, err := sdk.ParseCoins(amount) + if err != nil { + return errors.Wrap(err, "failed to parse coins") + } + + for i := 0; i < len(coins); i++ { + coin, err := sdk.ConvertCoin(coins[i], app.BaseCoinUnit) + if err != nil { + return fmt.Errorf("failed to convert coins: %w", err) + } + coins[i] = coin + } + + err = genutil.ValidateAccountInGenesis(genesisState, genAccIterator, key.GetAddress(), coins, cdc) + if err != nil { + return errors.Wrap(err, "failed to validate account in genesis") + } + + txBldr := auth.NewTxBuilderFromCLI(inBuf).WithTxEncoder(utils.GetTxEncoder(cdc)) + cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc) + + // Set the generate-only flag here after the CLI context has + // been created. This allows the from name/key to be correctly populated. + // + // TODO: Consider removing the manual setting of generate-only in + // favor of a 'gentx' flag in the create-validator command. + viper.Set(flags.FlagGenerateOnly, true) + + // create a 'create-validator' message + txBldr, msg, err := smbh.BuildCreateValidatorMsg(cliCtx, txBldr) + if err != nil { + return errors.Wrap(err, "failed to build create-validator message") + } + nmsg := msg.(staking.MsgCreateValidator) + coin, err := sdk.ConvertCoin(nmsg.Value, app.BaseCoinUnit) + if err != nil { + return fmt.Errorf("failed to convert coins: %w", err) + } + nmsg.Value = coin + msg = nmsg + + if key.GetType() == keys.TypeOffline || key.GetType() == keys.TypeMulti { + fmt.Println("Offline key passed in. Use `tx sign` command to sign:") + return utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}) + } + + // write the unsigned transaction to the buffer + w := bytes.NewBuffer([]byte{}) + cliCtx = cliCtx.WithOutput(w) + + if err = utils.PrintUnsignedStdTx(txBldr, cliCtx, []sdk.Msg{msg}); err != nil { + return errors.Wrap(err, "failed to print unsigned std tx") + } + + // read the transaction + stdTx, err := readUnsignedGenTxFile(cdc, w) + if err != nil { + return errors.Wrap(err, "failed to read unsigned gen tx file") + } + + // sign the transaction and write it to the output file + signedTx, err := utils.SignStdTx(txBldr, cliCtx, name, stdTx, false, true) + if err != nil { + return errors.Wrap(err, "failed to sign std tx") + } + + // Fetch output file name + outputDocument := viper.GetString(flags.FlagOutputDocument) + if outputDocument == "" { + outputDocument, err = makeOutputFilepath(config.RootDir, nodeID) + if err != nil { + return errors.Wrap(err, "failed to create output file path") + } + } + + if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil { + return errors.Wrap(err, "failed to write signed gen tx") + } + + fmt.Fprintf(os.Stderr, "Genesis transaction written to %q\n", outputDocument) + return nil + + }, + } + + cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory") + cmd.Flags().String(flagClientHome, defaultCLIHome, "client's home directory") + cmd.Flags().String(flags.FlagName, "", "name of private key with which to sign the gentx") + cmd.Flags().String(flags.FlagOutputDocument, "", + "write the genesis transaction JSON document to the given file instead of the default location") + cmd.Flags().AddFlagSet(fsCreateValidator) + cmd.Flags().String(flags.FlagKeyringBackend, flags.DefaultKeyringBackend, "Select keyring's backend (os|file|test)") + viper.BindPFlag(flags.FlagKeyringBackend, cmd.Flags().Lookup(flags.FlagKeyringBackend)) + + cmd.MarkFlagRequired(flags.FlagName) + return cmd +} + +func makeOutputFilepath(rootDir, nodeID string) (string, error) { + writePath := filepath.Join(rootDir, "config", "gentx") + if err := tmos.EnsureDir(writePath, 0700); err != nil { + return "", err + } + return filepath.Join(writePath, fmt.Sprintf("gentx-%v.json", nodeID)), nil +} + +func readUnsignedGenTxFile(cdc *codec.Codec, r io.Reader) (auth.StdTx, error) { + var stdTx auth.StdTx + bytes, err := ioutil.ReadAll(r) + if err != nil { + return stdTx, err + } + err = cdc.UnmarshalJSON(bytes, &stdTx) + return stdTx, err +} + +func writeSignedGenTx(cdc *codec.Codec, outputDocument string, tx auth.StdTx) error { + outputFile, err := os.OpenFile(outputDocument, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0644) + if err != nil { + return err + } + defer outputFile.Close() + json, err := cdc.MarshalJSON(tx) + if err != nil { + return err + } + _, err = fmt.Fprintf(outputFile, "%s\n", json) + return err +} diff --git a/cmd/chain-maind/init.go b/cmd/chain-maind/init.go new file mode 100644 index 000000000..e46d5deb3 --- /dev/null +++ b/cmd/chain-maind/init.go @@ -0,0 +1,167 @@ +package main + +import ( + "encoding/json" + "fmt" + "os" + "path/filepath" + + "github.com/crypto-com/chain-main/app" + "github.com/pkg/errors" + "github.com/spf13/cobra" + "github.com/spf13/viper" + cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/libs/cli" + tmos "github.com/tendermint/tendermint/libs/os" + tmrand "github.com/tendermint/tendermint/libs/rand" + "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/client/flags" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/types/module" + "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/gov" + "github.com/cosmos/cosmos-sdk/x/staking" +) + +const ( + flagOverwrite = "overwrite" +) + +func GetGenesisStakingStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) staking.GenesisState { + var genesisState staking.GenesisState + if appState[staking.ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[staking.ModuleName], &genesisState) + } + + return genesisState +} + +func GetGenesisGovStateFromAppState(cdc *codec.Codec, appState map[string]json.RawMessage) gov.GenesisState { + var genesisState gov.GenesisState + if appState[gov.ModuleName] != nil { + cdc.MustUnmarshalJSON(appState[gov.ModuleName], &genesisState) + } + + return genesisState +} + +type printInfo struct { + Moniker string `json:"moniker" yaml:"moniker"` + ChainID string `json:"chain_id" yaml:"chain_id"` + NodeID string `json:"node_id" yaml:"node_id"` + GenTxsDir string `json:"gentxs_dir" yaml:"gentxs_dir"` + AppMessage json.RawMessage `json:"app_message" yaml:"app_message"` +} + +func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, + appMessage json.RawMessage) printInfo { + + return printInfo{ + Moniker: moniker, + ChainID: chainID, + NodeID: nodeID, + GenTxsDir: genTxsDir, + AppMessage: appMessage, + } +} + +func displayInfo(cdc *codec.Codec, info printInfo) error { + out, err := codec.MarshalJSONIndent(cdc, info) + if err != nil { + return err + } + + _, err = fmt.Fprintf(os.Stderr, "%s\n", string(sdk.MustSortJSON(out))) + return err +} + +// InitCmd returns a command that initializes all files needed for Tendermint +// and the respective application. +func CustomInitCmd(ctx *server.Context, cdc *codec.Codec, mbm module.BasicManager, + defaultNodeHome string) *cobra.Command { // nolint: golint + cmd := &cobra.Command{ + Use: "init [moniker]", + Short: "Initialize private validator, p2p, genesis, and application configuration files", + Long: `Initialize validators's and node's configuration files.`, + Args: cobra.ExactArgs(1), + RunE: func(_ *cobra.Command, args []string) error { + config := ctx.Config + config.SetRoot(viper.GetString(cli.HomeFlag)) + + chainID := viper.GetString(flags.FlagChainID) + if chainID == "" { + chainID = fmt.Sprintf("test-chain-%v", tmrand.Str(6)) + } + + nodeID, _, err := genutil.InitializeNodeValidatorFiles(config) + if err != nil { + return err + } + + config.Moniker = args[0] + + genFile := config.GenesisFile() + if !viper.GetBool(flagOverwrite) && tmos.FileExists(genFile) { + return fmt.Errorf("genesis.json file already exists: %v", genFile) + } + appStateS := mbm.DefaultGenesis() + stakingGenState := GetGenesisStakingStateFromAppState(cdc, appStateS) + stakingGenState.Params.BondDenom = app.BaseCoinUnit + + stakingGenStateBz, err := cdc.MarshalJSON(stakingGenState) + if err != nil { + return fmt.Errorf("failed to marshal staking genesis state: %w", err) + } + + appStateS[staking.ModuleName] = stakingGenStateBz + + govGenState := GetGenesisGovStateFromAppState(cdc, appStateS) + govGenState.DepositParams.MinDeposit[0].Denom = app.BaseCoinUnit + + govGenStateBz, err := cdc.MarshalJSON(govGenState) + if err != nil { + return fmt.Errorf("failed to marshal gov genesis state: %w", err) + } + + appStateS[gov.ModuleName] = govGenStateBz + + appState, err := codec.MarshalJSONIndent(cdc, appStateS) + if err != nil { + return errors.Wrap(err, "Failed to marshall default genesis state") + } + + genDoc := &types.GenesisDoc{} + if _, err := os.Stat(genFile); err != nil { + if !os.IsNotExist(err) { + return err + } + } else { + genDoc, err = types.GenesisDocFromFile(genFile) + if err != nil { + return errors.Wrap(err, "Failed to read genesis doc from file") + } + } + + genDoc.ChainID = chainID + genDoc.Validators = nil + genDoc.AppState = appState + if err = genutil.ExportGenesisFile(genDoc, genFile); err != nil { + return errors.Wrap(err, "Failed to export gensis file") + } + + toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState) + + cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config) + return displayInfo(cdc, toPrint) + }, + } + + cmd.Flags().String(cli.HomeFlag, defaultNodeHome, "node's home directory") + cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file") + cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + + return cmd +} diff --git a/cmd/chain-maind/main.go b/cmd/chain-maind/main.go index ec1310385..d5886e16c 100644 --- a/cmd/chain-maind/main.go +++ b/cmd/chain-maind/main.go @@ -43,11 +43,11 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - rootCmd.AddCommand(genutilcli.InitCmd(ctx, cdc, app.ModuleBasics, app.DefaultNodeHome)) + rootCmd.AddCommand(CustomInitCmd(ctx, cdc, app.ModuleBasics, app.DefaultNodeHome)) rootCmd.AddCommand(genutilcli.CollectGenTxsCmd(ctx, cdc, auth.GenesisAccountIterator{}, app.DefaultNodeHome)) rootCmd.AddCommand(genutilcli.MigrateGenesisCmd(ctx, cdc)) rootCmd.AddCommand( - genutilcli.GenTxCmd( + CustomGenTxCmd( ctx, cdc, app.ModuleBasics, staking.AppModuleBasic{}, auth.GenesisAccountIterator{}, app.DefaultNodeHome, app.DefaultCLIHome, ), diff --git a/go.mod b/go.mod index 54934848f..2656fd72a 100644 --- a/go.mod +++ b/go.mod @@ -4,14 +4,18 @@ go 1.14 require ( github.com/cosmos/cosmos-sdk v0.39.1 + github.com/gogo/protobuf v1.3.1 github.com/golang/mock v1.4.3 // indirect github.com/google/go-cmp v0.5.0 // indirect github.com/gorilla/mux v1.7.4 github.com/onsi/ginkgo v1.8.0 // indirect github.com/onsi/gomega v1.5.0 // indirect + github.com/pkg/errors v0.9.1 github.com/spf13/afero v1.2.2 // indirect github.com/spf13/cobra v1.0.0 + github.com/spf13/pflag v1.0.5 github.com/spf13/viper v1.7.0 + github.com/stretchr/testify v1.6.1 github.com/tendermint/go-amino v0.15.1 github.com/tendermint/tendermint v0.33.7 github.com/tendermint/tm-db v0.5.1