From 26cdffe5073034141c41a86134f69ee69987f550 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/app.go | 6 +- app/export.go | 2 +- app/prefix.go | 18 +++ app/prefix_test.go | 44 ++++++ cmd/chain-maincli/main.go | 54 ++++++- cmd/chain-maind/genaccounts.go | 23 ++- cmd/chain-maind/gentx.go | 245 ++++++++++++++++++++++++++++++++ cmd/chain-maind/init.go | 167 ++++++++++++++++++++++ cmd/chain-maind/main.go | 4 +- go.mod | 4 + x/chainmain/abci.go | 3 +- x/chainmain/client/cli/query.go | 2 +- x/chainmain/client/cli/tx.go | 2 +- x/chainmain/client/rest/rest.go | 2 +- x/chainmain/genesis.go | 6 +- x/chainmain/handler.go | 6 +- x/chainmain/keeper/params.go | 1 + x/chainmain/keeper/querier.go | 8 +- x/chainmain/module.go | 2 +- x/chainmain/types/codec.go | 2 +- x/chainmain/types/params.go | 14 +- x/chainmain/types/querier.go | 1 - x/chainmain/types/types.go | 1 - 23 files changed, 579 insertions(+), 38 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/app.go b/app/app.go index 692d277c7..54d874ba9 100644 --- a/app/app.go +++ b/app/app.go @@ -18,17 +18,17 @@ import ( "github.com/cosmos/cosmos-sdk/version" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/bank" + distr "github.com/cosmos/cosmos-sdk/x/distribution" "github.com/cosmos/cosmos-sdk/x/genutil" + "github.com/cosmos/cosmos-sdk/x/gov" "github.com/cosmos/cosmos-sdk/x/params" + paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" "github.com/crypto-com/chain-main/x/chainmain" chainmainkeeper "github.com/crypto-com/chain-main/x/chainmain/keeper" chainmaintypes "github.com/crypto-com/chain-main/x/chainmain/types" // this line is used by starport scaffolding - distr "github.com/cosmos/cosmos-sdk/x/distribution" - "github.com/cosmos/cosmos-sdk/x/gov" - paramsclient "github.com/cosmos/cosmos-sdk/x/params/client" ) const appName = "Crypto.com Chain" diff --git a/app/export.go b/app/export.go index d999aa275..b6c892f5a 100644 --- a/app/export.go +++ b/app/export.go @@ -41,7 +41,7 @@ func (app *NewApp) ExportAppStateAndValidators( func (app *NewApp) prepForZeroHeightGenesis(ctx sdk.Context, jailWhiteList []string) { applyWhiteList := false - //Check if there is a whitelist + // Check if there is a whitelist if len(jailWhiteList) > 0 { applyWhiteList = true } diff --git a/app/prefix.go b/app/prefix.go index 725d89a21..9bc8a8706 100644 --- a/app/prefix.go +++ b/app/prefix.go @@ -1,6 +1,8 @@ package app import ( + "log" + sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -11,6 +13,8 @@ var ( ValidatorPubKeyPrefix = "crocnclpub" ConsNodeAddressPrefix = "crocnclcons" ConsNodePubKeyPrefix = "crocnclconspub" + HumanCoinUnit = "cro" + BaseCoinUnit = "basecro" // 10^-8 AKA "carson" ) func SetConfig() { @@ -18,5 +22,19 @@ func SetConfig() { config.SetBech32PrefixForAccount(AccountAddressPrefix, AccountPubKeyPrefix) config.SetBech32PrefixForValidator(ValidatorAddressPrefix, ValidatorPubKeyPrefix) config.SetBech32PrefixForConsensusNode(ConsNodeAddressPrefix, ConsNodePubKeyPrefix) + + croUnit := sdk.OneDec() + err := sdk.RegisterDenom(HumanCoinUnit, croUnit) + if err != nil { + log.Fatal(err) + } + + carsonUnit := sdk.NewDecWithPrec(1, 8) // 10^-8 (carson) + err = sdk.RegisterDenom(BaseCoinUnit, carsonUnit) + + if err != nil { + log.Fatal(err) + } + config.Seal() } diff --git a/app/prefix_test.go b/app/prefix_test.go new file mode 100644 index 000000000..af072544d --- /dev/null +++ b/app/prefix_test.go @@ -0,0 +1,44 @@ +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..00f865e6a 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,23 @@ 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/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 +102,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 +150,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 +185,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..3c15af6d4 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" @@ -50,6 +51,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa inBuf := bufio.NewReader(cmd.InOrStdin()) if err != nil { // attempt to lookup address from Keybase if no address was provided + // nolint: govet kb, err := keys.NewKeyring( sdk.KeyringServiceName(), viper.GetString(flags.FlagKeyringBackend), @@ -72,6 +74,14 @@ 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++ { + // nolint: govet + 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,11 +90,21 @@ 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++ { + // nolint: govet + 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 baseAccount := auth.NewBaseAccount(addr, coins.Sort(), nil, 0, 0) if !vestingAmt.IsZero() { + // nolint: govet baseVestingAccount, err := authvesting.NewBaseVestingAccount(baseAccount, vestingAmt.Sort(), vestingEnd) if err != nil { return fmt.Errorf("failed to create base vesting account: %w", err) @@ -104,6 +124,7 @@ contain valid denominations. Accounts may optionally be supplied with vesting pa genAccount = baseAccount } + // nolint: govet if err := genAccount.Validate(); err != nil { return fmt.Errorf("failed to validate new genesis account: %w", err) } diff --git a/cmd/chain-maind/gentx.go b/cmd/chain-maind/gentx.go new file mode 100644 index 000000000..27a3ef5b8 --- /dev/null +++ b/cmd/chain-maind/gentx.go @@ -0,0 +1,245 @@ +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++ { + // nolint: govet + 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..4b83767e1 --- /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 _, err2 := os.Stat(genFile); err2 != nil { + if !os.IsNotExist(err) { + return err2 + } + } else { + genDoc, err2 = types.GenesisDocFromFile(genFile) + if err2 != nil { + return errors.Wrap(err2, "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 diff --git a/x/chainmain/abci.go b/x/chainmain/abci.go index bf1ef36e3..71a938214 100644 --- a/x/chainmain/abci.go +++ b/x/chainmain/abci.go @@ -2,9 +2,8 @@ package chainmain import ( sdk "github.com/cosmos/cosmos-sdk/types" - abci "github.com/tendermint/tendermint/abci/types" "github.com/crypto-com/chain-main/x/chainmain/keeper" - // abci "github.com/tendermint/tendermint/abci/types" + abci "github.com/tendermint/tendermint/abci/types" ) // BeginBlocker check for infraction evidence or downtime of validators diff --git a/x/chainmain/client/cli/query.go b/x/chainmain/client/cli/query.go index e1356de9b..4a9a1dcdd 100644 --- a/x/chainmain/client/cli/query.go +++ b/x/chainmain/client/cli/query.go @@ -29,7 +29,7 @@ func GetQueryCmd(queryRoute string, cdc *codec.Codec) *cobra.Command { chainmainQueryCmd.AddCommand( flags.GetCommands( - // this line is used by starport scaffolding + // this line is used by starport scaffolding )..., ) diff --git a/x/chainmain/client/cli/tx.go b/x/chainmain/client/cli/tx.go index 5f54a9227..263aeebb8 100644 --- a/x/chainmain/client/cli/tx.go +++ b/x/chainmain/client/cli/tx.go @@ -22,7 +22,7 @@ func GetTxCmd(cdc *codec.Codec) *cobra.Command { } chainmainTxCmd.AddCommand(flags.PostCommands( - // this line is used by starport scaffolding + // this line is used by starport scaffolding )...) return chainmainTxCmd diff --git a/x/chainmain/client/rest/rest.go b/x/chainmain/client/rest/rest.go index 99cb1a657..aebd18363 100644 --- a/x/chainmain/client/rest/rest.go +++ b/x/chainmain/client/rest/rest.go @@ -8,5 +8,5 @@ import ( // RegisterRoutes registers chainmain-related REST handlers to a router func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router) { - // this line is used by starport scaffolding + // this line is used by starport scaffolding } diff --git a/x/chainmain/genesis.go b/x/chainmain/genesis.go index 85665988f..10da1b2c2 100644 --- a/x/chainmain/genesis.go +++ b/x/chainmain/genesis.go @@ -9,8 +9,10 @@ import ( // InitGenesis initialize default parameters // and the keeper's address to pubkey map -func InitGenesis(ctx sdk.Context, k keeper.Keeper /* TODO: Define what keepers the module needs */, data types.GenesisState) { - // TODO: Define logic for when you would like to initalize a new genesis +func InitGenesis(ctx sdk.Context, k keeper.Keeper, + /* TODO: Define what keepers the module needs */ + data types.GenesisState) { + // TODO: Define logic for when you would like to initialize a new genesis } // ExportGenesis writes the current store values diff --git a/x/chainmain/handler.go b/x/chainmain/handler.go index 0f0902c93..a45f91f2c 100644 --- a/x/chainmain/handler.go +++ b/x/chainmain/handler.go @@ -4,17 +4,17 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" "github.com/crypto-com/chain-main/x/chainmain/keeper" "github.com/crypto-com/chain-main/x/chainmain/types" - sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" ) // NewHandler ... func NewHandler(k keeper.Keeper) sdk.Handler { return func(ctx sdk.Context, msg sdk.Msg) (*sdk.Result, error) { ctx = ctx.WithEventManager(sdk.NewEventManager()) - switch msg := msg.(type) { - // this line is used by starport scaffolding + switch msg := msg.(type) { // nolint: gocritic + // this line is used by starport scaffolding default: errMsg := fmt.Sprintf("unrecognized %s message type: %T", types.ModuleName, msg) return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, errMsg) diff --git a/x/chainmain/keeper/params.go b/x/chainmain/keeper/params.go index 9fdeb71eb..035d628ed 100644 --- a/x/chainmain/keeper/params.go +++ b/x/chainmain/keeper/params.go @@ -1,4 +1,5 @@ package keeper + /* // TODO: Define if your module needs Parameters, if not this can be deleted diff --git a/x/chainmain/keeper/querier.go b/x/chainmain/keeper/querier.go index 5cfe12b84..52b84a8d9 100644 --- a/x/chainmain/keeper/querier.go +++ b/x/chainmain/keeper/querier.go @@ -1,7 +1,7 @@ package keeper import ( - // this line is used by starport scaffolding + // this line is used by starport scaffolding abci "github.com/tendermint/tendermint/abci/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -11,10 +11,10 @@ import ( // NewQuerier creates a new querier for chainmain clients. func NewQuerier(k Keeper) sdk.Querier { return func(ctx sdk.Context, path []string, req abci.RequestQuery) ([]byte, error) { - switch path[0] { - // this line is used by starport scaffolding # 2 + switch path[0] { // nolint: gocritic + // this line is used by starport scaffolding # 2 default: return nil, sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown chainmain query endpoint") } } -} \ No newline at end of file +} diff --git a/x/chainmain/module.go b/x/chainmain/module.go index c6d3bd701..7fc93c965 100644 --- a/x/chainmain/module.go +++ b/x/chainmain/module.go @@ -69,7 +69,7 @@ func (AppModuleBasic) GetQueryCmd(cdc *codec.Codec) *cobra.Command { return cli.GetQueryCmd(types.StoreKey, cdc) } -//____________________________________________________________________________ +// ____________________________________________________________________________ // AppModule implements an application module for the chainmain module. type AppModule struct { diff --git a/x/chainmain/types/codec.go b/x/chainmain/types/codec.go index 690c6a00a..1b5fc0ced 100644 --- a/x/chainmain/types/codec.go +++ b/x/chainmain/types/codec.go @@ -6,7 +6,7 @@ import ( // RegisterCodec registers concrete types on codec func RegisterCodec(cdc *codec.Codec) { - // this line is used by starport scaffolding + // this line is used by starport scaffolding } // ModuleCdc defines the module codec diff --git a/x/chainmain/types/params.go b/x/chainmain/types/params.go index 67382d737..db5decd5a 100644 --- a/x/chainmain/types/params.go +++ b/x/chainmain/types/params.go @@ -1,8 +1,6 @@ package types import ( - "fmt" - "github.com/cosmos/cosmos-sdk/x/params" ) @@ -14,8 +12,8 @@ const ( // Parameter store keys var ( - // TODO: Define your keys for the parameter store - // KeyParamName = []byte("ParamName") +// TODO: Define your keys for the parameter store +// KeyParamName = []byte("ParamName") ) // ParamKeyTable for chainmain module @@ -25,12 +23,12 @@ func ParamKeyTable() params.KeyTable { // Params - used for initializing default parameter for chainmain at genesis type Params struct { - // TODO: Add your Paramaters to the Paramter struct + // TODO: Add your Parameters to the Parameter struct // KeyParamName string `json:"key_param_name"` } // NewParams creates a new Params object -func NewParams(/* TODO: Pass in the paramters*/) Params { +func NewParams( /* TODO: Pass in the parameters */ ) Params { return Params{ // TODO: Create your Params Type } @@ -38,9 +36,9 @@ func NewParams(/* TODO: Pass in the paramters*/) Params { // String implements the stringer interface for Params func (p Params) String() string { - return fmt.Sprintf(` + return ` // TODO: Return all the params as a string - `, ) + ` } // ParamSetPairs - Implements params.ParamSet diff --git a/x/chainmain/types/querier.go b/x/chainmain/types/querier.go index 5bb13ecf9..ab1254f4c 100644 --- a/x/chainmain/types/querier.go +++ b/x/chainmain/types/querier.go @@ -1,2 +1 @@ package types - diff --git a/x/chainmain/types/types.go b/x/chainmain/types/types.go index 5bb13ecf9..ab1254f4c 100644 --- a/x/chainmain/types/types.go +++ b/x/chainmain/types/types.go @@ -1,2 +1 @@ package types -