github.com/cosmos/cosmos-sdk@v0.50.10/x/genutil/client/cli/init.go (about)

     1  package cli
     2  
     3  import (
     4  	"bufio"
     5  	"encoding/json"
     6  	"errors"
     7  	"fmt"
     8  	"os"
     9  	"path/filepath"
    10  
    11  	cfg "github.com/cometbft/cometbft/config"
    12  	"github.com/cosmos/go-bip39"
    13  	"github.com/spf13/cobra"
    14  
    15  	errorsmod "cosmossdk.io/errors"
    16  	"cosmossdk.io/math/unsafe"
    17  
    18  	"github.com/cosmos/cosmos-sdk/client"
    19  	"github.com/cosmos/cosmos-sdk/client/flags"
    20  	"github.com/cosmos/cosmos-sdk/client/input"
    21  	"github.com/cosmos/cosmos-sdk/server"
    22  	sdk "github.com/cosmos/cosmos-sdk/types"
    23  	"github.com/cosmos/cosmos-sdk/types/module"
    24  	"github.com/cosmos/cosmos-sdk/version"
    25  	"github.com/cosmos/cosmos-sdk/x/genutil"
    26  	"github.com/cosmos/cosmos-sdk/x/genutil/types"
    27  )
    28  
    29  const (
    30  	// FlagOverwrite defines a flag to overwrite an existing genesis JSON file.
    31  	FlagOverwrite = "overwrite"
    32  
    33  	// FlagSeed defines a flag to initialize the private validator key from a specific seed.
    34  	FlagRecover = "recover"
    35  
    36  	// FlagDefaultBondDenom defines the default denom to use in the genesis file.
    37  	FlagDefaultBondDenom = "default-denom"
    38  )
    39  
    40  type printInfo struct {
    41  	Moniker    string          `json:"moniker" yaml:"moniker"`
    42  	ChainID    string          `json:"chain_id" yaml:"chain_id"`
    43  	NodeID     string          `json:"node_id" yaml:"node_id"`
    44  	GenTxsDir  string          `json:"gentxs_dir" yaml:"gentxs_dir"`
    45  	AppMessage json.RawMessage `json:"app_message" yaml:"app_message"`
    46  }
    47  
    48  func newPrintInfo(moniker, chainID, nodeID, genTxsDir string, appMessage json.RawMessage) printInfo {
    49  	return printInfo{
    50  		Moniker:    moniker,
    51  		ChainID:    chainID,
    52  		NodeID:     nodeID,
    53  		GenTxsDir:  genTxsDir,
    54  		AppMessage: appMessage,
    55  	}
    56  }
    57  
    58  func displayInfo(info printInfo) error {
    59  	out, err := json.MarshalIndent(info, "", " ")
    60  	if err != nil {
    61  		return err
    62  	}
    63  
    64  	_, err = fmt.Fprintf(os.Stderr, "%s\n", out)
    65  
    66  	return err
    67  }
    68  
    69  // InitCmd returns a command that initializes all files needed for Tendermint
    70  // and the respective application.
    71  func InitCmd(mbm module.BasicManager, defaultNodeHome string) *cobra.Command {
    72  	cmd := &cobra.Command{
    73  		Use:   "init [moniker]",
    74  		Short: "Initialize private validator, p2p, genesis, and application configuration files",
    75  		Long:  `Initialize validators's and node's configuration files.`,
    76  		Args:  cobra.ExactArgs(1),
    77  		RunE: func(cmd *cobra.Command, args []string) error {
    78  			clientCtx := client.GetClientContextFromCmd(cmd)
    79  			cdc := clientCtx.Codec
    80  
    81  			serverCtx := server.GetServerContextFromCmd(cmd)
    82  			config := serverCtx.Config
    83  			config.SetRoot(clientCtx.HomeDir)
    84  
    85  			chainID, _ := cmd.Flags().GetString(flags.FlagChainID)
    86  			switch {
    87  			case chainID != "":
    88  			case clientCtx.ChainID != "":
    89  				chainID = clientCtx.ChainID
    90  			default:
    91  				chainID = fmt.Sprintf("test-chain-%v", unsafe.Str(6))
    92  			}
    93  
    94  			// Get bip39 mnemonic
    95  			var mnemonic string
    96  			recover, _ := cmd.Flags().GetBool(FlagRecover)
    97  			if recover {
    98  				inBuf := bufio.NewReader(cmd.InOrStdin())
    99  				value, err := input.GetString("Enter your bip39 mnemonic", inBuf)
   100  				if err != nil {
   101  					return err
   102  				}
   103  
   104  				mnemonic = value
   105  				if !bip39.IsMnemonicValid(mnemonic) {
   106  					return errors.New("invalid mnemonic")
   107  				}
   108  			}
   109  
   110  			// Get initial height
   111  			initHeight, _ := cmd.Flags().GetInt64(flags.FlagInitHeight)
   112  			if initHeight < 1 {
   113  				initHeight = 1
   114  			}
   115  
   116  			nodeID, _, err := genutil.InitializeNodeValidatorFilesFromMnemonic(config, mnemonic)
   117  			if err != nil {
   118  				return err
   119  			}
   120  
   121  			config.Moniker = args[0]
   122  
   123  			genFile := config.GenesisFile()
   124  			overwrite, _ := cmd.Flags().GetBool(FlagOverwrite)
   125  			defaultDenom, _ := cmd.Flags().GetString(FlagDefaultBondDenom)
   126  
   127  			// use os.Stat to check if the file exists
   128  			_, err = os.Stat(genFile)
   129  			if !overwrite && !os.IsNotExist(err) {
   130  				return fmt.Errorf("genesis.json file already exists: %v", genFile)
   131  			}
   132  
   133  			// Overwrites the SDK default denom for side-effects
   134  			if defaultDenom != "" {
   135  				sdk.DefaultBondDenom = defaultDenom
   136  			}
   137  			appGenState := mbm.DefaultGenesis(cdc)
   138  
   139  			appState, err := json.MarshalIndent(appGenState, "", " ")
   140  			if err != nil {
   141  				return errorsmod.Wrap(err, "Failed to marshal default genesis state")
   142  			}
   143  
   144  			appGenesis := &types.AppGenesis{}
   145  			if _, err := os.Stat(genFile); err != nil {
   146  				if !os.IsNotExist(err) {
   147  					return err
   148  				}
   149  			} else {
   150  				appGenesis, err = types.AppGenesisFromFile(genFile)
   151  				if err != nil {
   152  					return errorsmod.Wrap(err, "Failed to read genesis doc from file")
   153  				}
   154  			}
   155  
   156  			appGenesis.AppName = version.AppName
   157  			appGenesis.AppVersion = version.Version
   158  			appGenesis.ChainID = chainID
   159  			appGenesis.AppState = appState
   160  			appGenesis.InitialHeight = initHeight
   161  			appGenesis.Consensus = &types.ConsensusGenesis{
   162  				Validators: nil,
   163  			}
   164  
   165  			if err = genutil.ExportGenesisFile(appGenesis, genFile); err != nil {
   166  				return errorsmod.Wrap(err, "Failed to export genesis file")
   167  			}
   168  
   169  			toPrint := newPrintInfo(config.Moniker, chainID, nodeID, "", appState)
   170  
   171  			cfg.WriteConfigFile(filepath.Join(config.RootDir, "config", "config.toml"), config)
   172  			return displayInfo(toPrint)
   173  		},
   174  	}
   175  
   176  	cmd.Flags().String(flags.FlagHome, defaultNodeHome, "node's home directory")
   177  	cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file")
   178  	cmd.Flags().Bool(FlagRecover, false, "provide seed phrase to recover existing key instead of creating")
   179  	cmd.Flags().String(flags.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created")
   180  	cmd.Flags().String(FlagDefaultBondDenom, "", "genesis file default denomination, if left blank default value is 'stake'")
   181  	cmd.Flags().Int64(flags.FlagInitHeight, 1, "specify the initial block height at genesis")
   182  
   183  	return cmd
   184  }