diff --git a/client/keys/utils.go b/client/keys/utils.go index f86389a896..013aa1848b 100644 --- a/client/keys/utils.go +++ b/client/keys/utils.go @@ -24,8 +24,13 @@ var keybase keys.Keybase // initialize a keybase based on the configuration func GetKeyBase() (keys.Keybase, error) { + rootDir := viper.GetString(cli.HomeFlag) + return GetKeyBaseFromDir(rootDir) +} + +// initialize a keybase based on the configuration +func GetKeyBaseFromDir(rootDir string) (keys.Keybase, error) { if keybase == nil { - rootDir := viper.GetString(cli.HomeFlag) db, err := dbm.NewGoLevelDB(KeyDBName, filepath.Join(rootDir, "keys")) if err != nil { return nil, err diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index eb63c6f1a0..9ece80ea7f 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -1,20 +1,14 @@ package app import ( - "encoding/json" - "errors" + "os" - "github.com/spf13/pflag" - "github.com/spf13/viper" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - tmtypes "github.com/tendermint/tendermint/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" bam "github.com/cosmos/cosmos-sdk/baseapp" - "github.com/cosmos/cosmos-sdk/server" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" @@ -27,6 +21,12 @@ const ( appName = "GaiaApp" ) +// default home directories for expected binaries +var ( + DefaultCLIHome = os.ExpandEnv("$HOME/.gaiacli") + DefaultNodeHome = os.ExpandEnv("$HOME/.gaiad") +) + // Extended ABCI application type GaiaApp struct { *bam.BaseApp @@ -153,154 +153,3 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci return abci.ResponseInitChain{} } - -//________________________________________________________________________________________ - -// State to Unmarshal -type GenesisState struct { - Accounts []GenesisAccount `json:"accounts"` - StakeData stake.GenesisState `json:"stake"` -} - -// GenesisAccount doesn't need pubkey or sequence -type GenesisAccount struct { - Address sdk.Address `json:"address"` - Coins sdk.Coins `json:"coins"` -} - -func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { - return GenesisAccount{ - Address: acc.Address, - Coins: acc.Coins, - } -} - -// convert GenesisAccount to auth.BaseAccount -func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { - return &auth.BaseAccount{ - Address: ga.Address, - Coins: ga.Coins.Sort(), - } -} - -var ( - flagName = "name" - //flagOWK = "overwrite-keys" -) - -// get app init parameters for server init command -func GaiaAppInit() server.AppInit { - fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError) - //fsAppGenState.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") - - fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError) - fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator") - - return server.AppInit{ - FlagsAppGenState: fsAppGenState, - FlagsAppGenTx: fsAppGenTx, - AppGenState: GaiaAppGenState, - AppGenTx: GaiaAppGenTx, - } -} - -// simple genesis tx -type GaiaGenTx struct { - Name string `json:"name"` - Address sdk.Address `json:"address"` - PubKey crypto.PubKey `json:"pub_key"` -} - -// power given to validators in gaia init functions -var FreePower = int64(100) - -// Create the core parameters for genesis initialization for gaia -// note that the pubkey input is this machines pubkey -func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { - - if len(appGenTxs) == 0 { - err = errors.New("must provide at least genesis transaction") - return - } - - // start with the default staking genesis state - stakeData := stake.GetDefaultGenesisState() - - // get genesis flag account information - genaccs := make([]GenesisAccount, len(appGenTxs)) - for i, appGenTx := range appGenTxs { - - var genTx GaiaGenTx - err = cdc.UnmarshalJSON(appGenTx, &genTx) - if err != nil { - return - } - - // create the genesis account, give'm few fermions and a buncha token with there name - accAuth := auth.NewBaseAccountWithAddress(genTx.Address) - accAuth.Coins = sdk.Coins{ - {genTx.Name + "Token", 1000}, - {"fermion", 50}, - } - acc := NewGenesisAccount(&accAuth) - genaccs[i] = acc - - // add the validator - if len(genTx.Name) > 0 { - desc := stake.NewDescription(genTx.Name, "", "", "") - candidate := stake.NewCandidate(genTx.Address, genTx.PubKey, desc) - candidate.Assets = sdk.NewRat(FreePower) - stakeData.Candidates = append(stakeData.Candidates, candidate) - - // pool logic - stakeData.Pool.TotalSupply += FreePower - stakeData.Pool.BondedPool += FreePower - stakeData.Pool.BondedShares = sdk.NewRat(stakeData.Pool.BondedPool) - } - } - - // create the final app state - genesisState := GenesisState{ - Accounts: genaccs, - StakeData: stakeData, - } - appState, err = wire.MarshalJSONIndent(cdc, genesisState) - return -} - -// Generate a gaia genesis transaction -func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( - appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { - - var addr sdk.Address - var secret string - addr, secret, err = server.GenerateCoinKey() - if err != nil { - return - } - - var bz []byte - gaiaGenTx := GaiaGenTx{ - Name: viper.GetString(flagName), - Address: addr, - PubKey: pk, - } - bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx) - if err != nil { - return - } - appGenTx = json.RawMessage(bz) - - mm := map[string]string{"secret": secret} - bz, err = cdc.MarshalJSON(mm) - if err != nil { - return - } - cliPrint = json.RawMessage(bz) - - validator = tmtypes.GenesisValidator{ - PubKey: pk, - Power: FreePower, - } - return -} diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go new file mode 100644 index 0000000000..66fd1f98d9 --- /dev/null +++ b/cmd/gaia/app/genesis.go @@ -0,0 +1,175 @@ +package app + +import ( + "encoding/json" + "errors" + + "github.com/spf13/pflag" + "github.com/spf13/viper" + crypto "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" + + "github.com/cosmos/cosmos-sdk/server" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/cosmos/cosmos-sdk/x/stake" +) + +// State to Unmarshal +type GenesisState struct { + Accounts []GenesisAccount `json:"accounts"` + StakeData stake.GenesisState `json:"stake"` +} + +// GenesisAccount doesn't need pubkey or sequence +type GenesisAccount struct { + Address sdk.Address `json:"address"` + Coins sdk.Coins `json:"coins"` +} + +func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { + return GenesisAccount{ + Address: acc.Address, + Coins: acc.Coins, + } +} + +// convert GenesisAccount to auth.BaseAccount +func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { + return &auth.BaseAccount{ + Address: ga.Address, + Coins: ga.Coins.Sort(), + } +} + +var ( + flagName = "name" + flagClientHome = "home-client" + flagOWK = "owk" + + // bonded tokens given to genesis validators/accounts + freeFermionVal = int64(100) + freeFermionsAcc = int64(50) +) + +// get app init parameters for server init command +func GaiaAppInit() server.AppInit { + fsAppGenState := pflag.NewFlagSet("", pflag.ContinueOnError) + + fsAppGenTx := pflag.NewFlagSet("", pflag.ContinueOnError) + fsAppGenTx.String(flagName, "", "validator moniker, if left blank, do not add validator") + fsAppGenTx.String(flagClientHome, DefaultCLIHome, "home directory for the client, used for key generation") + fsAppGenTx.Bool(flagOWK, false, "overwrite the for the accounts created") + + return server.AppInit{ + FlagsAppGenState: fsAppGenState, + FlagsAppGenTx: fsAppGenTx, + AppGenState: GaiaAppGenState, + AppGenTx: GaiaAppGenTx, + } +} + +// simple genesis tx +type GaiaGenTx struct { + Name string `json:"name"` + Address sdk.Address `json:"address"` + PubKey crypto.PubKey `json:"pub_key"` +} + +// power given to validators in gaia init functions + +// Create the core parameters for genesis initialization for gaia +// note that the pubkey input is this machines pubkey +func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { + + if len(appGenTxs) == 0 { + err = errors.New("must provide at least genesis transaction") + return + } + + // start with the default staking genesis state + stakeData := stake.GetDefaultGenesisState() + + // get genesis flag account information + genaccs := make([]GenesisAccount, len(appGenTxs)) + for i, appGenTx := range appGenTxs { + + var genTx GaiaGenTx + err = cdc.UnmarshalJSON(appGenTx, &genTx) + if err != nil { + return + } + + // create the genesis account, give'm few fermions and a buncha token with there name + accAuth := auth.NewBaseAccountWithAddress(genTx.Address) + accAuth.Coins = sdk.Coins{ + {genTx.Name + "Token", 1000}, + {"fermion", freeFermionsAcc}, + } + acc := NewGenesisAccount(&accAuth) + genaccs[i] = acc + stakeData.Pool.TotalSupply += freeFermionsAcc // increase the supply + + // add the validator + if len(genTx.Name) > 0 { + desc := stake.NewDescription(genTx.Name, "", "", "") + candidate := stake.NewCandidate(genTx.Address, genTx.PubKey, desc) + candidate.Assets = sdk.NewRat(freeFermionVal) + stakeData.Candidates = append(stakeData.Candidates, candidate) + + // pool logic + stakeData.Pool.TotalSupply += freeFermionVal + stakeData.Pool.BondedPool += freeFermionVal + stakeData.Pool.BondedShares = sdk.NewRat(stakeData.Pool.BondedPool) + } + } + + // create the final app state + genesisState := GenesisState{ + Accounts: genaccs, + StakeData: stakeData, + } + appState, err = wire.MarshalJSONIndent(cdc, genesisState) + return +} + +// Generate a gaia genesis transaction +func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { + + var addr sdk.Address + var secret string + clientRoot := viper.GetString(flagClientHome) + overwrite := viper.GetBool(flagOWK) + name := viper.GetString(flagName) + addr, secret, err = server.GenerateSaveCoinKey(clientRoot, name, "1234567890", overwrite) + if err != nil { + return + } + + var bz []byte + gaiaGenTx := GaiaGenTx{ + Name: name, + Address: addr, + PubKey: pk, + } + bz, err = wire.MarshalJSONIndent(cdc, gaiaGenTx) + if err != nil { + return + } + appGenTx = json.RawMessage(bz) + + mm := map[string]string{"secret": secret} + bz, err = cdc.MarshalJSON(mm) + if err != nil { + return + } + cliPrint = json.RawMessage(bz) + + validator = tmtypes.GenesisValidator{ + PubKey: pk, + Power: freeFermionVal, + } + return +} diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 00d94861d1..01f2e15631 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -24,7 +24,8 @@ func TestGaiaCLISend(t *testing.T) { pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) - key, chainID := executeInit(t, "gaiad init -o --name=foo") + chainID := executeInit(t, "gaiad init -o --name=foo") + executeWrite(t, "gaiacli keys add bar", pass) // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -34,9 +35,6 @@ func TestGaiaCLISend(t *testing.T) { cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer cmd.Process.Kill() - executeWrite(t, "gaiacli keys add foo --recover", pass, key) - executeWrite(t, "gaiacli keys add bar", pass) - fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") barAddr, _ := executeGetAddrPK(t, "gaiacli keys show bar --output=json") @@ -58,7 +56,8 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) - key, chainID := executeInit(t, "gaiad init -o --name=foo") + chainID := executeInit(t, "gaiad init -o --name=foo") + executeWrite(t, "gaiacli keys add bar", pass) // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -68,8 +67,6 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { cmd, _, _ := tests.GoExecuteT(t, fmt.Sprintf("gaiad start --rpc.laddr=%v", servAddr)) defer cmd.Process.Kill() - executeWrite(t, "gaiacli keys add foo --recover", pass, key) - executeWrite(t, "gaiacli keys add bar", pass) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") barAddr, barPubKey := executeGetAddrPK(t, "gaiacli keys show bar --output=json") @@ -140,7 +137,7 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) { fmt.Printf("debug read: %v\n", string(bz)) } -func executeInit(t *testing.T, cmdStr string) (key, chainID string) { +func executeInit(t *testing.T, cmdStr string) (chainID string) { out := tests.ExecuteT(t, cmdStr) var initRes map[string]json.RawMessage @@ -150,13 +147,6 @@ func executeInit(t *testing.T, cmdStr string) (key, chainID string) { err = json.Unmarshal(initRes["chain_id"], &chainID) require.NoError(t, err) - var appMessageRes map[string]json.RawMessage - err = json.Unmarshal(initRes["app_message"], &appMessageRes) - require.NoError(t, err) - - err = json.Unmarshal(appMessageRes["secret"], &key) - require.NoError(t, err) - return } diff --git a/cmd/gaia/cmd/gaiacli/main.go b/cmd/gaia/cmd/gaiacli/main.go index 8efb9f4dd8..ab0a98c695 100644 --- a/cmd/gaia/cmd/gaiacli/main.go +++ b/cmd/gaia/cmd/gaiacli/main.go @@ -1,8 +1,6 @@ package main import ( - "os" - "github.com/spf13/cobra" "github.com/tendermint/tmlibs/cli" @@ -73,6 +71,6 @@ func main() { ) // prepare and add flags - executor := cli.PrepareMainCmd(rootCmd, "GA", os.ExpandEnv("$HOME/.gaiacli")) + executor := cli.PrepareMainCmd(rootCmd, "GA", app.DefaultCLIHome) executor.Execute() } diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 565cf5ac26..0417671a2f 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -1,7 +1,6 @@ package main import ( - "os" "path/filepath" "github.com/spf13/cobra" @@ -27,8 +26,7 @@ func main() { server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp) // prepare and add flags - rootDir := os.ExpandEnv("$HOME/.gaiad") - executor := cli.PrepareBaseCmd(rootCmd, "GA", rootDir) + executor := cli.PrepareBaseCmd(rootCmd, "GA", app.DefaultNodeHome) executor.Execute() } diff --git a/server/init.go b/server/init.go index 98b724caf5..d23d78b818 100644 --- a/server/init.go +++ b/server/init.go @@ -8,8 +8,6 @@ import ( "path" "path/filepath" - sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/cosmos-sdk/wire" "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/pflag" @@ -22,8 +20,13 @@ import ( "github.com/tendermint/tendermint/p2p" tmtypes "github.com/tendermint/tendermint/types" pvm "github.com/tendermint/tendermint/types/priv_validator" + tmcli "github.com/tendermint/tmlibs/cli" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" + + clkeys "github.com/cosmos/cosmos-sdk/client/keys" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) // genesis piece structure for creating combined genesis @@ -82,7 +85,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { } genTxFile := json.RawMessage(bz) name := fmt.Sprintf("gentx-%v.json", nodeID) - file := filepath.Join(viper.GetString("home"), name) + file := filepath.Join(viper.GetString(tmcli.HomeFlag), name) err = cmn.WriteFile(file, bz, 0644) if err != nil { return err @@ -148,7 +151,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return err } config.P2P.PersistentPeers = persistentPeers - configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get + configFilePath := filepath.Join(viper.GetString(tmcli.HomeFlag), "config", "config.toml") //TODO this is annoying should be easier to get cfg.WriteConfigFile(configFilePath, config) } else { appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey) @@ -165,7 +168,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return err } - err = WriteGenesisFile(cdc, genFile, chainID, validators, appState) + err = writeGenesisFile(cdc, genFile, chainID, validators, appState) if err != nil { return err } @@ -258,7 +261,7 @@ func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { } // create the genesis file -func WriteGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { +func writeGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { genDoc := tmtypes.GenesisDoc{ ChainID: chainID, Validators: validators, @@ -399,3 +402,30 @@ func GenerateCoinKey() (sdk.Address, string, error) { addr := info.PubKey.Address() return addr, secret, nil } + +// GenerateSaveCoinKey returns the address of a public key, along with the secret +// phrase to recover the private key. +func GenerateSaveCoinKey(clientRoot, keyName, keyPass string, overwrite bool) (sdk.Address, string, error) { + + // get the keystore from the client + keybase, err := clkeys.GetKeyBaseFromDir(clientRoot) + if err != nil { + return nil, "", err + } + + // ensure no overwrite + if !overwrite { + _, err := keybase.Get(keyName) + if err == nil { + return nil, "", errors.New("key already exists, overwrite is disabled") + } + } + + // generate a private key, with recovery phrase + info, secret, err := keybase.Create(keyName, keyPass, keys.AlgoEd25519) + if err != nil { + return nil, "", err + } + addr := info.PubKey.Address() + return addr, secret, nil +} diff --git a/server/tm_cmds.go b/server/tm_cmds.go index a876d1bcd3..d581ca5f76 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -36,7 +36,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { flagJSON := "json" cmd := cobra.Command{ Use: "show_validator", - Short: "Show this node's validator info", + Short: "Show this node's tendermint validator info", RunE: func(cmd *cobra.Command, args []string) error { cfg := ctx.Config @@ -67,7 +67,7 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { func UnsafeResetAllCmd(ctx *Context) *cobra.Command { return &cobra.Command{ Use: "unsafe_reset_all", - Short: "Reset all blockchain data", + Short: "Reset blockchain database, priv_validator.json file, and the logger", RunE: func(cmd *cobra.Command, args []string) error { cfg := ctx.Config tcmd.ResetAll(cfg.DBDir(), cfg.PrivValidatorFile(), ctx.Logger)