diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 733482f58802..adfb12d5735d 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -16,6 +16,7 @@ import ( tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/cmd/gaia/app" + gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init" "github.com/cosmos/cosmos-sdk/server" ) @@ -28,8 +29,11 @@ func main() { Short: "Gaia Daemon (server)", PersistentPreRunE: server.PersistentPreRunEFn(ctx), } + appInit := app.GaiaAppInit() + rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit)) + rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit)) - server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), + server.AddCommands(ctx, cdc, rootCmd, appInit, newApp, exportAppStateAndTMValidators) // prepare and add flags diff --git a/cmd/gaia/init/init.go b/cmd/gaia/init/init.go new file mode 100644 index 000000000000..a04c1d2ae77e --- /dev/null +++ b/cmd/gaia/init/init.go @@ -0,0 +1,321 @@ +package init + +import ( + "encoding/json" + "fmt" + "io/ioutil" + "os" + "path" + "path/filepath" + "sort" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + servercfg "github.com/cosmos/cosmos-sdk/server/config" + "github.com/spf13/cobra" + "github.com/spf13/viper" + cfg "github.com/tendermint/tendermint/config" + "github.com/tendermint/tendermint/crypto" + "github.com/tendermint/tendermint/libs/cli" + "github.com/tendermint/tendermint/libs/common" + "github.com/tendermint/tendermint/p2p" + "github.com/tendermint/tendermint/privval" + "github.com/tendermint/tendermint/types" +) + +// get cmd to initialize all files for tendermint and application +func GenTxCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command { + cmd := &cobra.Command{ + Use: "gen-tx", + Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, args []string) error { + config := ctx.Config + config.SetRoot(viper.GetString(cli.HomeFlag)) + + ip := viper.GetString(server.FlagIP) + if len(ip) == 0 { + eip, err := server.ExternalIP() + if err != nil { + return err + } + ip = eip + } + + genTxConfig := servercfg.GenTx{ + viper.GetString(server.FlagName), + viper.GetString(server.FlagClientHome), + viper.GetBool(server.FlagOWK), + ip, + } + cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig) + if err != nil { + return err + } + toPrint := struct { + AppMessage json.RawMessage `json:"app_message"` + GenTxFile json.RawMessage `json:"gen_tx_file"` + }{ + cliPrint, + genTxFile, + } + out, err := codec.MarshalJSONIndent(cdc, toPrint) + if err != nil { + return err + } + fmt.Println(string(out)) + return nil + }, + } + cmd.Flags().String(server.FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) + return cmd +} + +// NOTE: This will update (write) the config file with +// updated name (moniker) for node. +func gentxWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, genTxConfig servercfg.GenTx) ( + cliPrint json.RawMessage, genTxFile json.RawMessage, err error) { + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return + } + nodeID := string(nodeKey.ID()) + pubKey := readOrCreatePrivValidator(config) + + appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) + if err != nil { + return + } + + tx := server.GenesisTx{ + NodeID: nodeID, + IP: genTxConfig.IP, + Validator: validator, + AppGenTx: appGenTx, + } + bz, err := codec.MarshalJSONIndent(cdc, tx) + if err != nil { + return + } + genTxFile = json.RawMessage(bz) + name := fmt.Sprintf("gentx-%v.json", nodeID) + writePath := filepath.Join(config.RootDir, "config", "gentx") + file := filepath.Join(writePath, name) + err = common.EnsureDir(writePath, 0700) + if err != nil { + return + } + err = common.WriteFile(file, bz, 0644) + if err != nil { + return + } + + // Write updated config with moniker + config.Moniker = genTxConfig.Name + configFilePath := filepath.Join(config.RootDir, "config", "config.toml") + cfg.WriteConfigFile(configFilePath, config) + + return +} + +// get cmd to initialize all files for tendermint and application +// nolint: golint +func InitCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command { + cmd := &cobra.Command{ + Use: "init", + Short: "Initialize genesis config, priv-validator file, and p2p-node file", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, _ []string) error { + + config := ctx.Config + config.SetRoot(viper.GetString(cli.HomeFlag)) + initConfig := server.InitConfig{ + viper.GetString(server.FlagChainID), + viper.GetBool(server.FlagWithTxs), + filepath.Join(config.RootDir, "config", "gentx"), + viper.GetBool(server.FlagOverwrite), + } + + chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig) + if err != nil { + return err + } + // print out some key information + toPrint := struct { + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppMessage json.RawMessage `json:"app_message"` + }{ + chainID, + nodeID, + appMessage, + } + out, err := codec.MarshalJSONIndent(cdc, toPrint) + if err != nil { + return err + } + fmt.Println(string(out)) + return nil + }, + } + cmd.Flags().BoolP(server.FlagOverwrite, "o", false, "overwrite the genesis.json file") + cmd.Flags().String(server.FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") + cmd.Flags().Bool(server.FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/") + cmd.Flags().AddFlagSet(appInit.FlagsAppGenState) + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided + cmd.AddCommand(GenTxCmd(ctx, cdc, appInit)) + return cmd +} + +func initWithConfig(cdc *codec.Codec, appInit server.AppInit, config *cfg.Config, initConfig server.InitConfig) ( + chainID string, nodeID string, appMessage json.RawMessage, err error) { + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return + } + nodeID = string(nodeKey.ID()) + pubKey := readOrCreatePrivValidator(config) + + if initConfig.ChainID == "" { + initConfig.ChainID = fmt.Sprintf("test-chain-%v", common.RandStr(6)) + } + chainID = initConfig.ChainID + + genFile := config.GenesisFile() + if !initConfig.Overwrite && common.FileExists(genFile) { + err = fmt.Errorf("genesis.json file already exists: %v", genFile) + return + } + + // process genesis transactions, or otherwise create one for defaults + var appGenTxs []json.RawMessage + var validators []types.GenesisValidator + var persistentPeers string + + if initConfig.GenTxs { + validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc) + if err != nil { + return + } + config.P2P.PersistentPeers = persistentPeers + configFilePath := filepath.Join(config.RootDir, "config", "config.toml") + cfg.WriteConfigFile(configFilePath, config) + } else { + genTxConfig := servercfg.GenTx{ + viper.GetString(server.FlagName), + viper.GetString(server.FlagClientHome), + viper.GetBool(server.FlagOWK), + "127.0.0.1", + } + + // Write updated config with moniker + config.Moniker = genTxConfig.Name + configFilePath := filepath.Join(config.RootDir, "config", "config.toml") + cfg.WriteConfigFile(configFilePath, config) + appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) + appMessage = am + if err != nil { + return "", "", nil, err + } + validators = []types.GenesisValidator{validator} + appGenTxs = []json.RawMessage{appGenTx} + } + + appState, err := appInit.AppGenState(cdc, appGenTxs) + if err != nil { + return + } + + err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState) + if err != nil { + return + } + + return +} + +// append a genesis-piece +func processGenTxs(genTxsDir string, cdc *codec.Codec) ( + validators []types.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { + + var fos []os.FileInfo + fos, err = ioutil.ReadDir(genTxsDir) + if err != nil { + return + } + + genTxs := make(map[string]server.GenesisTx) + var nodeIDs []string + for _, fo := range fos { + filename := path.Join(genTxsDir, fo.Name()) + if !fo.IsDir() && (path.Ext(filename) != ".json") { + continue + } + + // get the genTx + var bz []byte + bz, err = ioutil.ReadFile(filename) + if err != nil { + return + } + var genTx server.GenesisTx + err = cdc.UnmarshalJSON(bz, &genTx) + if err != nil { + return + } + + genTxs[genTx.NodeID] = genTx + nodeIDs = append(nodeIDs, genTx.NodeID) + } + + sort.Strings(nodeIDs) + + for _, nodeID := range nodeIDs { + genTx := genTxs[nodeID] + + // combine some stuff + validators = append(validators, genTx.Validator) + appGenTxs = append(appGenTxs, genTx.AppGenTx) + + // Add a persistent peer + comma := "," + if len(persistentPeers) == 0 { + comma = "" + } + persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP) + } + + return +} + +// read of create the private key file for this config +func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { + // private validator + privValFile := tmConfig.PrivValidatorFile() + var privValidator *privval.FilePV + if common.FileExists(privValFile) { + privValidator = privval.LoadFilePV(privValFile) + } else { + privValidator = privval.GenFilePV(privValFile) + privValidator.Save() + } + return privValidator.GetPubKey() +} + +// writeGenesisFile creates and writes the genesis configuration to disk. An +// error is returned if building or writing the configuration to file fails. +// nolint: unparam +func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []types.GenesisValidator, appState json.RawMessage) error { + genDoc := types.GenesisDoc{ + ChainID: chainID, + Validators: validators, + AppState: appState, + } + + if err := genDoc.ValidateAndComplete(); err != nil { + return err + } + + return genDoc.SaveAs(genesisFile) +} diff --git a/cmd/gaia/init/init_test.go b/cmd/gaia/init/init_test.go new file mode 100644 index 000000000000..3a7f0a358d47 --- /dev/null +++ b/cmd/gaia/init/init_test.go @@ -0,0 +1,111 @@ +package init + +import ( + "bytes" + "io" + "io/ioutil" + "os" + "testing" + "time" + + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/cosmos-sdk/server" + "github.com/cosmos/cosmos-sdk/server/mock" + "github.com/stretchr/testify/require" + abciServer "github.com/tendermint/tendermint/abci/server" + tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" + "github.com/tendermint/tendermint/libs/log" +) + +func TestInitCmd(t *testing.T) { + defer server.SetupViper(t)() + + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := server.NewContext(cfg, logger) + cdc := codec.New() + appInit := server.AppInit{ + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, + } + cmd := InitCmd(ctx, cdc, appInit) + err = cmd.RunE(nil, nil) + require.NoError(t, err) +} + +func TestEmptyState(t *testing.T) { + defer server.SetupViper(t)() + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := server.NewContext(cfg, logger) + cdc := codec.New() + appInit := server.AppInit{ + AppGenTx: mock.AppGenTx, + AppGenState: mock.AppGenStateEmpty, + } + cmd := InitCmd(ctx, cdc, appInit) + err = cmd.RunE(nil, nil) + require.NoError(t, err) + + old := os.Stdout + r, w, _ := os.Pipe() + os.Stdout = w + cmd = server.ExportCmd(ctx, cdc, nil) + err = cmd.RunE(nil, nil) + require.NoError(t, err) + + outC := make(chan string) + go func() { + var buf bytes.Buffer + io.Copy(&buf, r) + outC <- buf.String() + }() + + w.Close() + os.Stdout = old + out := <-outC + require.Contains(t, out, "WARNING: State is not initialized") + require.Contains(t, out, "genesis_time") + require.Contains(t, out, "chain_id") + require.Contains(t, out, "consensus_params") + require.Contains(t, out, "validators") + require.Contains(t, out, "app_hash") +} + +func TestStartStandAlone(t *testing.T) { + home, err := ioutil.TempDir("", "mock-sdk-cmd") + require.Nil(t, err) + defer func() { + os.RemoveAll(home) + }() + + logger := log.NewNopLogger() + cfg, err := tcmd.ParseConfig() + require.Nil(t, err) + ctx := server.NewContext(cfg, logger) + cdc := codec.New() + appInit := server.AppInit{ + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, + } + initCmd := InitCmd(ctx, cdc, appInit) + err = initCmd.RunE(nil, nil) + require.NoError(t, err) + + app, err := mock.NewApp(home, logger) + require.Nil(t, err) + svrAddr, _, err := server.FreeTCPAddr() + require.Nil(t, err) + svr, err := abciServer.NewServer(svrAddr, "socket", app) + require.Nil(t, err, "error creating listener") + svr.SetLogger(logger.With("module", "abci-server")) + svr.Start() + + timer := time.NewTimer(time.Duration(2) * time.Second) + select { + case <-timer.C: + svr.Stop() + } +} diff --git a/server/testnet.go b/cmd/gaia/init/testnet.go similarity index 95% rename from server/testnet.go rename to cmd/gaia/init/testnet.go index f10ea3e7b27a..48b714f2de21 100644 --- a/server/testnet.go +++ b/cmd/gaia/init/testnet.go @@ -1,7 +1,8 @@ -package server +package init import ( "fmt" + "github.com/cosmos/cosmos-sdk/server" "net" "path/filepath" @@ -30,7 +31,7 @@ var ( const nodeDirPerm = 0755 // get cmd to initialize all files for tendermint testnet and application -func TestnetFilesCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command { +func TestnetFilesCmd(ctx *server.Context, cdc *codec.Codec, appInit server.AppInit) *cobra.Command { cmd := &cobra.Command{ Use: "testnet", Short: "Initialize files for a Gaiad testnet", @@ -65,7 +66,7 @@ Example: return cmd } -func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) error { +func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit server.AppInit) error { outDir := viper.GetString(outputDir) numValidators := viper.GetInt(nValidators) @@ -133,7 +134,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) er nodeDaemonHomeName := viper.GetString(nodeDaemonHome) nodeDir := filepath.Join(outDir, nodeDirName, nodeDaemonHomeName) gentxsDir := filepath.Join(outDir, "gentxs") - initConfig := InitConfig{ + initConfig := server.InitConfig{ chainID, true, gentxsDir, @@ -156,7 +157,7 @@ func testnetWithConfig(config *cfg.Config, cdc *codec.Codec, appInit AppInit) er func getIP(i int) (ip string, err error) { ip = viper.GetString(startingIPAddress) if len(ip) == 0 { - ip, err = ExternalIP() + ip, err = server.ExternalIP() if err != nil { return "", err } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 956bc59df363..36219354449b 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -6,6 +6,7 @@ import ( "os" "github.com/cosmos/cosmos-sdk/baseapp" + gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init" "github.com/cosmos/cosmos-sdk/examples/basecoin/app" "github.com/cosmos/cosmos-sdk/server" @@ -28,7 +29,11 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, + appInit := server.DefaultAppInit + rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, appInit)) + rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, appInit)) + + server.AddCommands(ctx, cdc, rootCmd, appInit, newApp, exportAppStateAndTMValidators) // prepare and add flags diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 9f14e8797319..7f8c7c54d17f 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -13,6 +13,7 @@ import ( "github.com/tendermint/tendermint/libs/log" tmtypes "github.com/tendermint/tendermint/types" + gaiaInit "github.com/cosmos/cosmos-sdk/cmd/gaia/init" "github.com/cosmos/cosmos-sdk/codec" "github.com/cosmos/cosmos-sdk/examples/democoin/app" "github.com/cosmos/cosmos-sdk/server" @@ -70,6 +71,9 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } + rootCmd.AddCommand(gaiaInit.InitCmd(ctx, cdc, CoolAppInit)) + rootCmd.AddCommand(gaiaInit.TestnetFilesCmd(ctx, cdc, CoolAppInit)) + server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, newApp, exportAppStateAndTMValidators) diff --git a/server/export_test.go b/server/export_test.go deleted file mode 100644 index 999ba3c00581..000000000000 --- a/server/export_test.go +++ /dev/null @@ -1,53 +0,0 @@ -package server - -import ( - "bytes" - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server/mock" - "github.com/stretchr/testify/require" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tendermint/libs/log" - "io" - "os" - "testing" -) - -func TestEmptyState(t *testing.T) { - defer setupViper(t)() - logger := log.NewNopLogger() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := codec.New() - appInit := AppInit{ - AppGenTx: mock.AppGenTx, - AppGenState: mock.AppGenStateEmpty, - } - cmd := InitCmd(ctx, cdc, appInit) - err = cmd.RunE(nil, nil) - require.NoError(t, err) - - old := os.Stdout - r, w, _ := os.Pipe() - os.Stdout = w - cmd = ExportCmd(ctx, cdc, nil) - err = cmd.RunE(nil, nil) - require.NoError(t, err) - - outC := make(chan string) - go func() { - var buf bytes.Buffer - io.Copy(&buf, r) - outC <- buf.String() - }() - - w.Close() - os.Stdout = old - out := <-outC - require.Contains(t, out, "WARNING: State is not initialized") - require.Contains(t, out, "genesis_time") - require.Contains(t, out, "chain_id") - require.Contains(t, out, "consensus_params") - require.Contains(t, out, "validators") - require.Contains(t, out, "app_hash") -} diff --git a/server/init.go b/server/init.go index 89001e0a4b6c..091ffa9484e6 100644 --- a/server/init.go +++ b/server/init.go @@ -3,26 +3,12 @@ package server import ( "encoding/json" "fmt" - "io/ioutil" - "os" - "path" - "path/filepath" - "sort" - + "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/pkg/errors" - "github.com/spf13/cobra" "github.com/spf13/pflag" - "github.com/spf13/viper" - - "github.com/cosmos/cosmos-sdk/crypto/keys" "github.com/tendermint/tendermint/crypto" - cfg "github.com/tendermint/tendermint/config" - tmcli "github.com/tendermint/tendermint/libs/cli" - cmn "github.com/tendermint/tendermint/libs/common" dbm "github.com/tendermint/tendermint/libs/db" - "github.com/tendermint/tendermint/p2p" - pvm "github.com/tendermint/tendermint/privval" tmtypes "github.com/tendermint/tendermint/types" clkeys "github.com/cosmos/cosmos-sdk/client/keys" @@ -62,304 +48,8 @@ type InitConfig struct { Overwrite bool } -// get cmd to initialize all files for tendermint and application -func GenTxCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command { - cmd := &cobra.Command{ - Use: "gen-tx", - Short: "Create genesis transaction file (under [--home]/config/gentx/gentx-[nodeID].json)", - Args: cobra.NoArgs, - RunE: func(_ *cobra.Command, args []string) error { - config := ctx.Config - config.SetRoot(viper.GetString(tmcli.HomeFlag)) - - ip := viper.GetString(FlagIP) - if len(ip) == 0 { - eip, err := ExternalIP() - if err != nil { - return err - } - ip = eip - } - - genTxConfig := serverconfig.GenTx{ - viper.GetString(FlagName), - viper.GetString(FlagClientHome), - viper.GetBool(FlagOWK), - ip, - } - cliPrint, genTxFile, err := gentxWithConfig(cdc, appInit, config, genTxConfig) - if err != nil { - return err - } - toPrint := struct { - AppMessage json.RawMessage `json:"app_message"` - GenTxFile json.RawMessage `json:"gen_tx_file"` - }{ - cliPrint, - genTxFile, - } - out, err := codec.MarshalJSONIndent(cdc, toPrint) - if err != nil { - return err - } - fmt.Println(string(out)) - return nil - }, - } - cmd.Flags().String(FlagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") - cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) - return cmd -} - -// NOTE: This will update (write) the config file with -// updated name (moniker) for node. -func gentxWithConfig(cdc *codec.Codec, appInit AppInit, config *cfg.Config, genTxConfig serverconfig.GenTx) ( - cliPrint json.RawMessage, genTxFile json.RawMessage, err error) { - nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) - if err != nil { - return - } - nodeID := string(nodeKey.ID()) - pubKey := readOrCreatePrivValidator(config) - - appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) - if err != nil { - return - } - - tx := GenesisTx{ - NodeID: nodeID, - IP: genTxConfig.IP, - Validator: validator, - AppGenTx: appGenTx, - } - bz, err := codec.MarshalJSONIndent(cdc, tx) - if err != nil { - return - } - genTxFile = json.RawMessage(bz) - name := fmt.Sprintf("gentx-%v.json", nodeID) - writePath := filepath.Join(config.RootDir, "config", "gentx") - file := filepath.Join(writePath, name) - err = cmn.EnsureDir(writePath, 0700) - if err != nil { - return - } - err = cmn.WriteFile(file, bz, 0644) - if err != nil { - return - } - - // Write updated config with moniker - config.Moniker = genTxConfig.Name - configFilePath := filepath.Join(config.RootDir, "config", "config.toml") - cfg.WriteConfigFile(configFilePath, config) - - return -} - -// get cmd to initialize all files for tendermint and application -func InitCmd(ctx *Context, cdc *codec.Codec, appInit AppInit) *cobra.Command { - cmd := &cobra.Command{ - Use: "init", - Short: "Initialize genesis config, priv-validator file, and p2p-node file", - Args: cobra.NoArgs, - RunE: func(_ *cobra.Command, _ []string) error { - - config := ctx.Config - config.SetRoot(viper.GetString(tmcli.HomeFlag)) - initConfig := InitConfig{ - viper.GetString(FlagChainID), - viper.GetBool(FlagWithTxs), - filepath.Join(config.RootDir, "config", "gentx"), - viper.GetBool(FlagOverwrite), - } - - chainID, nodeID, appMessage, err := initWithConfig(cdc, appInit, config, initConfig) - if err != nil { - return err - } - // print out some key information - toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - AppMessage json.RawMessage `json:"app_message"` - }{ - chainID, - nodeID, - appMessage, - } - out, err := codec.MarshalJSONIndent(cdc, toPrint) - if err != nil { - return err - } - fmt.Println(string(out)) - return nil - }, - } - cmd.Flags().BoolP(FlagOverwrite, "o", false, "overwrite the genesis.json file") - cmd.Flags().String(FlagChainID, "", "genesis file chain-id, if left blank will be randomly created") - cmd.Flags().Bool(FlagWithTxs, false, "apply existing genesis transactions from [--home]/config/gentx/") - cmd.Flags().AddFlagSet(appInit.FlagsAppGenState) - cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) // need to add this flagset for when no GenTx's provided - cmd.AddCommand(GenTxCmd(ctx, cdc, appInit)) - return cmd -} - -func initWithConfig(cdc *codec.Codec, appInit AppInit, config *cfg.Config, initConfig InitConfig) ( - chainID string, nodeID string, appMessage json.RawMessage, err error) { - nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) - if err != nil { - return - } - nodeID = string(nodeKey.ID()) - pubKey := readOrCreatePrivValidator(config) - - if initConfig.ChainID == "" { - initConfig.ChainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) - } - chainID = initConfig.ChainID - - genFile := config.GenesisFile() - if !initConfig.Overwrite && cmn.FileExists(genFile) { - err = fmt.Errorf("genesis.json file already exists: %v", genFile) - return - } - - // process genesis transactions, or otherwise create one for defaults - var appGenTxs []json.RawMessage - var validators []tmtypes.GenesisValidator - var persistentPeers string - - if initConfig.GenTxs { - validators, appGenTxs, persistentPeers, err = processGenTxs(initConfig.GenTxsDir, cdc) - if err != nil { - return - } - config.P2P.PersistentPeers = persistentPeers - configFilePath := filepath.Join(config.RootDir, "config", "config.toml") - cfg.WriteConfigFile(configFilePath, config) - } else { - genTxConfig := serverconfig.GenTx{ - viper.GetString(FlagName), - viper.GetString(FlagClientHome), - viper.GetBool(FlagOWK), - "127.0.0.1", - } - - // Write updated config with moniker - config.Moniker = genTxConfig.Name - configFilePath := filepath.Join(config.RootDir, "config", "config.toml") - cfg.WriteConfigFile(configFilePath, config) - appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey, genTxConfig) - appMessage = am - if err != nil { - return "", "", nil, err - } - validators = []tmtypes.GenesisValidator{validator} - appGenTxs = []json.RawMessage{appGenTx} - } - - appState, err := appInit.AppGenState(cdc, appGenTxs) - if err != nil { - return - } - - err = writeGenesisFile(cdc, genFile, initConfig.ChainID, validators, appState) - if err != nil { - return - } - - return -} - -// append a genesis-piece -func processGenTxs(genTxsDir string, cdc *codec.Codec) ( - validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { - - var fos []os.FileInfo - fos, err = ioutil.ReadDir(genTxsDir) - if err != nil { - return - } - - genTxs := make(map[string]GenesisTx) - var nodeIDs []string - for _, fo := range fos { - filename := path.Join(genTxsDir, fo.Name()) - if !fo.IsDir() && (path.Ext(filename) != ".json") { - continue - } - - // get the genTx - var bz []byte - bz, err = ioutil.ReadFile(filename) - if err != nil { - return - } - var genTx GenesisTx - err = cdc.UnmarshalJSON(bz, &genTx) - if err != nil { - return - } - - genTxs[genTx.NodeID] = genTx - nodeIDs = append(nodeIDs, genTx.NodeID) - } - - sort.Strings(nodeIDs) - - for _, nodeID := range nodeIDs { - genTx := genTxs[nodeID] - - // combine some stuff - validators = append(validators, genTx.Validator) - appGenTxs = append(appGenTxs, genTx.AppGenTx) - - // Add a persistent peer - comma := "," - if len(persistentPeers) == 0 { - comma = "" - } - persistentPeers += fmt.Sprintf("%s%s@%s:26656", comma, genTx.NodeID, genTx.IP) - } - - return -} - //________________________________________________________________________________________ -// read of create the private key file for this config -func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { - // private validator - privValFile := tmConfig.PrivValidatorFile() - var privValidator *pvm.FilePV - if cmn.FileExists(privValFile) { - privValidator = pvm.LoadFilePV(privValFile) - } else { - privValidator = pvm.GenFilePV(privValFile) - privValidator.Save() - } - return privValidator.GetPubKey() -} - -// writeGenesisFile creates and writes the genesis configuration to disk. An -// error is returned if building or writing the configuration to file fails. -// nolint: unparam -func writeGenesisFile(cdc *codec.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { - genDoc := tmtypes.GenesisDoc{ - ChainID: chainID, - Validators: validators, - AppState: appState, - } - - if err := genDoc.ValidateAndComplete(); err != nil { - return err - } - - return genDoc.SaveAs(genesisFile) -} - //_____________________________________________________________________ // Core functionality passed from the application to the server init command diff --git a/server/init_test.go b/server/init_test.go deleted file mode 100644 index 1913ac671722..000000000000 --- a/server/init_test.go +++ /dev/null @@ -1,47 +0,0 @@ -package server - -import ( - "testing" - - "github.com/stretchr/testify/require" - - "github.com/tendermint/tendermint/libs/log" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server/mock" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" -) - -// TODO update -func TestInitCmd(t *testing.T) { - defer setupViper(t)() - - logger := log.NewNopLogger() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := codec.New() - appInit := AppInit{ - AppGenState: mock.AppGenState, - AppGenTx: mock.AppGenTx, - } - cmd := InitCmd(ctx, cdc, appInit) - err = cmd.RunE(nil, nil) - require.NoError(t, err) -} - -func TestGenTxCmd(t *testing.T) { - // TODO -} - -func TestTestnetFilesCmd(t *testing.T) { - // TODO -} - -func TestSimpleAppGenTx(t *testing.T) { - // TODO -} - -func TestSimpleAppGenState(t *testing.T) { - // TODO -} diff --git a/server/start_test.go b/server/start_test.go deleted file mode 100644 index db9fcd40f840..000000000000 --- a/server/start_test.go +++ /dev/null @@ -1,52 +0,0 @@ -package server - -import ( - "io/ioutil" - "os" - "testing" - "time" - - "github.com/stretchr/testify/require" - - "github.com/cosmos/cosmos-sdk/codec" - "github.com/cosmos/cosmos-sdk/server/mock" - "github.com/tendermint/tendermint/abci/server" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" - "github.com/tendermint/tendermint/libs/log" -) - -func TestStartStandAlone(t *testing.T) { - home, err := ioutil.TempDir("", "mock-sdk-cmd") - require.Nil(t, err) - defer func() { - os.RemoveAll(home) - }() - - logger := log.NewNopLogger() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) - ctx := NewContext(cfg, logger) - cdc := codec.New() - appInit := AppInit{ - AppGenState: mock.AppGenState, - AppGenTx: mock.AppGenTx, - } - initCmd := InitCmd(ctx, cdc, appInit) - err = initCmd.RunE(nil, nil) - require.NoError(t, err) - - app, err := mock.NewApp(home, logger) - require.Nil(t, err) - svrAddr, _, err := FreeTCPAddr() - require.Nil(t, err) - svr, err := server.NewServer(svrAddr, "socket", app) - require.Nil(t, err, "error creating listener") - svr.SetLogger(logger.With("module", "abci-server")) - svr.Start() - - timer := time.NewTimer(time.Duration(2) * time.Second) - select { - case <-timer.C: - svr.Stop() - } -} diff --git a/server/test_helpers.go b/server/test_helpers.go index d1230898ddfd..8de164e08ae4 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -36,9 +36,9 @@ func FreeTCPAddr() (addr, port string, err error) { return } -// setupViper creates a homedir to run inside, +// SetupViper creates a homedir to run inside, // and returns a cleanup function to defer -func setupViper(t *testing.T) func() { +func SetupViper(t *testing.T) func() { rootDir, err := ioutil.TempDir("", "mock-sdk-cmd") require.Nil(t, err) viper.Set(cli.HomeFlag, rootDir) diff --git a/server/util.go b/server/util.go index 51c15e6e82ac..5199c12071e1 100644 --- a/server/util.go +++ b/server/util.go @@ -143,8 +143,6 @@ func AddCommands( ) rootCmd.AddCommand( - InitCmd(ctx, cdc, appInit), - TestnetFilesCmd(ctx, cdc, appInit), StartCmd(ctx, appCreator), UnsafeResetAllCmd(ctx), client.LineBreak,