From f3fffcb7a27574b58c62ba1e7a2ef09ddffc878d Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 20 Apr 2018 17:42:56 -0400 Subject: [PATCH 01/22] more versatile init --- server/init.go | 88 +++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/server/init.go b/server/init.go index a68566cdf0..c432149be1 100644 --- a/server/init.go +++ b/server/init.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/tendermint/go-crypto/keys" "github.com/tendermint/go-crypto/keys/words" @@ -19,28 +20,15 @@ import ( dbm "github.com/tendermint/tmlibs/db" ) -// testnetInformation contains the info necessary -// to setup a testnet including this account and validator. -type testnetInformation struct { - Secret string `json:"secret"` - - ChainID string `json:"chain_id"` - Account string `json:"account"` - Validator tmtypes.GenesisValidator `json:"validator"` - NodeID p2p.ID `json:"node_id"` -} - type initCmd struct { genAppState GenAppState context *Context } -// InitCmd will initialize all files for tendermint, -// along with proper app_state. -// The application can pass in a function to generate -// proper state. And may want to use GenerateCoinKey -// to create default account(s). -func InitCmd(gen GenAppState, ctx *Context) *cobra.Command { +// InitCmd will initialize all files for tendermint, along with proper +// app_state. The application can pass in a function to generate proper state. +// And may want to use GenerateCoinKey to create default account(s). +func InitCmd(gen GenAppState, fs pflag.FlagSet, ctx *Context) *cobra.Command { cmd := initCmd{ genAppState: gen, context: ctx, @@ -50,12 +38,23 @@ func InitCmd(gen GenAppState, ctx *Context) *cobra.Command { Short: "Initialize genesis files", RunE: cmd.run, } + cobraCmd.Flags().AddFlagSet(fs) return &cobraCmd } +// defaultPrint contains the info necessary +// to setup a testnet including this account and validator. +type defaultPrint struct { + Secret string `json:"secret"` + ChainID string `json:"chain_id"` + Account string `json:"account"` + Validator tmtypes.GenesisValidator `json:"validator"` + NodeID string `json:"node_id"` +} + func (c initCmd) run(cmd *cobra.Command, args []string) error { // Store testnet information as we go - var testnetInfo testnetInformation + var testnetInfo defaultPrint // Run the basic tendermint initialization, // set up a default genesis with no app_options @@ -71,15 +70,13 @@ func (c initCmd) run(cmd *cobra.Command, args []string) error { } // generate secret and address - addr, secret, err := GenerateCoinKey() - if err != nil { - return err - } - - var defaultDenom = "mycoin" + //addr, secret, err := GenerateCoinKey() + //if err != nil { + //return err + //} // Now, we want to add the custom app_state - appState, err := c.genAppState(args, addr, defaultDenom) + appState, err := c.genAppState() if err != nil { return err } @@ -98,6 +95,8 @@ func (c initCmd) run(cmd *cobra.Command, args []string) error { return err } testnetInfo.NodeID = nodeKey.ID() + + // print the output out, err := wire.MarshalJSONIndent(cdc, testnetInfo) if err != nil { return err @@ -108,7 +107,7 @@ func (c initCmd) run(cmd *cobra.Command, args []string) error { // This was copied from tendermint/cmd/tendermint/commands/init.go // so we could pass in the config and the logger. -func (c initCmd) initTendermintFiles(config *cfg.Config, info *testnetInformation) error { +func (c initCmd) initTendermintFiles(config *cfg.Config, info *defaultPrint) error { // private validator privValFile := config.PrivValidatorFile() var privValidator *pvm.FilePV @@ -157,28 +156,31 @@ func (c initCmd) initTendermintFiles(config *cfg.Config, info *testnetInformatio //------------------------------------------------------------------- -// GenAppState takes the command line args, as well -// as an address and coin denomination. -// It returns a default app_state to be included in -// in the genesis file. -// This is application-specific -type GenAppState func(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) +// GenAppState takes the command line args, as well as an address and coin +// denomination. It returns a default app_state to be included in in the +// genesis file. This is application-specific +type GenAppState func() (json.RawMessage, error) -// DefaultGenAppState expects two args: an account address -// and a coin denomination, and gives lots of coins to that address. -func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) { - opts := fmt.Sprintf(`{ +// Create one account with a whole bunch of mycoin in it +func DefaultGenAppState(args []string) (json.RawMessage, error) { + + addr, secret, err := GenerateCoinKey() + if err != nil { + return err + } + + genesisState := fmt.Sprintf(`{ "accounts": [{ "address": "%s", "coins": [ { - "denom": "%s", + "denom": "mycoin", "amount": 9007199254740992 } ] }] - }`, addr.String(), coinDenom) - return json.RawMessage(opts), nil + }`, addr.String()) + return json.RawMessage(genesisState), nil } //------------------------------------------------------------------- @@ -209,12 +211,10 @@ func addGenesisState(filename string, appState json.RawMessage) error { return ioutil.WriteFile(filename, out, 0600) } -//------------------------------------------------------------------- +//_____________________________________________________________________ -// GenerateCoinKey returns the address of a public key, -// along with the secret phrase to recover the private key. -// You can give coins to this address and return the recovery -// phrase to the user to access them. +// GenerateCoinKey returns the address of a public key, along with the secret +// phrase to recover the private key. func GenerateCoinKey() (sdk.Address, string, error) { // construct an in-memory key store codec, err := words.LoadCodec("english") From 6748aa7bc6a4b1f6162e30af6f50d8f564e9108a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Fri, 20 Apr 2018 19:55:22 -0400 Subject: [PATCH 02/22] first stab init refactor --- cmd/gaia/app/app.go | 31 +++-- cmd/gaia/cmd/gaiad/main.go | 2 +- mock/app.go | 24 ++-- server/init.go | 251 ++++++++++++++----------------------- server/test_helpers.go | 2 +- server/util.go | 2 +- 6 files changed, 140 insertions(+), 172 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index fd981a3b5c..6819b67b2b 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -2,13 +2,17 @@ package app import ( "encoding/json" + "fmt" 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" @@ -177,9 +181,24 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { } } -// DefaultGenAppState expects two args: an account address +// GaiaGenAppState expects two args: an account address // and a coin denomination, and gives lots of coins to that address. -func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) { +func GaiaGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { + + var addr sdk.Address + var secret string + addr, secret, err = server.GenerateCoinKey() + if err != nil { + return + } + fmt.Printf("secret recovery key:\n%s\n", secret) + + chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + + validators = []tmtypes.GenesisValidator{{ + PubKey: pubKey, + Power: 10, + }} accAuth := auth.NewBaseAccountWithAddress(addr) accAuth.Coins = sdk.Coins{{"fermion", 100000}} @@ -191,10 +210,6 @@ func DefaultGenAppState(args []string, addr sdk.Address, coinDenom string) (json StakeData: stake.GetDefaultGenesisState(), } - stateBytes, err := json.MarshalIndent(genesisState, "", "\t") - if err != nil { - return nil, err - } - - return stateBytes, nil + appState, err = json.MarshalIndent(genesisState, "", "\t") + return } diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 199a061524..63485433fd 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -36,7 +36,7 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { } func main() { - server.AddCommands(rootCmd, app.DefaultGenAppState, generateApp, context) + server.AddCommands(rootCmd, app.GaiaGenAppState, generateApp, context) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.gaiad") diff --git a/mock/app.go b/mock/app.go index 631cc3c314..462c5564f2 100644 --- a/mock/app.go +++ b/mock/app.go @@ -6,6 +6,9 @@ import ( "path/filepath" 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" @@ -103,11 +106,18 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci } } -// GenInitOptions can be passed into InitCmd, -// returns a static string of a few key-values that can be parsed -// by InitChainer -func GenInitOptions(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) { - opts := []byte(`{ +// GenAppState can be passed into InitCmd, returns a static string of a few +// key-values that can be parsed by InitChainer +func GenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { + + chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + + validators = []tmtypes.GenesisValidator{{ + PubKey: pubKey, + Power: 10, + }} + + appState = json.RawMessage(fmt.Sprintf(`{ "values": [ { "key": "hello", @@ -118,6 +128,6 @@ func GenInitOptions(args []string, addr sdk.Address, coinDenom string) (json.Raw "value": "bar" } ] -}`) - return opts, nil +}`)) + return } diff --git a/server/init.go b/server/init.go index c432149be1..7669e5bc54 100644 --- a/server/init.go +++ b/server/init.go @@ -8,8 +8,8 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/cobra" - "github.com/spf13/pflag" + crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-crypto/keys" "github.com/tendermint/go-crypto/keys/words" cfg "github.com/tendermint/tendermint/config" @@ -20,183 +20,91 @@ import ( dbm "github.com/tendermint/tmlibs/db" ) -type initCmd struct { - genAppState GenAppState - context *Context -} - -// InitCmd will initialize all files for tendermint, along with proper -// app_state. The application can pass in a function to generate proper state. -// And may want to use GenerateCoinKey to create default account(s). -func InitCmd(gen GenAppState, fs pflag.FlagSet, ctx *Context) *cobra.Command { - cmd := initCmd{ - genAppState: gen, - context: ctx, - } +// get cmd to initialize all files for tendermint and application +func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { cobraCmd := cobra.Command{ Use: "init", Short: "Initialize genesis files", - RunE: cmd.run, + RunE: func(cmd *cobra.Command, args []string) error { + + config := ctx.Config + pubkey := ReadOrCreatePrivValidator(config) + + chainID, validators, appState, err := gen(pubkey) + if err != nil { + return err + } + + err = CreateGenesisFile(config, chainID, validators, appState) + if err != nil { + return err + } + + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return err + } + + // print out some key information + toPrint := struct { + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + }{ + chainID, + string(nodeKey.ID()), + } + out, err := wire.MarshalJSONIndent(cdc, toPrint) + if err != nil { + return err + } + fmt.Println(string(out)) + return nil + }, } - cobraCmd.Flags().AddFlagSet(fs) return &cobraCmd } -// defaultPrint contains the info necessary -// to setup a testnet including this account and validator. -type defaultPrint struct { - Secret string `json:"secret"` - ChainID string `json:"chain_id"` - Account string `json:"account"` - Validator tmtypes.GenesisValidator `json:"validator"` - NodeID string `json:"node_id"` -} - -func (c initCmd) run(cmd *cobra.Command, args []string) error { - // Store testnet information as we go - var testnetInfo defaultPrint - - // Run the basic tendermint initialization, - // set up a default genesis with no app_options - config := c.context.Config - err := c.initTendermintFiles(config, &testnetInfo) - if err != nil { - return err - } - - // no app_options, leave like tendermint - if c.genAppState == nil { - return nil - } - - // generate secret and address - //addr, secret, err := GenerateCoinKey() - //if err != nil { - //return err - //} - - // Now, we want to add the custom app_state - appState, err := c.genAppState() - if err != nil { - return err - } - - testnetInfo.Secret = secret - testnetInfo.Account = addr.String() - - // And add them to the genesis file - genFile := config.GenesisFile() - if err := addGenesisState(genFile, appState); err != nil { - return err - } - - nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) - if err != nil { - return err - } - testnetInfo.NodeID = nodeKey.ID() - - // print the output - out, err := wire.MarshalJSONIndent(cdc, testnetInfo) - if err != nil { - return err - } - fmt.Println(string(out)) - return nil -} - -// This was copied from tendermint/cmd/tendermint/commands/init.go -// so we could pass in the config and the logger. -func (c initCmd) initTendermintFiles(config *cfg.Config, info *defaultPrint) error { +// read of create the private key file for this config +func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { // private validator - privValFile := config.PrivValidatorFile() + privValFile := tmConfig.PrivValidatorFile() var privValidator *pvm.FilePV if cmn.FileExists(privValFile) { privValidator = pvm.LoadFilePV(privValFile) - c.context.Logger.Info("Found private validator", "path", privValFile) } else { privValidator = pvm.GenFilePV(privValFile) privValidator.Save() - c.context.Logger.Info("Generated private validator", "path", privValFile) } + return privValidator.GetPubKey() +} - // genesis file - genFile := config.GenesisFile() +// create the genesis file +func CreateGenesisFile(tmConfig *cfg.Config, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { + genFile := tmConfig.GenesisFile() if cmn.FileExists(genFile) { - c.context.Logger.Info("Found genesis file", "path", genFile) - } else { - genDoc := tmtypes.GenesisDoc{ - ChainID: cmn.Fmt("test-chain-%v", cmn.RandStr(6)), - } - genDoc.Validators = []tmtypes.GenesisValidator{{ - PubKey: privValidator.GetPubKey(), - Power: 10, - }} - - if err := genDoc.SaveAs(genFile); err != nil { - return err - } - c.context.Logger.Info("Generated genesis file", "path", genFile) + return fmt.Errorf("genesis config file already exists: %v", genFile) } - - // reload the config file and find our validator info - loadedDoc, err := tmtypes.GenesisDocFromFile(genFile) - if err != nil { + genDoc := tmtypes.GenesisDoc{ + ChainID: chainID, + Validators: validators, + } + if err := genDoc.ValidateAndComplete(); err != nil { return err } - for _, validator := range loadedDoc.Validators { - if validator.PubKey == privValidator.GetPubKey() { - info.Validator = validator - } + if err := genDoc.SaveAs(genFile); err != nil { + return err } - info.ChainID = loadedDoc.ChainID - - return nil + return addAppStateToGenesis(genFile, appState) } -//------------------------------------------------------------------- - -// GenAppState takes the command line args, as well as an address and coin -// denomination. It returns a default app_state to be included in in the -// genesis file. This is application-specific -type GenAppState func() (json.RawMessage, error) - -// Create one account with a whole bunch of mycoin in it -func DefaultGenAppState(args []string) (json.RawMessage, error) { - - addr, secret, err := GenerateCoinKey() +// Add one line to the genesis file +func addAppStateToGenesis(genesisConfigPath string, appState json.RawMessage) error { + bz, err := ioutil.ReadFile(genesisConfigPath) if err != nil { return err } - genesisState := fmt.Sprintf(`{ - "accounts": [{ - "address": "%s", - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - }] - }`, addr.String()) - return json.RawMessage(genesisState), nil -} - -//------------------------------------------------------------------- - -// GenesisDoc involves some tendermint-specific structures we don't -// want to parse, so we just grab it into a raw object format, -// so we can add one line. -type GenesisDoc map[string]json.RawMessage - -func addGenesisState(filename string, appState json.RawMessage) error { - bz, err := ioutil.ReadFile(filename) - if err != nil { - return err - } - - var doc GenesisDoc + var doc map[string]json.RawMessage err = cdc.UnmarshalJSON(bz, &doc) if err != nil { return err @@ -207,15 +115,51 @@ func addGenesisState(filename string, appState json.RawMessage) error { if err != nil { return err } - - return ioutil.WriteFile(filename, out, 0600) + return ioutil.WriteFile(genesisConfigPath, out, 0600) } //_____________________________________________________________________ +// GenAppParams creates the core parameters initialization. It takes in a +// pubkey meant to represent the pubkey of the validator of this machine. +type GenAppParams func(crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) + +// Create one account with a whole bunch of mycoin in it +func SimpleGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { + + var addr sdk.Address + var secret string + addr, secret, err = GenerateCoinKey() + if err != nil { + return + } + fmt.Printf("secret recovery key:\n%s\n", secret) + + chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + + validators = []tmtypes.GenesisValidator{{ + PubKey: pubKey, + Power: 10, + }} + + appState = json.RawMessage(fmt.Sprintf(`{ + "accounts": [{ + "address": "%s", + "coins": [ + { + "denom": "mycoin", + "amount": 9007199254740992 + } + ] + }] +}`, addr.String())) + return +} + // GenerateCoinKey returns the address of a public key, along with the secret // phrase to recover the private key. func GenerateCoinKey() (sdk.Address, string, error) { + // construct an in-memory key store codec, err := words.LoadCodec("english") if err != nil { @@ -231,7 +175,6 @@ func GenerateCoinKey() (sdk.Address, string, error) { if err != nil { return nil, "", err } - addr := info.PubKey.Address() return addr, secret, nil } diff --git a/server/test_helpers.go b/server/test_helpers.go index f226ba1b1f..01a093f47c 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -50,7 +50,7 @@ func StartServer(t *testing.T) chan error { // init server ctx := NewContext(cfg, log.NewNopLogger()) - initCmd := InitCmd(mock.GenInitOptions, ctx) + initCmd := InitCmd(mock.GenAppState, ctx) err = initCmd.RunE(nil, nil) require.NoError(t, err) diff --git a/server/util.go b/server/util.go index cf37ec5cc4..83f22db82e 100644 --- a/server/util.go +++ b/server/util.go @@ -63,7 +63,7 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error // add server commands func AddCommands( rootCmd *cobra.Command, - appState GenAppState, appCreator AppCreator, + appState GenAppParams, appCreator AppCreator, context *Context) { rootCmd.PersistentFlags().String("log_level", context.Config.LogLevel, "Log level") From 55c1e1dcfc4c38fa997fcb184f85f272e100f784 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sat, 21 Apr 2018 22:26:46 -0400 Subject: [PATCH 03/22] init refactor --- cmd/gaia/app/app.go | 8 +++-- cmd/gaia/cmd/gaiad/main.go | 20 +++++------ examples/basecoin/cmd/basecoind/main.go | 29 ++++++++------- examples/democoin/cmd/democoind/main.go | 46 +++++++++++------------- mock/app.go | 14 ++++---- mock/app_test.go | 9 +++-- server/init.go | 37 +++++++++---------- server/init_test.go | 2 +- server/start.go | 47 ++++++++++--------------- server/start_test.go | 6 ++-- server/test_helpers.go | 37 +++++++++---------- server/util.go | 34 +++++++++++++----- server/util_test.go | 43 ++++++++++++++++++++++ 13 files changed, 187 insertions(+), 145 deletions(-) create mode 100644 server/util_test.go diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 6819b67b2b..b09bd7159a 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -2,7 +2,6 @@ package app import ( "encoding/json" - "fmt" abci "github.com/tendermint/abci/types" crypto "github.com/tendermint/go-crypto" @@ -183,7 +182,7 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { // GaiaGenAppState expects two args: an account address // and a coin denomination, and gives lots of coins to that address. -func GaiaGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { +func GaiaGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { var addr sdk.Address var secret string @@ -191,7 +190,10 @@ func GaiaGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes if err != nil { return } - fmt.Printf("secret recovery key:\n%s\n", secret) + + mm := map[string]string{"secret": secret} + bz, err := cdc.MarshalJSON(mm) + message = json.RawMessage(bz) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 63485433fd..8231c4d428 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -15,16 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) -// rootCmd is the entry point for this binary -var ( - context = server.NewDefaultContext() - rootCmd = &cobra.Command{ - Use: "gaiad", - Short: "Gaia Daemon (server)", - PersistentPreRunE: server.PersistentPreRunEFn(context), - } -) - func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { dataDir := filepath.Join(rootDir, "data") db, err := dbm.NewGoLevelDB("gaia", dataDir) @@ -36,7 +26,15 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { } func main() { - server.AddCommands(rootCmd, app.GaiaGenAppState, generateApp, context) + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + rootCmd := &cobra.Command{ + Use: "gaiad", + Short: "Gaia Daemon (server)", + PersistentPreRunE: server.PersistentPreRunEFn(ctx), + } + + server.AddCommands(ctx, cdc, rootCmd, app.GaiaGenAppState, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.gaiad") diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 37eb7d58f4..7d74473008 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -15,15 +15,23 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) -// rootCmd is the entry point for this binary -var ( - context = server.NewDefaultContext() - rootCmd = &cobra.Command{ +func main() { + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + + rootCmd := &cobra.Command{ Use: "basecoind", Short: "Basecoin Daemon (server)", - PersistentPreRunE: server.PersistentPreRunEFn(context), + PersistentPreRunE: server.PersistentPreRunEFn(ctx), } -) + + server.AddCommands(ctx, cdc, rootCmd, server.SimpleGenAppState, generateApp) + + // prepare and add flags + rootDir := os.ExpandEnv("$HOME/.basecoind") + executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) + executor.Execute() +} func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { dataDir := filepath.Join(rootDir, "data") @@ -34,12 +42,3 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { bapp := app.NewBasecoinApp(logger, db) return bapp, nil } - -func main() { - server.AddCommands(rootCmd, server.DefaultGenAppState, generateApp, context) - - // prepare and add flags - rootDir := os.ExpandEnv("$HOME/.basecoind") - executor := cli.PrepareBaseCmd(rootCmd, "BC", rootDir) - executor.Execute() -} diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 8f8bb5a905..0255156298 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -8,42 +8,29 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" + tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" "github.com/cosmos/cosmos-sdk/examples/democoin/app" "github.com/cosmos/cosmos-sdk/server" - sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) -// rootCmd is the entry point for this binary -var ( - context = server.NewDefaultContext() - rootCmd = &cobra.Command{ - Use: "democoind", - Short: "Democoin Daemon (server)", - PersistentPreRunE: server.PersistentPreRunEFn(context), - } -) - -// defaultAppState sets up the app_state for the -// default genesis file -func defaultAppState(args []string, addr sdk.Address, coinDenom string) (json.RawMessage, error) { - baseJSON, err := server.DefaultGenAppState(args, addr, coinDenom) +// coolGenAppState sets up the app_state and appends the cool app state +func CoolGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { + chainID, validators, appState, message, err = server.SimpleGenAppState(cdc, pubKey) if err != nil { - return nil, err + return } - var jsonMap map[string]json.RawMessage - err = json.Unmarshal(baseJSON, &jsonMap) - if err != nil { - return nil, err - } - jsonMap["cool"] = json.RawMessage(`{ + key := "cool" + value := json.RawMessage(`{ "trend": "ice-cold" }`) - bz, err := json.Marshal(jsonMap) - return json.RawMessage(bz), err + appState, err = server.AppendJSON(cdc, appState, key, value) + return } func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { @@ -56,7 +43,16 @@ func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { } func main() { - server.AddCommands(rootCmd, defaultAppState, generateApp, context) + cdc := app.MakeCodec() + ctx := server.NewDefaultContext() + + rootCmd := &cobra.Command{ + Use: "democoind", + Short: "Democoin Daemon (server)", + PersistentPreRunE: server.PersistentPreRunEFn(ctx), + } + + server.AddCommands(ctx, cdc, rootCmd, CoolGenAppState, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/mock/app.go b/mock/app.go index 462c5564f2..c687d6d4b4 100644 --- a/mock/app.go +++ b/mock/app.go @@ -14,11 +14,11 @@ import ( bam "github.com/cosmos/cosmos-sdk/baseapp" sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/wire" ) -// NewApp creates a simple mock kvstore app for testing. -// It should work similar to a real app. -// Make sure rootDir is empty before running the test, +// NewApp creates a simple mock kvstore app for testing. It should work +// similar to a real app. Make sure rootDir is empty before running the test, // in order to guarantee consistent results func NewApp(rootDir string, logger log.Logger) (abci.Application, error) { db, err := dbm.NewGoLevelDB("mock", filepath.Join(rootDir, "data")) @@ -108,16 +108,16 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci // GenAppState can be passed into InitCmd, returns a static string of a few // key-values that can be parsed by InitChainer -func GenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { +func GenAppState(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { - chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + chainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) validators = []tmtypes.GenesisValidator{{ PubKey: pubKey, Power: 10, }} - appState = json.RawMessage(fmt.Sprintf(`{ + appState = json.RawMessage(`{ "values": [ { "key": "hello", @@ -128,6 +128,6 @@ func GenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.Gen "value": "bar" } ] -}`)) +}`) return } diff --git a/mock/app_test.go b/mock/app_test.go index 18449631c6..099808ee2d 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -7,6 +7,7 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" + crypto "github.com/tendermint/go-crypto" ) // TestInitApp makes sure we can initialize this thing without an error @@ -21,9 +22,13 @@ func TestInitApp(t *testing.T) { require.NoError(t, err) // initialize it future-way - opts, err := GenInitOptions(nil, nil, "") + pubKey := crypto.GenPrivKeyEd25519().PubKey() + _, _, appState, _, err := GenAppState(nil, pubKey) require.NoError(t, err) - req := abci.RequestInitChain{AppStateBytes: opts} + //TODO test validators in the init chain? + req := abci.RequestInitChain{ + AppStateBytes: appState, + } app.InitChain(req) app.Commit() diff --git a/server/init.go b/server/init.go index 7669e5bc54..139a9937de 100644 --- a/server/init.go +++ b/server/init.go @@ -21,7 +21,7 @@ import ( ) // get cmd to initialize all files for tendermint and application -func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { +func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { cobraCmd := cobra.Command{ Use: "init", Short: "Initialize genesis files", @@ -30,12 +30,12 @@ func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { config := ctx.Config pubkey := ReadOrCreatePrivValidator(config) - chainID, validators, appState, err := gen(pubkey) + chainID, validators, appState, message, err := gen(cdc, pubkey) if err != nil { return err } - err = CreateGenesisFile(config, chainID, validators, appState) + err = CreateGenesisFile(config, cdc, chainID, validators, appState) if err != nil { return err } @@ -47,11 +47,13 @@ func InitCmd(gen GenAppParams, ctx *Context) *cobra.Command { // print out some key information toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + Message json.RawMessage `json:"message"` }{ chainID, string(nodeKey.ID()), + message, } out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { @@ -79,7 +81,7 @@ func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { } // create the genesis file -func CreateGenesisFile(tmConfig *cfg.Config, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { +func CreateGenesisFile(tmConfig *cfg.Config, cdc *wire.Codec, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { genFile := tmConfig.GenesisFile() if cmn.FileExists(genFile) { return fmt.Errorf("genesis config file already exists: %v", genFile) @@ -94,24 +96,16 @@ func CreateGenesisFile(tmConfig *cfg.Config, chainID string, validators []tmtype if err := genDoc.SaveAs(genFile); err != nil { return err } - return addAppStateToGenesis(genFile, appState) + return addAppStateToGenesis(cdc, genFile, appState) } // Add one line to the genesis file -func addAppStateToGenesis(genesisConfigPath string, appState json.RawMessage) error { +func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState json.RawMessage) error { bz, err := ioutil.ReadFile(genesisConfigPath) if err != nil { return err } - - var doc map[string]json.RawMessage - err = cdc.UnmarshalJSON(bz, &doc) - if err != nil { - return err - } - - doc["app_state"] = appState - out, err := wire.MarshalJSONIndent(cdc, doc) + out, err := AppendJSON(cdc, bz, "app_state", appState) if err != nil { return err } @@ -122,10 +116,10 @@ func addAppStateToGenesis(genesisConfigPath string, appState json.RawMessage) er // GenAppParams creates the core parameters initialization. It takes in a // pubkey meant to represent the pubkey of the validator of this machine. -type GenAppParams func(crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) +type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) // Create one account with a whole bunch of mycoin in it -func SimpleGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage, err error) { +func SimpleGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { var addr sdk.Address var secret string @@ -133,7 +127,10 @@ func SimpleGenAppState(pubKey crypto.PubKey) (chainID string, validators []tmtyp if err != nil { return } - fmt.Printf("secret recovery key:\n%s\n", secret) + + mm := map[string]string{"secret": secret} + bz, err := cdc.MarshalJSON(mm) + message = json.RawMessage(bz) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) diff --git a/server/init_test.go b/server/init_test.go index 19e6695193..a035a3077d 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -18,7 +18,7 @@ func TestInit(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - cmd := InitCmd(mock.GenInitOptions, ctx) + cmd := InitCmd(ctx, cdc, mock.GenAppState) err = cmd.RunE(nil, nil) require.NoError(t, err) } diff --git a/server/start.go b/server/start.go index a4ff9852e5..c9a38abdff 100644 --- a/server/start.go +++ b/server/start.go @@ -27,45 +27,34 @@ type AppCreator func(string, log.Logger) (abci.Application, error) // StartCmd runs the service passed in, either // stand-alone, or in-process with tendermint -func StartCmd(app AppCreator, ctx *Context) *cobra.Command { - start := startCmd{ - appCreator: app, - context: ctx, - } +func StartCmd(ctx *Context, appCreator AppCreator) *cobra.Command { cmd := &cobra.Command{ Use: "start", Short: "Run the full node", - RunE: start.run, + RunE: func(cmd *cobra.Command, args []string) error { + if !viper.GetBool(flagWithTendermint) { + ctx.Logger.Info("Starting ABCI without Tendermint") + return startStandAlone(ctx, appCreator) + } + ctx.Logger.Info("Starting ABCI with Tendermint") + return startInProcess(ctx, appCreator) + }, } + // basic flags for abci app cmd.Flags().Bool(flagWithTendermint, true, "run abci app embedded in-process with tendermint") cmd.Flags().String(flagAddress, "tcp://0.0.0.0:46658", "Listen address") - // AddNodeFlags adds support for all - // tendermint-specific command line options + // AddNodeFlags adds support for all tendermint-specific command line options tcmd.AddNodeFlags(cmd) return cmd } -type startCmd struct { - appCreator AppCreator - context *Context -} - -func (s startCmd) run(cmd *cobra.Command, args []string) error { - if !viper.GetBool(flagWithTendermint) { - s.context.Logger.Info("Starting ABCI without Tendermint") - return s.startStandAlone() - } - s.context.Logger.Info("Starting ABCI with Tendermint") - return s.startInProcess() -} - -func (s startCmd) startStandAlone() error { +func startStandAlone(ctx *Context, appCreator AppCreator) error { // Generate the app in the proper dir addr := viper.GetString(flagAddress) home := viper.GetString("home") - app, err := s.appCreator(home, s.context.Logger) + app, err := appCreator(home, ctx.Logger) if err != nil { return err } @@ -74,7 +63,7 @@ func (s startCmd) startStandAlone() error { if err != nil { return errors.Errorf("Error creating listener: %v\n", err) } - svr.SetLogger(s.context.Logger.With("module", "abci-server")) + svr.SetLogger(ctx.Logger.With("module", "abci-server")) svr.Start() // Wait forever @@ -85,10 +74,10 @@ func (s startCmd) startStandAlone() error { return nil } -func (s startCmd) startInProcess() error { - cfg := s.context.Config +func startInProcess(ctx *Context, appCreator AppCreator) error { + cfg := ctx.Config home := cfg.RootDir - app, err := s.appCreator(home, s.context.Logger) + app, err := appCreator(home, ctx.Logger) if err != nil { return err } @@ -99,7 +88,7 @@ func (s startCmd) startInProcess() error { proxy.NewLocalClientCreator(app), node.DefaultGenesisDocProviderFunc(cfg), node.DefaultDBProvider, - s.context.Logger.With("module", "node")) + ctx.Logger.With("module", "node")) if err != nil { return err } diff --git a/server/start_test.go b/server/start_test.go index ec6c886b11..f8ac5f709e 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -25,7 +25,7 @@ func TestStartStandAlone(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(mock.GenInitOptions, ctx) + initCmd := InitCmd(ctx, cdc, mock.GenAppState) err = initCmd.RunE(nil, nil) require.NoError(t, err) @@ -51,13 +51,13 @@ func TestStartWithTendermint(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(mock.GenInitOptions, ctx) + initCmd := InitCmd(ctx, cdc, mock.GenAppState) err = initCmd.RunE(nil, nil) require.NoError(t, err) // set up app and start up viper.Set(flagWithTendermint, true) - startCmd := StartCmd(mock.NewApp, ctx) + startCmd := StartCmd(ctx, mock.NewApp) startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address timeout := time.Duration(5) * time.Second diff --git a/server/test_helpers.go b/server/test_helpers.go index 01a093f47c..6855f0e927 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -8,13 +8,10 @@ import ( "testing" "time" - "github.com/cosmos/cosmos-sdk/mock" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/stretchr/testify/require" - tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tmlibs/cli" - "github.com/tendermint/tmlibs/log" ) // Get a free address for a test tendermint server @@ -42,27 +39,27 @@ func setupViper(t *testing.T) func() { // Begin the server pass up the channel to close // NOTE pass up the channel so it can be closed at the end of the process -func StartServer(t *testing.T) chan error { - defer setupViper(t)() +//func StartServer(t *testing.T, cdc *wire.Codec) chan error { +//defer setupViper(t)() - cfg, err := tcmd.ParseConfig() - require.Nil(t, err) +//cfg, err := tcmd.ParseConfig() +//require.Nil(t, err) - // init server - ctx := NewContext(cfg, log.NewNopLogger()) - initCmd := InitCmd(mock.GenAppState, ctx) - err = initCmd.RunE(nil, nil) - require.NoError(t, err) +//// init server +//ctx := NewContext(cfg, log.NewNopLogger()) +//initCmd := InitCmd(ctx, cdc, mock.GenAppState) +//err = initCmd.RunE(nil, nil) +//require.NoError(t, err) - // start server - viper.Set(flagWithTendermint, true) - startCmd := StartCmd(mock.NewApp, ctx) - startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address - startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address - timeout := time.Duration(3) * time.Second +//// start server +//viper.Set(flagWithTendermint, true) +//startCmd := StartCmd(mock.NewApp, ctx) +//startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address +//startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address +//timeout := time.Duration(3) * time.Second - return RunOrTimeout(startCmd, timeout, t) -} +//return RunOrTimeout(startCmd, timeout, t) +//} // Run or Timout RunE of command passed in func RunOrTimeout(cmd *cobra.Command, timeout time.Duration, t *testing.T) chan error { diff --git a/server/util.go b/server/util.go index 83f22db82e..1d60428b58 100644 --- a/server/util.go +++ b/server/util.go @@ -1,12 +1,14 @@ package server import ( + "encoding/json" "os" "github.com/spf13/cobra" "github.com/spf13/viper" "github.com/cosmos/cosmos-sdk/version" + "github.com/cosmos/cosmos-sdk/wire" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" cfg "github.com/tendermint/tendermint/config" "github.com/tendermint/tmlibs/cli" @@ -31,7 +33,7 @@ func NewContext(config *cfg.Config, logger log.Logger) *Context { return &Context{config, logger} } -//-------------------------------------------------------------------- +//___________________________________________________________________________________ // PersistentPreRunEFn returns a PersistentPreRunE function for cobra // that initailizes the passed in context with a properly configured @@ -62,18 +64,32 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error // add server commands func AddCommands( + ctx *Context, cdc *wire.Codec, rootCmd *cobra.Command, - appState GenAppParams, appCreator AppCreator, - context *Context) { + appState GenAppParams, appCreator AppCreator) { - rootCmd.PersistentFlags().String("log_level", context.Config.LogLevel, "Log level") + rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") rootCmd.AddCommand( - InitCmd(appState, context), - StartCmd(appCreator, context), - UnsafeResetAllCmd(context), - ShowNodeIDCmd(context), - ShowValidatorCmd(context), + InitCmd(ctx, cdc, appState), + StartCmd(ctx, appCreator), + UnsafeResetAllCmd(ctx), + ShowNodeIDCmd(ctx), + ShowValidatorCmd(ctx), version.VersionCmd, ) } + +//___________________________________________________________________________________ + +// append a new json field to existing json message +func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { + var jsonMap map[string]json.RawMessage + err = cdc.UnmarshalJSON(baseJSON, &jsonMap) + if err != nil { + return nil, err + } + jsonMap[key] = value + bz, err := wire.MarshalJSONIndent(cdc, jsonMap) + return json.RawMessage(bz), err +} diff --git a/server/util_test.go b/server/util_test.go new file mode 100644 index 0000000000..5345b0f8f3 --- /dev/null +++ b/server/util_test.go @@ -0,0 +1,43 @@ +package server + +import ( + "encoding/json" + "testing" + + "github.com/cosmos/cosmos-sdk/wire" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +//func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { + +func TestAppendJSON(t *testing.T) { + + foo := map[string]string{"foo": "foofoo"} + bar := map[string]string{"barInner": "barbar"} + + // create raw messages + bz, err := cdc.MarshalJSON(foo) + require.NoError(t, err) + fooRaw := json.RawMessage(bz) + + bz, err = cdc.MarshalJSON(bar) + require.NoError(t, err) + barRaw := json.RawMessage(bz) + + // make the append + cdc := wire.NewCodec() + appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw) + require.NoError(t, err) + + // test the append + var appended map[string]json.RawMessage + err = cdc.UnmarshalJSON(appBz, &appended) + require.NoError(t, err) + + var resBar map[string]string + err = cdc.UnmarshalJSON(appended["barOuter"], &resBar) + require.NoError(t, err) + + assert.Equal(t, bar, resBar, "appended: %v", appended) +} From d4c2d6fd4cea11ec2b67f30f77fb6f02c8e66a3a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sun, 22 Apr 2018 00:57:53 -0400 Subject: [PATCH 04/22] fix cli tests --- cmd/gaia/cli_test/cli_test.go | 44 ++++++++++++++----------- examples/basecoin/cmd/basecoind/main.go | 2 +- examples/democoin/cmd/democoind/main.go | 2 +- server/init.go | 36 +++++++++++--------- 4 files changed, 47 insertions(+), 37 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 827c7116b4..07028ba16b 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -3,7 +3,6 @@ package clitest import ( "encoding/json" "fmt" - "strings" "testing" "time" @@ -24,7 +23,7 @@ func TestGaiaCLISend(t *testing.T) { pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) - masterKey, chainID := executeInit(t, "gaiad init") + masterKey, chainID := executeInit(t, "gaiad init -o") // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -57,7 +56,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) - masterKey, chainID := executeInit(t, "gaiad init") + masterKey, chainID := executeInit(t, "gaiad init -o") // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -90,19 +89,19 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { // TODO timeout issues if not connected to the internet // unbond a single share - unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) - unbondStr += fmt.Sprintf(" --name=%v", "foo") - unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) - unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr) - unbondStr += fmt.Sprintf(" --shares=%v", "1") - unbondStr += fmt.Sprintf(" --sequence=%v", "1") - fmt.Printf("debug unbondStr: %v\n", unbondStr) - executeWrite(t, unbondStr, pass) - time.Sleep(time.Second * 3) // waiting for some blocks to pass - fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion")) - candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) - assert.Equal(t, int64(2), candidate.Assets.Evaluate()) + //unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) + //unbondStr += fmt.Sprintf(" --name=%v", "foo") + //unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) + //unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr) + //unbondStr += fmt.Sprintf(" --shares=%v", "1") + //unbondStr += fmt.Sprintf(" --sequence=%v", "1") + //fmt.Printf("debug unbondStr: %v\n", unbondStr) + //executeWrite(t, unbondStr, pass) + //time.Sleep(time.Second * 3) // waiting for some blocks to pass + //fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) + //assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion")) + //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) + //assert.Equal(t, int64(2), candidate.Assets.Evaluate()) } func executeWrite(t *testing.T, cmdStr string, writes ...string) { @@ -131,15 +130,20 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) { func executeInit(t *testing.T, cmdStr string) (masterKey, chainID string) { out := tests.ExecuteT(t, cmdStr, 1) - outCut := "{" + strings.SplitN(out, "{", 2)[1] // weird I'm sorry var initRes map[string]json.RawMessage - err := json.Unmarshal([]byte(outCut), &initRes) - require.NoError(t, err) - err = json.Unmarshal(initRes["secret"], &masterKey) + err := json.Unmarshal([]byte(out), &initRes) require.NoError(t, err) + 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"], &masterKey) + require.NoError(t, err) return } diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 7d74473008..02f2c80652 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -25,7 +25,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, server.SimpleGenAppState, generateApp) + server.AddCommands(ctx, cdc, rootCmd, server.SimpleGenAppParams, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 0255156298..93602023a1 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -21,7 +21,7 @@ import ( // coolGenAppState sets up the app_state and appends the cool app state func CoolGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { - chainID, validators, appState, message, err = server.SimpleGenAppState(cdc, pubKey) + chainID, validators, appState, message, err = server.SimpleGenAppParams(cdc, pubKey) if err != nil { return } diff --git a/server/init.go b/server/init.go index 139a9937de..fc80b495fd 100644 --- a/server/init.go +++ b/server/init.go @@ -8,6 +8,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/cobra" + "github.com/spf13/viper" crypto "github.com/tendermint/go-crypto" "github.com/tendermint/go-crypto/keys" @@ -22,6 +23,8 @@ import ( // get cmd to initialize all files for tendermint and application func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { + flagOverwrite := "overwrite" + cobraCmd := cobra.Command{ Use: "init", Short: "Initialize genesis files", @@ -30,12 +33,17 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { config := ctx.Config pubkey := ReadOrCreatePrivValidator(config) - chainID, validators, appState, message, err := gen(cdc, pubkey) + chainID, validators, appState, cliPrint, err := gen(cdc, pubkey) if err != nil { return err } - err = CreateGenesisFile(config, cdc, chainID, validators, appState) + genFile := config.GenesisFile() + if !viper.GetBool(flagOverwrite) && cmn.FileExists(genFile) { + return fmt.Errorf("genesis config file already exists: %v", genFile) + } + + err = WriteGenesisFile(cdc, genFile, chainID, validators, appState) if err != nil { return err } @@ -47,13 +55,13 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { // print out some key information toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - Message json.RawMessage `json:"message"` + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppMessage json.RawMessage `json:"app_message"` }{ chainID, string(nodeKey.ID()), - message, + cliPrint, } out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { @@ -63,6 +71,8 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { return nil }, } + + cobraCmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") return &cobraCmd } @@ -81,11 +91,7 @@ func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { } // create the genesis file -func CreateGenesisFile(tmConfig *cfg.Config, cdc *wire.Codec, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { - genFile := tmConfig.GenesisFile() - if cmn.FileExists(genFile) { - return fmt.Errorf("genesis config file already exists: %v", genFile) - } +func WriteGenesisFile(cdc *wire.Codec, genesisFile, chainID string, validators []tmtypes.GenesisValidator, appState json.RawMessage) error { genDoc := tmtypes.GenesisDoc{ ChainID: chainID, Validators: validators, @@ -93,10 +99,10 @@ func CreateGenesisFile(tmConfig *cfg.Config, cdc *wire.Codec, chainID string, va if err := genDoc.ValidateAndComplete(); err != nil { return err } - if err := genDoc.SaveAs(genFile); err != nil { + if err := genDoc.SaveAs(genesisFile); err != nil { return err } - return addAppStateToGenesis(cdc, genFile, appState) + return addAppStateToGenesis(cdc, genesisFile, appState) } // Add one line to the genesis file @@ -119,7 +125,7 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) // Create one account with a whole bunch of mycoin in it -func SimpleGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { +func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { var addr sdk.Address var secret string @@ -130,7 +136,7 @@ func SimpleGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, v mm := map[string]string{"secret": secret} bz, err := cdc.MarshalJSON(mm) - message = json.RawMessage(bz) + cliPrint = json.RawMessage(bz) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) From 246e4bdac3432e3f730ead6219bf2cc480c10bfb Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sun, 22 Apr 2018 01:32:47 -0400 Subject: [PATCH 05/22] renames --- CHANGELOG.md | 2 +- cmd/gaia/app/app.go | 15 +++++++++++---- cmd/gaia/cmd/gaiad/main.go | 22 +++++++++++----------- examples/democoin/cmd/democoind/main.go | 8 ++++---- mock/app.go | 4 ++-- mock/app_test.go | 2 +- server/init.go | 2 +- server/init_test.go | 2 +- server/start_test.go | 4 ++-- server/test_helpers.go | 2 +- server/tm_cmds.go | 4 ++++ server/wire.go | 12 ------------ 12 files changed, 39 insertions(+), 40 deletions(-) delete mode 100644 server/wire.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 076129dbc1..618db746aa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -74,7 +74,7 @@ BREAKING CHANGES to allow mounting multiple stores with their own DB until they can share one * [x/staking] Renamed to `simplestake` * [builder] Functions don't take `passphrase` as argument -* [server] GenAppState returns generated seed and address +* [server] GenAppParams returns generated seed and address * [basecoind] `init` command outputs JSON of everything necessary for testnet * [basecoind] `basecoin.db -> data/basecoin.db` * [basecli] `data/keys.db -> keys/keys.db` diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index b09bd7159a..1ab0c7c19d 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -180,9 +180,16 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { } } -// GaiaGenAppState expects two args: an account address -// and a coin denomination, and gives lots of coins to that address. -func GaiaGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { +// XXX func GeneratePiece +// XXX func AddPiece + +// Create the core parameters for genesis initialization for gaia +func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { + + // XXX what's the best way to pass around this information? have special flagset defined here? + // add keys to accounts (flag) + // generate X accounts each with X money + // generate X number of validators each bonded with X amount of token var addr sdk.Address var secret string @@ -193,7 +200,7 @@ func GaiaGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, val mm := map[string]string{"secret": secret} bz, err := cdc.MarshalJSON(mm) - message = json.RawMessage(bz) + cliPrint = json.RawMessage(bz) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 8231c4d428..1637a80852 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -15,16 +15,6 @@ import ( "github.com/cosmos/cosmos-sdk/server" ) -func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { - dataDir := filepath.Join(rootDir, "data") - db, err := dbm.NewGoLevelDB("gaia", dataDir) - if err != nil { - return nil, err - } - bapp := app.NewGaiaApp(logger, db) - return bapp, nil -} - func main() { cdc := app.MakeCodec() ctx := server.NewDefaultContext() @@ -34,10 +24,20 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, app.GaiaGenAppState, generateApp) + server.AddCommands(ctx, cdc, rootCmd, app.GaiaGenAppParams, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.gaiad") executor := cli.PrepareBaseCmd(rootCmd, "GA", rootDir) executor.Execute() } + +func generateApp(rootDir string, logger log.Logger) (abci.Application, error) { + dataDir := filepath.Join(rootDir, "data") + db, err := dbm.NewGoLevelDB("gaia", dataDir) + if err != nil { + return nil, err + } + bapp := app.NewGaiaApp(logger, db) + return bapp, nil +} diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 93602023a1..7cfd55e916 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -19,9 +19,9 @@ import ( "github.com/cosmos/cosmos-sdk/wire" ) -// coolGenAppState sets up the app_state and appends the cool app state -func CoolGenAppState(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { - chainID, validators, appState, message, err = server.SimpleGenAppParams(cdc, pubKey) +// coolGenAppParams sets up the app_state and appends the cool app state +func CoolGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { + chainID, validators, appState, cliPrint, err = server.SimpleGenAppParams(cdc, pubKey) if err != nil { return } @@ -52,7 +52,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, CoolGenAppState, generateApp) + server.AddCommands(ctx, cdc, rootCmd, CoolGenAppParams, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/mock/app.go b/mock/app.go index c687d6d4b4..09f09b830c 100644 --- a/mock/app.go +++ b/mock/app.go @@ -106,9 +106,9 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci } } -// GenAppState can be passed into InitCmd, returns a static string of a few +// GenAppParams can be passed into InitCmd, returns a static string of a few // key-values that can be parsed by InitChainer -func GenAppState(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) { +func GenAppParams(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { chainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) diff --git a/mock/app_test.go b/mock/app_test.go index 099808ee2d..fe0948a84c 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -23,7 +23,7 @@ func TestInitApp(t *testing.T) { // initialize it future-way pubKey := crypto.GenPrivKeyEd25519().PubKey() - _, _, appState, _, err := GenAppState(nil, pubKey) + _, _, appState, _, err := GenAppParams(nil, pubKey) require.NoError(t, err) //TODO test validators in the init chain? req := abci.RequestInitChain{ diff --git a/server/init.go b/server/init.go index fc80b495fd..14635a9410 100644 --- a/server/init.go +++ b/server/init.go @@ -122,7 +122,7 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js // GenAppParams creates the core parameters initialization. It takes in a // pubkey meant to represent the pubkey of the validator of this machine. -type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, message json.RawMessage, err error) +type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) // Create one account with a whole bunch of mycoin in it func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { diff --git a/server/init_test.go b/server/init_test.go index a035a3077d..e4bf8c0169 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -18,7 +18,7 @@ func TestInit(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - cmd := InitCmd(ctx, cdc, mock.GenAppState) + cmd := InitCmd(ctx, cdc, mock.GenAppParams) err = cmd.RunE(nil, nil) require.NoError(t, err) } diff --git a/server/start_test.go b/server/start_test.go index f8ac5f709e..9cbd456616 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -25,7 +25,7 @@ func TestStartStandAlone(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(ctx, cdc, mock.GenAppState) + initCmd := InitCmd(ctx, cdc, mock.GenAppParams) err = initCmd.RunE(nil, nil) require.NoError(t, err) @@ -51,7 +51,7 @@ func TestStartWithTendermint(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(ctx, cdc, mock.GenAppState) + initCmd := InitCmd(ctx, cdc, mock.GenAppParams) err = initCmd.RunE(nil, nil) require.NoError(t, err) diff --git a/server/test_helpers.go b/server/test_helpers.go index 6855f0e927..55b6caf43b 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -47,7 +47,7 @@ func setupViper(t *testing.T) func() { //// init server //ctx := NewContext(cfg, log.NewNopLogger()) -//initCmd := InitCmd(ctx, cdc, mock.GenAppState) +//initCmd := InitCmd(ctx, cdc, mock.GenAppParams) //err = initCmd.RunE(nil, nil) //require.NoError(t, err) diff --git a/server/tm_cmds.go b/server/tm_cmds.go index 73dca6651e..a876d1bcd3 100644 --- a/server/tm_cmds.go +++ b/server/tm_cmds.go @@ -5,6 +5,7 @@ import ( "fmt" "strings" + "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -43,6 +44,9 @@ func ShowValidatorCmd(ctx *Context) *cobra.Command { pubKey := privValidator.PubKey if viper.GetBool(flagJSON) { + + cdc := wire.NewCodec() + wire.RegisterCrypto(cdc) pubKeyJSONBytes, err := cdc.MarshalJSON(pubKey) if err != nil { return err diff --git a/server/wire.go b/server/wire.go deleted file mode 100644 index 261e7cfe1e..0000000000 --- a/server/wire.go +++ /dev/null @@ -1,12 +0,0 @@ -package server - -import ( - "github.com/cosmos/cosmos-sdk/wire" -) - -var cdc *wire.Codec - -func init() { - cdc = wire.NewCodec() - wire.RegisterCrypto(cdc) -} From 867d0e502ca5c7d605230189e58da8dcecc505fc Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Sun, 22 Apr 2018 13:36:35 -0400 Subject: [PATCH 06/22] working genesis pieces --- cmd/gaia/app/app.go | 1 - server/init.go | 112 ++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 1ab0c7c19d..61242b0393 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -180,7 +180,6 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { } } -// XXX func GeneratePiece // XXX func AddPiece // Create the core parameters for genesis initialization for gaia diff --git a/server/init.go b/server/init.go index 14635a9410..de2bc94282 100644 --- a/server/init.go +++ b/server/init.go @@ -4,6 +4,9 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" + "path" + "path/filepath" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" @@ -21,14 +24,14 @@ import ( dbm "github.com/tendermint/tmlibs/db" ) +// TODO flag to retrieve genesis file / config file from a URL? // get cmd to initialize all files for tendermint and application -func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { - flagOverwrite := "overwrite" - - cobraCmd := cobra.Command{ +func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState AppendAppState) *cobra.Command { + flagOverwrite, flagAppendFile := "overwrite", "piece-file" + cmd := &cobra.Command{ Use: "init", - Short: "Initialize genesis files", - RunE: func(cmd *cobra.Command, args []string) error { + Short: "Initialize genesis config, priv-validator file, and p2p-node file", + RunE: func(_ *cobra.Command, _ []string) error { config := ctx.Config pubkey := ReadOrCreatePrivValidator(config) @@ -72,10 +75,100 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams) *cobra.Command { }, } - cobraCmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") - return &cobraCmd + cmd.AddCommand(FromPiecesCmd(ctx, cdc, appendState)) + cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") + cmd.Flags().BoolP(flagAppendFile, "a", false, "create an append file for others to import") + return cmd } +// genesis piece structure for creating combined genesis +type GenesisPiece struct { + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppState json.RawMessage `json:"app_state"` + Validators []tmtypes.GenesisValidator `json:"validators"` +} + +// get cmd to initialize all files for tendermint and application +func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *cobra.Command { + return &cobra.Command{ + Use: "from-pieces [directory]", + Short: "Create genesis from directory of genesis pieces", + Args: cobra.ExactArgs(1), + RunE: func(_ *cobra.Command, args []string) error { + pieceDir := args[0] + + // ensure that the privVal and nodeKey file already exist + config := ctx.Config + privValFile := config.PrivValidatorFile() + nodeKeyFile := config.NodeKeyFile() + genFile := config.GenesisFile() + if !cmn.FileExists(privValFile) { + return fmt.Errorf("privVal file must already exist, please initialize with init cmd: %v", privValFile) + } + if !cmn.FileExists(nodeKeyFile) { + return fmt.Errorf("nodeKey file must already exist, please initialize with init cmd: %v", nodeKeyFile) + } + cmn.FileExists(genFile) + + // XXX remove the existing gen config file + + // deterministically walk the directory for genesis-piece files to import + filepath.Walk(pieceDir, appendPiece(cdc, appendState, nodeKeyFile, genFile)) + + return nil + }, + } +} + +// append a genesis-piece +func appendPiece(cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFile string) filepath.WalkFunc { + return func(filePath string, _ os.FileInfo, err error) error { + if err != nil { + return err + } + if path.Ext(filePath) != "json" { + return nil + } + + // XXX get the file bytes + var bz []byte + + // get the piece + var piece GenesisPiece + err = cdc.UnmarshalJSON(bz, &piece) + if err != nil { + return err + } + + // if the first file, create the genesis from scratch with piece inputs + if !cmn.FileExists(genFile) { + return WriteGenesisFile(cdc, genFile, piece.chainID, piece.validators, piece.appState) + } + + // XXX read in the genFile + + // XXX verify chain-ids are the same + // XXX combine the validator set + var validators []tmtypes.GenesisValidator + + // combine the app state + appState, err := appendState(appState, piece.AppState) + if err != nil { + return err + } + + // write the appended genesis file + return WriteGenesisFile(cdc, genFile, piece.chainID, validators, appState) + + // XXX read in nodeKey and combine new nodeID file + + return nil + } +} + +//________________________________________________________________________________________ + // read of create the private key file for this config func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { // private validator @@ -124,6 +217,9 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js // pubkey meant to represent the pubkey of the validator of this machine. type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) +// append appState1 with appState2 +type AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMesssage) (appState json.RawMessage, err error) + // Create one account with a whole bunch of mycoin in it func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { From 556896679a49c0aeecce02f41fe36409a82b332a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 23 Apr 2018 11:47:39 -0400 Subject: [PATCH 07/22] ... --- client/tx/query.go | 5 +-- server/init.go | 60 ++++++++++++++++++-------- server/util.go | 2 +- x/auth/client/cli/account.go | 83 ++++++++++++++---------------------- 4 files changed, 77 insertions(+), 73 deletions(-) diff --git a/client/tx/query.go b/client/tx/query.go index 0583f94f5b..2078b78831 100644 --- a/client/tx/query.go +++ b/client/tx/query.go @@ -8,7 +8,6 @@ import ( "strconv" "github.com/gorilla/mux" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" abci "github.com/tendermint/abci/types" @@ -25,10 +24,8 @@ func QueryTxCmd(cdc *wire.Codec) *cobra.Command { cmd := &cobra.Command{ Use: "tx [hash]", Short: "Matches this txhash over all committed blocks", + Args: cobra.ExactArgs(1), RunE: func(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide a tx hash") - } // find the key to look up the account hashHexStr := args[0] diff --git a/server/init.go b/server/init.go index de2bc94282..0ce6ad50b2 100644 --- a/server/init.go +++ b/server/init.go @@ -31,6 +31,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append 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 @@ -74,10 +75,11 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append return nil }, } - - cmd.AddCommand(FromPiecesCmd(ctx, cdc, appendState)) + if appendState != nil { + cmd.AddCommand(FromPiecesCmd(ctx, cdc, appendState)) + cmd.Flags().BoolP(flagAppendFile, "a", false, "create an append file for others to import") + } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") - cmd.Flags().BoolP(flagAppendFile, "a", false, "create an append file for others to import") return cmd } @@ -102,16 +104,16 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *c config := ctx.Config privValFile := config.PrivValidatorFile() nodeKeyFile := config.NodeKeyFile() - genFile := config.GenesisFile() if !cmn.FileExists(privValFile) { return fmt.Errorf("privVal file must already exist, please initialize with init cmd: %v", privValFile) } if !cmn.FileExists(nodeKeyFile) { return fmt.Errorf("nodeKey file must already exist, please initialize with init cmd: %v", nodeKeyFile) } - cmn.FileExists(genFile) - // XXX remove the existing gen config file + // remove genFile for creation + genFile := config.GenesisFile() + os.Remove(genFile) // deterministically walk the directory for genesis-piece files to import filepath.Walk(pieceDir, appendPiece(cdc, appendState, nodeKeyFile, genFile)) @@ -123,16 +125,19 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *c // append a genesis-piece func appendPiece(cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFile string) filepath.WalkFunc { - return func(filePath string, _ os.FileInfo, err error) error { + return func(pieceFile string, _ os.FileInfo, err error) error { if err != nil { return err } - if path.Ext(filePath) != "json" { + if path.Ext(pieceFile) != "json" { return nil } - // XXX get the file bytes - var bz []byte + // get the piece file bytes + bz, err := ioutil.ReadFile(pieceFile) + if err != nil { + return err + } // get the piece var piece GenesisPiece @@ -143,25 +148,44 @@ func appendPiece(cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFi // if the first file, create the genesis from scratch with piece inputs if !cmn.FileExists(genFile) { - return WriteGenesisFile(cdc, genFile, piece.chainID, piece.validators, piece.appState) + return WriteGenesisFile(cdc, genFile, piece.ChainID, piece.Validators, piece.AppState) } - // XXX read in the genFile + // read in the genFile + bz, err = ioutil.ReadFile(genFile) + if err != nil { + return err + } + var genMap map[string]json.RawMessage + err = cdc.UnmarshalJSON(bz, &genMap) + if err != nil { + return err + } + appState := genMap["app_state"] - // XXX verify chain-ids are the same - // XXX combine the validator set + // verify chain-ids are the same + if piece.ChainID != string(genMap["chain_id"]) { + return fmt.Errorf("piece chain id's are mismatched, %s != %s", piece.ChainID, genMap["chain_id"]) + } + + // combine the validator set var validators []tmtypes.GenesisValidator + err = cdc.UnmarshalJSON(genMap["validators"], &validators) + if err != nil { + return err + } + validators = append(validators, piece.Validators...) // combine the app state - appState, err := appendState(appState, piece.AppState) + appState, err = appendState(cdc, appState, piece.AppState) if err != nil { return err } // write the appended genesis file - return WriteGenesisFile(cdc, genFile, piece.chainID, validators, appState) + return WriteGenesisFile(cdc, genFile, piece.ChainID, validators, appState) - // XXX read in nodeKey and combine new nodeID file + // XXX XXX XXX read in configTOMBL and combine new nodeID file return nil } @@ -218,7 +242,7 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) // append appState1 with appState2 -type AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMesssage) (appState json.RawMessage, err error) +type AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) // Create one account with a whole bunch of mycoin in it func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { diff --git a/server/util.go b/server/util.go index 1d60428b58..4b34d0383f 100644 --- a/server/util.go +++ b/server/util.go @@ -71,7 +71,7 @@ func AddCommands( rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") rootCmd.AddCommand( - InitCmd(ctx, cdc, appState), + InitCmd(ctx, cdc, appState, nil), StartCmd(ctx, appCreator), UnsafeResetAllCmd(ctx), ShowNodeIDCmd(ctx), diff --git a/x/auth/client/cli/account.go b/x/auth/client/cli/account.go index c6c8c6c548..b45cb12ddf 100644 --- a/x/auth/client/cli/account.go +++ b/x/auth/client/cli/account.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "fmt" - "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/cosmos/cosmos-sdk/client/context" @@ -32,56 +31,40 @@ func GetAccountDecoder(cdc *wire.Codec) sdk.AccountDecoder { // GetAccountCmd returns a query account that will display the // state of the account at a given address func GetAccountCmd(storeName string, cdc *wire.Codec, decoder sdk.AccountDecoder) *cobra.Command { - cmdr := commander{ - storeName, - cdc, - decoder, - } return &cobra.Command{ - Use: "account
", + Use: "account [address]", Short: "Query account balance", - RunE: cmdr.getAccountCmd, + Args: cobra.ExactArgs(1), + RunE: func(cmd *cobra.Command, args []string) error { + + // find the key to look up the account + addr := args[0] + bz, err := hex.DecodeString(addr) + if err != nil { + return err + } + key := sdk.Address(bz) + + // perform query + ctx := context.NewCoreContextFromViper() + res, err := ctx.Query(key, storeName) + if err != nil { + return err + } + + // decode the value + account, err := decoder(res) + if err != nil { + return err + } + + // print out whole account + output, err := wire.MarshalJSONIndent(cdc, account) + if err != nil { + return err + } + fmt.Println(string(output)) + return nil + }, } } - -type commander struct { - storeName string - cdc *wire.Codec - decoder sdk.AccountDecoder -} - -func (c commander) getAccountCmd(cmd *cobra.Command, args []string) error { - if len(args) != 1 || len(args[0]) == 0 { - return errors.New("You must provide an account name") - } - - // find the key to look up the account - addr := args[0] - bz, err := hex.DecodeString(addr) - if err != nil { - return err - } - key := sdk.Address(bz) - - ctx := context.NewCoreContextFromViper() - - res, err := ctx.Query(key, c.storeName) - if err != nil { - return err - } - - // decode the value - account, err := c.decoder(res) - if err != nil { - return err - } - - // print out whole account - output, err := wire.MarshalJSONIndent(c.cdc, account) - if err != nil { - return err - } - fmt.Println(string(output)) - - return nil -} From c8f5fcb27b26d2a4132d6871ccfbf670b09f4fef Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 23 Apr 2018 15:15:50 -0400 Subject: [PATCH 08/22] init append functionality complete --- server/init.go | 48 ++++++++++++++++++++++++++++++++++++++------ server/init_test.go | 4 +++- server/start_test.go | 7 +++++-- server/util.go | 41 +++++++++++++++++++++++++++++++++++++ server/util_test.go | 2 +- 5 files changed, 92 insertions(+), 10 deletions(-) diff --git a/server/init.go b/server/init.go index 0ce6ad50b2..3e8e0da4a6 100644 --- a/server/init.go +++ b/server/init.go @@ -27,7 +27,7 @@ import ( // TODO flag to retrieve genesis file / config file from a URL? // get cmd to initialize all files for tendermint and application func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState AppendAppState) *cobra.Command { - flagOverwrite, flagAppendFile := "overwrite", "piece-file" + flagOverwrite, flagPieceFile := "overwrite", "piece-file" cmd := &cobra.Command{ Use: "init", Short: "Initialize genesis config, priv-validator file, and p2p-node file", @@ -56,15 +56,17 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append if err != nil { return err } + nodeID := string(nodeKey.ID()) // print out some key information + toPrint := struct { ChainID string `json:"chain_id"` NodeID string `json:"node_id"` AppMessage json.RawMessage `json:"app_message"` }{ chainID, - string(nodeKey.ID()), + nodeID, cliPrint, } out, err := wire.MarshalJSONIndent(cdc, toPrint) @@ -72,12 +74,35 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append return err } fmt.Println(string(out)) + + // write the piece file is path specified + pieceFile := viper.GetString(flagPieceFile) + if len(pieceFile) > 0 { + //create the piece + ip, err := externalIP() + if err != nil { + return err + } + piece := GenesisPiece{ + ChainID: chainID, + NodeID: nodeID, + IP: ip, + AppState: appState, + Validators: validators, + } + bz, err := cdc.MarshalJSON(piece) + if err != nil { + return err + } + return cmn.WriteFile(pieceFile, bz, 0644) + } + return nil }, } if appendState != nil { cmd.AddCommand(FromPiecesCmd(ctx, cdc, appendState)) - cmd.Flags().BoolP(flagAppendFile, "a", false, "create an append file for others to import") + cmd.Flags().StringP(flagPieceFile, "a", "", "create an append file for others to import") } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") return cmd @@ -87,6 +112,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append type GenesisPiece struct { ChainID string `json:"chain_id"` NodeID string `json:"node_id"` + IP string `json:"ip"` AppState json.RawMessage `json:"app_state"` Validators []tmtypes.GenesisValidator `json:"validators"` } @@ -116,7 +142,7 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *c os.Remove(genFile) // deterministically walk the directory for genesis-piece files to import - filepath.Walk(pieceDir, appendPiece(cdc, appendState, nodeKeyFile, genFile)) + filepath.Walk(pieceDir, appendPiece(ctx, cdc, appendState, nodeKeyFile, genFile)) return nil }, @@ -124,7 +150,7 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *c } // append a genesis-piece -func appendPiece(cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFile string) filepath.WalkFunc { +func appendPiece(ctx *Context, cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFile string) filepath.WalkFunc { return func(pieceFile string, _ os.FileInfo, err error) error { if err != nil { return err @@ -185,7 +211,17 @@ func appendPiece(cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFi // write the appended genesis file return WriteGenesisFile(cdc, genFile, piece.ChainID, validators, appState) - // XXX XXX XXX read in configTOMBL and combine new nodeID file + // Add a persistent peer if the config (if it's not me) + myIP, err := externalIP() + if err != nil { + return err + } + if myIP == piece.IP { + return nil + } + ctx.Config.P2P.PersistentPeers += fmt.Sprintf(",%s@%s", piece.NodeID, piece.IP) + configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get + cfg.WriteConfigFile(configFilePath, ctx.Config) return nil } diff --git a/server/init_test.go b/server/init_test.go index e4bf8c0169..b13fb4789a 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -8,6 +8,7 @@ import ( "github.com/tendermint/tmlibs/log" "github.com/cosmos/cosmos-sdk/mock" + "github.com/cosmos/cosmos-sdk/wire" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" ) @@ -18,7 +19,8 @@ func TestInit(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - cmd := InitCmd(ctx, cdc, mock.GenAppParams) + cdc := wire.NewCodec() + cmd := InitCmd(ctx, cdc, mock.GenAppParams, nil) err = cmd.RunE(nil, nil) require.NoError(t, err) } diff --git a/server/start_test.go b/server/start_test.go index 9cbd456616..d933d19f15 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -10,6 +10,7 @@ import ( "github.com/stretchr/testify/require" "github.com/cosmos/cosmos-sdk/mock" + "github.com/cosmos/cosmos-sdk/wire" "github.com/tendermint/abci/server" tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" "github.com/tendermint/tmlibs/log" @@ -25,7 +26,8 @@ func TestStartStandAlone(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(ctx, cdc, mock.GenAppParams) + cdc := wire.NewCodec() + initCmd := InitCmd(ctx, cdc, mock.GenAppParams, nil) err = initCmd.RunE(nil, nil) require.NoError(t, err) @@ -51,7 +53,8 @@ func TestStartWithTendermint(t *testing.T) { cfg, err := tcmd.ParseConfig() require.Nil(t, err) ctx := NewContext(cfg, logger) - initCmd := InitCmd(ctx, cdc, mock.GenAppParams) + cdc := wire.NewCodec() + initCmd := InitCmd(ctx, cdc, mock.GenAppParams, nil) err = initCmd.RunE(nil, nil) require.NoError(t, err) diff --git a/server/util.go b/server/util.go index 4b34d0383f..3f24d59877 100644 --- a/server/util.go +++ b/server/util.go @@ -2,8 +2,10 @@ package server import ( "encoding/json" + "net" "os" + "github.com/pkg/errors" "github.com/spf13/cobra" "github.com/spf13/viper" @@ -93,3 +95,42 @@ func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMess bz, err := wire.MarshalJSONIndent(cdc, jsonMap) return json.RawMessage(bz), err } + +// https://stackoverflow.com/questions/23558425/how-do-i-get-the-local-ip-address-in-go +// TODO there must be a better way to get external IP +func externalIP() (string, error) { + ifaces, err := net.Interfaces() + if err != nil { + return "", err + } + for _, iface := range ifaces { + if iface.Flags&net.FlagUp == 0 { + continue // interface down + } + if iface.Flags&net.FlagLoopback != 0 { + continue // loopback interface + } + addrs, err := iface.Addrs() + if err != nil { + return "", err + } + for _, addr := range addrs { + var ip net.IP + switch v := addr.(type) { + case *net.IPNet: + ip = v.IP + case *net.IPAddr: + ip = v.IP + } + if ip == nil || ip.IsLoopback() { + continue + } + ip = ip.To4() + if ip == nil { + continue // not an ipv4 address + } + return ip.String(), nil + } + } + return "", errors.New("are you connected to the network?") +} diff --git a/server/util_test.go b/server/util_test.go index 5345b0f8f3..a21fe38828 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -12,6 +12,7 @@ import ( //func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { func TestAppendJSON(t *testing.T) { + cdc := wire.NewCodec() foo := map[string]string{"foo": "foofoo"} bar := map[string]string{"barInner": "barbar"} @@ -26,7 +27,6 @@ func TestAppendJSON(t *testing.T) { barRaw := json.RawMessage(bz) // make the append - cdc := wire.NewCodec() appBz, err := AppendJSON(cdc, fooRaw, "barOuter", barRaw) require.NoError(t, err) From 201908949affa1ed4a104a3108101a47fb29e2fc Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 23 Apr 2018 20:05:58 -0400 Subject: [PATCH 09/22] stake init overhaul --- cmd/gaia/app/app.go | 146 +++++++++++++++++++----- cmd/gaia/cli_test/cli_test.go | 21 ++-- cmd/gaia/cmd/gaiad/main.go | 2 +- examples/basecoin/app/app.go | 4 +- examples/basecoin/cmd/basecoind/main.go | 2 +- examples/democoin/app/app.go | 4 +- examples/democoin/cmd/democoind/main.go | 7 +- server/init.go | 41 ++++--- server/init_test.go | 5 +- server/start_test.go | 10 +- server/util.go | 6 +- x/stake/handler.go | 3 + x/stake/types.go | 5 +- 13 files changed, 189 insertions(+), 67 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 61242b0393..3eda293d3f 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -2,7 +2,11 @@ package app import ( "encoding/json" + "errors" + "strings" + "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" @@ -133,7 +137,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci stateJSON := req.AppStateBytes genesisState := new(GenesisState) - err := json.Unmarshal(stateJSON, genesisState) + err := app.cdc.UnmarshalJSON(stateJSON, genesisState) if err != nil { panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "") @@ -151,7 +155,7 @@ func (app *GaiaApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) abci return abci.ResponseInitChain{} } -//__________________________________________________________ +//________________________________________________________________________________________ // State to Unmarshal type GenesisState struct { @@ -172,7 +176,7 @@ func NewGenesisAccount(acc *auth.BaseAccount) GenesisAccount { } } -// convert GenesisAccount to GaiaAccount +// convert GenesisAccount to auth.BaseAccount func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { return &auth.BaseAccount{ Address: ga.Address, @@ -180,44 +184,126 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { } } -// XXX func AddPiece +var ( + flagAccounts = "accounts" + flagOWK = "overwrite-keys" +) + +// get app init parameters for server init command +func GaiaAppInit() server.AppInit { + fs := pflag.NewFlagSet("", pflag.ContinueOnError) + fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval;name2-coins-isval;...") + fs.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") + return server.AppInit{ + Flags: fs, + GenAppParams: GaiaGenAppParams, + AppendAppState: GaiaAppendAppState, + } +} // Create the core parameters for genesis initialization for gaia +// note that the pubkey input is this machines pubkey func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { - // XXX what's the best way to pass around this information? have special flagset defined here? - // add keys to accounts (flag) - // generate X accounts each with X money - // generate X number of validators each bonded with X amount of token - - var addr sdk.Address - var secret string - addr, secret, err = server.GenerateCoinKey() - if err != nil { - return - } - - mm := map[string]string{"secret": secret} - bz, err := cdc.MarshalJSON(mm) - cliPrint = json.RawMessage(bz) - + printMap := make(map[string]string) + var candidates []stake.Candidate + poolAssets := int64(0) chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) - validators = []tmtypes.GenesisValidator{{ - PubKey: pubKey, - Power: 10, - }} + // get genesis flag account information + accountsStr := viper.GetString(flagAccounts) + accounts := strings.Split(accountsStr, ";") + genaccs := make([]GenesisAccount, len(accounts)) + for i, account := range accounts { + p := strings.Split(account, "-") + if len(p) != 3 { + err = errors.New("input account has bad form, each account must be in form name-coins-isval, for example: foobar-10fermion,10baz-true") + return + } + name := p[0] + var coins sdk.Coins + coins, err = sdk.ParseCoins(p[1]) + if err != nil { + return + } + isValidator := false + if p[2] == "true" { + isValidator = true + } - accAuth := auth.NewBaseAccountWithAddress(addr) - accAuth.Coins = sdk.Coins{{"fermion", 100000}} - acc := NewGenesisAccount(&accAuth) - genaccs := []GenesisAccount{acc} + var addr sdk.Address + var secret string + addr, secret, err = server.GenerateCoinKey() + if err != nil { + return + } + + printMap["secret-"+name] = secret + + // create the genesis account + accAuth := auth.NewBaseAccountWithAddress(addr) + accAuth.Coins = coins + acc := NewGenesisAccount(&accAuth) + genaccs[i] = acc + + // add the validator + if isValidator { + + // only use this machines pubkey the first time, all others are dummies + var pk crypto.PubKey + if i == 0 { + pk = pubKey + } else { + pk = crypto.GenPrivKeyEd25519().PubKey() + } + + freePower := int64(100) + validator := tmtypes.GenesisValidator{ + PubKey: pk, + Power: freePower, + } + desc := stake.NewDescription(name, "", "", "") + candidate := stake.NewCandidate(addr, pk, desc) + candidate.Assets = sdk.NewRat(freePower) + poolAssets += freePower + validators = append(validators, validator) + candidates = append(candidates, candidate) + } + } + + // create the print message + bz, err := cdc.MarshalJSON(printMap) + cliPrint = json.RawMessage(bz) + + stakeData := stake.GetDefaultGenesisState() + stakeData.Candidates = candidates + + // assume everything is bonded from the get-go + stakeData.Pool.TotalSupply = poolAssets + stakeData.Pool.BondedShares = sdk.NewRat(poolAssets) genesisState := GenesisState{ Accounts: genaccs, - StakeData: stake.GetDefaultGenesisState(), + StakeData: stakeData, } - appState, err = json.MarshalIndent(genesisState, "", "\t") + appState, err = wire.MarshalJSONIndent(cdc, genesisState) return } + +// append gaia app_state together, stitch the accounts together take the +// staking parameters from the first appState +func GaiaAppendAppState(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) { + var genState1, genState2 GenesisState + err = cdc.UnmarshalJSON(appState1, &genState1) + if err != nil { + panic(err) + } + err = cdc.UnmarshalJSON(appState2, &genState2) + if err != nil { + panic(err) + } + genState1.Accounts = append(genState1.Accounts, genState2.Accounts...) + + return cdc.MarshalJSON(genState1) +} diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 07028ba16b..0d44438792 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -23,7 +23,8 @@ func TestGaiaCLISend(t *testing.T) { pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) - masterKey, chainID := executeInit(t, "gaiad init -o") + keys, chainID := executeInit(t, "gaiad init -o --accounts=foo-100000fermion-true", "foo") + require.Equal(t, 1, len(keys)) // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -33,7 +34,7 @@ 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, masterKey) + executeWrite(t, "gaiacli keys add foo --recover", pass, keys[0]) executeWrite(t, "gaiacli keys add bar", pass) fooAddr, _ := executeGetAddrPK(t, "gaiacli keys show foo --output=json") @@ -56,7 +57,8 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) - masterKey, chainID := executeInit(t, "gaiad init -o") + keys, chainID := executeInit(t, "gaiad init -o --accounts=bar-100000fermion-true;foo-100000fermion-true", "bar", "foo") + require.Equal(t, 2, len(keys)) // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -66,7 +68,7 @@ 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, masterKey) + executeWrite(t, "gaiacli keys add foo --recover", pass, keys[1]) fooAddr, fooPubKey := executeGetAddrPK(t, "gaiacli keys show foo --output=json") fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion")) @@ -128,7 +130,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) (masterKey, chainID string) { +func executeInit(t *testing.T, cmdStr string, names ...string) (keys []string, chainID string) { out := tests.ExecuteT(t, cmdStr, 1) var initRes map[string]json.RawMessage @@ -142,8 +144,13 @@ func executeInit(t *testing.T, cmdStr string) (masterKey, chainID string) { err = json.Unmarshal(initRes["app_message"], &appMessageRes) require.NoError(t, err) - err = json.Unmarshal(appMessageRes["secret"], &masterKey) - require.NoError(t, err) + for _, name := range names { + var key string + err = json.Unmarshal(appMessageRes["secret-"+name], &key) + require.NoError(t, err) + keys = append(keys, key) + } + return } diff --git a/cmd/gaia/cmd/gaiad/main.go b/cmd/gaia/cmd/gaiad/main.go index 1637a80852..565cf5ac26 100644 --- a/cmd/gaia/cmd/gaiad/main.go +++ b/cmd/gaia/cmd/gaiad/main.go @@ -24,7 +24,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, app.GaiaGenAppParams, generateApp) + server.AddCommands(ctx, cdc, rootCmd, app.GaiaAppInit(), generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.gaiad") diff --git a/examples/basecoin/app/app.go b/examples/basecoin/app/app.go index b02f216695..ead9c78e33 100644 --- a/examples/basecoin/app/app.go +++ b/examples/basecoin/app/app.go @@ -1,8 +1,6 @@ package app import ( - "encoding/json" - abci "github.com/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -133,7 +131,7 @@ func (app *BasecoinApp) initChainer(ctx sdk.Context, req abci.RequestInitChain) stateJSON := req.AppStateBytes genesisState := new(types.GenesisState) - err := json.Unmarshal(stateJSON, genesisState) + err := app.cdc.UnmarshalJSON(stateJSON, genesisState) if err != nil { panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "") diff --git a/examples/basecoin/cmd/basecoind/main.go b/examples/basecoin/cmd/basecoind/main.go index 02f2c80652..8d14821c6a 100644 --- a/examples/basecoin/cmd/basecoind/main.go +++ b/examples/basecoin/cmd/basecoind/main.go @@ -25,7 +25,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, server.SimpleGenAppParams, generateApp) + server.AddCommands(ctx, cdc, rootCmd, server.DefaultAppInit, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.basecoind") diff --git a/examples/democoin/app/app.go b/examples/democoin/app/app.go index b70f51b5cc..8266b2b9b9 100644 --- a/examples/democoin/app/app.go +++ b/examples/democoin/app/app.go @@ -1,8 +1,6 @@ package app import ( - "encoding/json" - abci "github.com/tendermint/abci/types" cmn "github.com/tendermint/tmlibs/common" dbm "github.com/tendermint/tmlibs/db" @@ -147,7 +145,7 @@ func (app *DemocoinApp) initChainerFn(coolKeeper cool.Keeper, powKeeper pow.Keep stateJSON := req.AppStateBytes genesisState := new(types.GenesisState) - err := json.Unmarshal(stateJSON, genesisState) + err := app.cdc.UnmarshalJSON(stateJSON, genesisState) if err != nil { panic(err) // TODO https://github.com/cosmos/cosmos-sdk/issues/468 // return sdk.ErrGenesisParse("").TraceCause(err, "") diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 7cfd55e916..0eb378005d 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -19,6 +19,11 @@ import ( "github.com/cosmos/cosmos-sdk/wire" ) +// init parameters +var CoolAppInit = server.AppInit{ + GenAppParams: CoolGenAppParams, +} + // coolGenAppParams sets up the app_state and appends the cool app state func CoolGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { chainID, validators, appState, cliPrint, err = server.SimpleGenAppParams(cdc, pubKey) @@ -52,7 +57,7 @@ func main() { PersistentPreRunE: server.PersistentPreRunEFn(ctx), } - server.AddCommands(ctx, cdc, rootCmd, CoolGenAppParams, generateApp) + server.AddCommands(ctx, cdc, rootCmd, CoolAppInit, generateApp) // prepare and add flags rootDir := os.ExpandEnv("$HOME/.democoind") diff --git a/server/init.go b/server/init.go index 3e8e0da4a6..7e7d895a10 100644 --- a/server/init.go +++ b/server/init.go @@ -11,6 +11,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/wire" "github.com/spf13/cobra" + "github.com/spf13/pflag" "github.com/spf13/viper" crypto "github.com/tendermint/go-crypto" @@ -26,7 +27,7 @@ import ( // TODO flag to retrieve genesis file / config file from a URL? // get cmd to initialize all files for tendermint and application -func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState AppendAppState) *cobra.Command { +func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { flagOverwrite, flagPieceFile := "overwrite", "piece-file" cmd := &cobra.Command{ Use: "init", @@ -37,7 +38,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append config := ctx.Config pubkey := ReadOrCreatePrivValidator(config) - chainID, validators, appState, cliPrint, err := gen(cdc, pubkey) + chainID, validators, appState, cliPrint, err := appInit.GenAppParams(cdc, pubkey) if err != nil { return err } @@ -100,11 +101,12 @@ func InitCmd(ctx *Context, cdc *wire.Codec, gen GenAppParams, appendState Append return nil }, } - if appendState != nil { - cmd.AddCommand(FromPiecesCmd(ctx, cdc, appendState)) + if appInit.AppendAppState != nil { + cmd.AddCommand(FromPiecesCmd(ctx, cdc, appInit)) cmd.Flags().StringP(flagPieceFile, "a", "", "create an append file for others to import") } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") + cmd.Flags().AddFlagSet(appInit.Flags) return cmd } @@ -118,7 +120,7 @@ type GenesisPiece struct { } // get cmd to initialize all files for tendermint and application -func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *cobra.Command { +func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return &cobra.Command{ Use: "from-pieces [directory]", Short: "Create genesis from directory of genesis pieces", @@ -142,7 +144,7 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *c os.Remove(genFile) // deterministically walk the directory for genesis-piece files to import - filepath.Walk(pieceDir, appendPiece(ctx, cdc, appendState, nodeKeyFile, genFile)) + filepath.Walk(pieceDir, appendPiece(ctx, cdc, appInit, nodeKeyFile, genFile)) return nil }, @@ -150,7 +152,7 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appendState AppendAppState) *c } // append a genesis-piece -func appendPiece(ctx *Context, cdc *wire.Codec, appendState AppendAppState, nodeKeyFile, genFile string) filepath.WalkFunc { +func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, genFile string) filepath.WalkFunc { return func(pieceFile string, _ os.FileInfo, err error) error { if err != nil { return err @@ -203,7 +205,7 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appendState AppendAppState, node validators = append(validators, piece.Validators...) // combine the app state - appState, err = appendState(cdc, appState, piece.AppState) + appState, err = appInit.AppendAppState(cdc, appState, piece.AppState) if err != nil { return err } @@ -273,17 +275,30 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js //_____________________________________________________________________ -// GenAppParams creates the core parameters initialization. It takes in a -// pubkey meant to represent the pubkey of the validator of this machine. -type GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) +// Core functionality passed from the application to the server init command +type AppInit struct { -// append appState1 with appState2 -type AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) + // flags required for GenAppParams + Flags *pflag.FlagSet + + // GenAppParams creates the core parameters initialization. It takes in a + // pubkey meant to represent the pubkey of the validator of this machine. + GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) + + // append appState1 with appState2 + AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) +} + +// simple default application init +var DefaultAppInit = AppInit{ + GenAppParams: SimpleGenAppParams, +} // Create one account with a whole bunch of mycoin in it func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { var addr sdk.Address + var secret string addr, secret, err = GenerateCoinKey() if err != nil { diff --git a/server/init_test.go b/server/init_test.go index b13fb4789a..5db4835160 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -20,7 +20,10 @@ func TestInit(t *testing.T) { require.Nil(t, err) ctx := NewContext(cfg, logger) cdc := wire.NewCodec() - cmd := InitCmd(ctx, cdc, mock.GenAppParams, nil) + appInit := AppInit{ + GenAppParams: mock.GenAppParams, + } + cmd := InitCmd(ctx, cdc, appInit) err = cmd.RunE(nil, nil) require.NoError(t, err) } diff --git a/server/start_test.go b/server/start_test.go index d933d19f15..85f1a7135e 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -27,7 +27,10 @@ func TestStartStandAlone(t *testing.T) { require.Nil(t, err) ctx := NewContext(cfg, logger) cdc := wire.NewCodec() - initCmd := InitCmd(ctx, cdc, mock.GenAppParams, nil) + appInit := AppInit{ + GenAppParams: mock.GenAppParams, + } + initCmd := InitCmd(ctx, cdc, appInit) err = initCmd.RunE(nil, nil) require.NoError(t, err) @@ -54,7 +57,10 @@ func TestStartWithTendermint(t *testing.T) { require.Nil(t, err) ctx := NewContext(cfg, logger) cdc := wire.NewCodec() - initCmd := InitCmd(ctx, cdc, mock.GenAppParams, nil) + appInit := AppInit{ + GenAppParams: mock.GenAppParams, + } + initCmd := InitCmd(ctx, cdc, appInit) err = initCmd.RunE(nil, nil) require.NoError(t, err) diff --git a/server/util.go b/server/util.go index 3f24d59877..ed91f30489 100644 --- a/server/util.go +++ b/server/util.go @@ -67,13 +67,13 @@ func PersistentPreRunEFn(context *Context) func(*cobra.Command, []string) error // add server commands func AddCommands( ctx *Context, cdc *wire.Codec, - rootCmd *cobra.Command, - appState GenAppParams, appCreator AppCreator) { + rootCmd *cobra.Command, appInit AppInit, + appCreator AppCreator) { rootCmd.PersistentFlags().String("log_level", ctx.Config.LogLevel, "Log level") rootCmd.AddCommand( - InitCmd(ctx, cdc, appState, nil), + InitCmd(ctx, cdc, appInit), StartCmd(ctx, appCreator), UnsafeResetAllCmd(ctx), ShowNodeIDCmd(ctx), diff --git a/x/stake/handler.go b/x/stake/handler.go index d9f718fe58..e397203857 100644 --- a/x/stake/handler.go +++ b/x/stake/handler.go @@ -52,6 +52,9 @@ func NewEndBlocker(k Keeper) sdk.EndBlocker { func InitGenesis(ctx sdk.Context, k Keeper, data GenesisState) { k.setPool(ctx, data.Pool) k.setParams(ctx, data.Params) + for _, candidate := range data.Candidates { + k.setCandidate(ctx, candidate) + } } //_____________________________________________________________________ diff --git a/x/stake/types.go b/x/stake/types.go index 8f9e87cbb0..634b51186b 100644 --- a/x/stake/types.go +++ b/x/stake/types.go @@ -9,8 +9,9 @@ import ( // GenesisState - all staking state that must be provided at genesis type GenesisState struct { - Pool Pool `json:"pool"` - Params Params `json:"params"` + Pool Pool `json:"pool"` + Params Params `json:"params"` + Candidates []Candidate `json:"candidates"` } //_________________________________________________________________________ From 3aa47527375f38a4b76cfdcf74e9dc84c6cb994a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 23 Apr 2018 20:26:28 -0400 Subject: [PATCH 10/22] stake cli init fixes --- cmd/gaia/app/app.go | 4 ++-- cmd/gaia/cli_test/cli_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 3eda293d3f..c0a91afc85 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -192,7 +192,7 @@ var ( // get app init parameters for server init command func GaiaAppInit() server.AppInit { fs := pflag.NewFlagSet("", pflag.ContinueOnError) - fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval;name2-coins-isval;...") + fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval:name2-coins-isval:...") fs.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") return server.AppInit{ Flags: fs, @@ -212,7 +212,7 @@ func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, va // get genesis flag account information accountsStr := viper.GetString(flagAccounts) - accounts := strings.Split(accountsStr, ";") + accounts := strings.Split(accountsStr, ":") genaccs := make([]GenesisAccount, len(accounts)) for i, account := range accounts { p := strings.Split(account, "-") diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 0d44438792..b3b2c4e7eb 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -57,7 +57,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) - keys, chainID := executeInit(t, "gaiad init -o --accounts=bar-100000fermion-true;foo-100000fermion-true", "bar", "foo") + keys, chainID := executeInit(t, "gaiad init -o --accounts=bar-100000fermion-true:foo-100000fermion-false", "bar", "foo") require.Equal(t, 2, len(keys)) // get a free port, also setup some common flags From 525a852b0172a5c44ee152e38d686557d9f33270 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Mon, 23 Apr 2018 21:32:43 -0400 Subject: [PATCH 11/22] bug fixes to init from-pieces command --- cmd/gaia/app/app.go | 18 +++++++++++++++++- server/init.go | 34 +++++++++++++++++++++++++--------- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index c0a91afc85..37c062595e 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -186,6 +186,7 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { var ( flagAccounts = "accounts" + flagChainID = "chain-id" flagOWK = "overwrite-keys" ) @@ -193,6 +194,7 @@ var ( func GaiaAppInit() server.AppInit { fs := pflag.NewFlagSet("", pflag.ContinueOnError) fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval:name2-coins-isval:...") + fs.String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created") fs.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") return server.AppInit{ Flags: fs, @@ -208,7 +210,11 @@ func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, va printMap := make(map[string]string) var candidates []stake.Candidate poolAssets := int64(0) - chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + + chainID = viper.GetString(flagChainID) + if len(chainID) == 0 { + chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + } // get genesis flag account information accountsStr := viper.GetString(flagAccounts) @@ -280,6 +286,7 @@ func GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, va // assume everything is bonded from the get-go stakeData.Pool.TotalSupply = poolAssets + stakeData.Pool.BondedPool = poolAssets stakeData.Pool.BondedShares = sdk.NewRat(poolAssets) genesisState := GenesisState{ @@ -304,6 +311,15 @@ func GaiaAppendAppState(cdc *wire.Codec, appState1, appState2 json.RawMessage) ( panic(err) } genState1.Accounts = append(genState1.Accounts, genState2.Accounts...) + genState1.StakeData.Candidates = append(genState1.StakeData.Candidates, genState2.StakeData.Candidates...) + + // pool logic + CombinedSupply := genState1.StakeData.Pool.TotalSupply + genState2.StakeData.Pool.TotalSupply + CombinedBondedPool := genState1.StakeData.Pool.BondedPool + genState2.StakeData.Pool.BondedPool + CombinedBondedShares := genState1.StakeData.Pool.BondedShares.Add(genState2.StakeData.Pool.BondedShares) + genState1.StakeData.Pool.TotalSupply = CombinedSupply + genState1.StakeData.Pool.BondedPool = CombinedBondedPool + genState1.StakeData.Pool.BondedShares = CombinedBondedShares return cdc.MarshalJSON(genState1) } diff --git a/server/init.go b/server/init.go index 7e7d895a10..68eb7f738a 100644 --- a/server/init.go +++ b/server/init.go @@ -77,8 +77,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { fmt.Println(string(out)) // write the piece file is path specified - pieceFile := viper.GetString(flagPieceFile) - if len(pieceFile) > 0 { + if viper.GetBool(flagPieceFile) { //create the piece ip, err := externalIP() if err != nil { @@ -95,7 +94,9 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { if err != nil { return err } - return cmn.WriteFile(pieceFile, bz, 0644) + name := fmt.Sprintf("piece%v.json", nodeID) + file := filepath.Join(viper.GetString("home"), name) + return cmn.WriteFile(file, bz, 0644) } return nil @@ -103,7 +104,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { } if appInit.AppendAppState != nil { cmd.AddCommand(FromPiecesCmd(ctx, cdc, appInit)) - cmd.Flags().StringP(flagPieceFile, "a", "", "create an append file for others to import") + cmd.Flags().BoolP(flagPieceFile, "a", false, "create an append file (under [--home]/[nodeID]piece.json) for others to import") } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") cmd.Flags().AddFlagSet(appInit.Flags) @@ -144,7 +145,10 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Comman os.Remove(genFile) // deterministically walk the directory for genesis-piece files to import - filepath.Walk(pieceDir, appendPiece(ctx, cdc, appInit, nodeKeyFile, genFile)) + err := filepath.Walk(pieceDir, appendPiece(ctx, cdc, appInit, nodeKeyFile, genFile)) + if err != nil { + return err + } return nil }, @@ -157,7 +161,7 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, ge if err != nil { return err } - if path.Ext(pieceFile) != "json" { + if path.Ext(pieceFile) != ".json" { return nil } @@ -192,7 +196,12 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, ge appState := genMap["app_state"] // verify chain-ids are the same - if piece.ChainID != string(genMap["chain_id"]) { + var genChainID string + err = cdc.UnmarshalJSON(genMap["chain_id"], &genChainID) + if err != nil { + return err + } + if piece.ChainID != genChainID { return fmt.Errorf("piece chain id's are mismatched, %s != %s", piece.ChainID, genMap["chain_id"]) } @@ -211,7 +220,10 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, ge } // write the appended genesis file - return WriteGenesisFile(cdc, genFile, piece.ChainID, validators, appState) + err = WriteGenesisFile(cdc, genFile, piece.ChainID, validators, appState) + if err != nil { + return err + } // Add a persistent peer if the config (if it's not me) myIP, err := externalIP() @@ -221,7 +233,11 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, ge if myIP == piece.IP { return nil } - ctx.Config.P2P.PersistentPeers += fmt.Sprintf(",%s@%s", piece.NodeID, piece.IP) + comma := "," + if len(ctx.Config.P2P.PersistentPeers) == 0 { + comma = "" + } + ctx.Config.P2P.PersistentPeers += fmt.Sprintf("%s%s@%s", comma, piece.NodeID, piece.IP) configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get cfg.WriteConfigFile(configFilePath, ctx.Config) From 4049c5d24fb5be7d5904fb580ea7b7bea4a3fd95 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Tue, 24 Apr 2018 19:46:39 -0400 Subject: [PATCH 12/22] cwgoes comments, bug fix --- server/init.go | 21 +++++++++++++-------- server/test_helpers.go | 24 ------------------------ server/util_test.go | 2 -- 3 files changed, 13 insertions(+), 34 deletions(-) diff --git a/server/init.go b/server/init.go index 68eb7f738a..4420bdf017 100644 --- a/server/init.go +++ b/server/init.go @@ -25,10 +25,9 @@ import ( dbm "github.com/tendermint/tmlibs/db" ) -// TODO flag to retrieve genesis file / config file from a URL? // get cmd to initialize all files for tendermint and application func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { - flagOverwrite, flagPieceFile := "overwrite", "piece-file" + flagOverwrite, flagPieceFile, flagIP := "overwrite", "piece-file", "ip" cmd := &cobra.Command{ Use: "init", Short: "Initialize genesis config, priv-validator file, and p2p-node file", @@ -79,9 +78,12 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { // write the piece file is path specified if viper.GetBool(flagPieceFile) { //create the piece - ip, err := externalIP() - if err != nil { - return err + ip := viper.GetString(flagIP) + if len(ip) == 0 { + ip, err = externalIP() + if err != nil { + return err + } } piece := GenesisPiece{ ChainID: chainID, @@ -90,7 +92,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { AppState: appState, Validators: validators, } - bz, err := cdc.MarshalJSON(piece) + bz, err := wire.MarshalJSONIndent(cdc, piece) if err != nil { return err } @@ -107,6 +109,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { cmd.Flags().BoolP(flagPieceFile, "a", false, "create an append file (under [--home]/[nodeID]piece.json) for others to import") } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") + cmd.Flags().String(flagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") cmd.Flags().AddFlagSet(appInit.Flags) return cmd } @@ -158,6 +161,7 @@ func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Comman // append a genesis-piece func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, genFile string) filepath.WalkFunc { return func(pieceFile string, _ os.FileInfo, err error) error { + fmt.Printf("debug pieceFile: %v\n", pieceFile) if err != nil { return err } @@ -202,7 +206,7 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, ge return err } if piece.ChainID != genChainID { - return fmt.Errorf("piece chain id's are mismatched, %s != %s", piece.ChainID, genMap["chain_id"]) + return fmt.Errorf("piece chain id's are mismatched, %s != %s", piece.ChainID, genChainID) } // combine the validator set @@ -237,7 +241,8 @@ func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, ge if len(ctx.Config.P2P.PersistentPeers) == 0 { comma = "" } - ctx.Config.P2P.PersistentPeers += fmt.Sprintf("%s%s@%s", comma, piece.NodeID, piece.IP) + //newPeer := fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) + ctx.Config.P2P.PersistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get cfg.WriteConfigFile(configFilePath, ctx.Config) diff --git a/server/test_helpers.go b/server/test_helpers.go index 55b6caf43b..382c778787 100644 --- a/server/test_helpers.go +++ b/server/test_helpers.go @@ -37,30 +37,6 @@ func setupViper(t *testing.T) func() { } } -// Begin the server pass up the channel to close -// NOTE pass up the channel so it can be closed at the end of the process -//func StartServer(t *testing.T, cdc *wire.Codec) chan error { -//defer setupViper(t)() - -//cfg, err := tcmd.ParseConfig() -//require.Nil(t, err) - -//// init server -//ctx := NewContext(cfg, log.NewNopLogger()) -//initCmd := InitCmd(ctx, cdc, mock.GenAppParams) -//err = initCmd.RunE(nil, nil) -//require.NoError(t, err) - -//// start server -//viper.Set(flagWithTendermint, true) -//startCmd := StartCmd(mock.NewApp, ctx) -//startCmd.Flags().Set(flagAddress, FreeTCPAddr(t)) // set to a new free address -//startCmd.Flags().Set("rpc.laddr", FreeTCPAddr(t)) // set to a new free address -//timeout := time.Duration(3) * time.Second - -//return RunOrTimeout(startCmd, timeout, t) -//} - // Run or Timout RunE of command passed in func RunOrTimeout(cmd *cobra.Command, timeout time.Duration, t *testing.T) chan error { done := make(chan error) diff --git a/server/util_test.go b/server/util_test.go index a21fe38828..13f8ad5dbc 100644 --- a/server/util_test.go +++ b/server/util_test.go @@ -9,8 +9,6 @@ import ( "github.com/stretchr/testify/require" ) -//func AppendJSON(cdc *wire.Codec, baseJSON []byte, key string, value json.RawMessage) (appended []byte, err error) { - func TestAppendJSON(t *testing.T) { cdc := wire.NewCodec() From d1402f4e922414e83206f622051a51a04cffa18f Mon Sep 17 00:00:00 2001 From: Ethan Buchman Date: Tue, 24 Apr 2018 20:55:15 -0400 Subject: [PATCH 13/22] move waitForXxx funcs from lcd to tests.WaitForXxx --- client/lcd/helpers.go | 19 -------- client/lcd/lcd_test.go | 82 +++---------------------------- tests/util.go | 107 +++++++++++++++++++++++++++++++++++++++++ 3 files changed, 114 insertions(+), 94 deletions(-) create mode 100644 tests/util.go diff --git a/client/lcd/helpers.go b/client/lcd/helpers.go index a64d44dfa6..367e1a53de 100644 --- a/client/lcd/helpers.go +++ b/client/lcd/helpers.go @@ -7,33 +7,14 @@ import ( "os" "path/filepath" "strings" - "time" cmn "github.com/tendermint/tmlibs/common" cfg "github.com/tendermint/tendermint/config" - ctypes "github.com/tendermint/tendermint/rpc/core/types" - rpcclient "github.com/tendermint/tendermint/rpc/lib/client" ) var globalConfig *cfg.Config -func waitForRPC() { - laddr := GetConfig().RPC.ListenAddress - fmt.Println("LADDR", laddr) - client := rpcclient.NewJSONRPCClient(laddr) - ctypes.RegisterAmino(client.Codec()) - result := new(ctypes.ResultStatus) - for { - _, err := client.Call("status", map[string]interface{}{}, result) - if err == nil { - return - } - fmt.Println("error", err) - time.Sleep(time.Millisecond) - } -} - // f**ing long, but unique for each test func makePathname() string { // get path diff --git a/client/lcd/lcd_test.go b/client/lcd/lcd_test.go index 0b5c6b064b..66a8a4085f 100644 --- a/client/lcd/lcd_test.go +++ b/client/lcd/lcd_test.go @@ -10,7 +10,6 @@ import ( "os" "regexp" "testing" - "time" "github.com/spf13/viper" "github.com/stretchr/testify/assert" @@ -34,6 +33,7 @@ import ( keys "github.com/cosmos/cosmos-sdk/client/keys" bapp "github.com/cosmos/cosmos-sdk/examples/basecoin/app" btypes "github.com/cosmos/cosmos-sdk/examples/basecoin/types" + tests "github.com/cosmos/cosmos-sdk/tests" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -157,7 +157,7 @@ func TestNodeStatus(t *testing.T) { func TestBlock(t *testing.T) { - waitForHeight(2) + tests.WaitForHeight(2, port) var resultBlock ctypes.ResultBlock @@ -224,7 +224,7 @@ func TestCoinSend(t *testing.T) { // create TX receiveAddr, resultTx := doSend(t, port, seed) - waitForHeight(resultTx.Height + 1) + tests.WaitForHeight(resultTx.Height+1, port) // check if tx was commited assert.Equal(t, uint32(0), resultTx.CheckTx.Code) @@ -253,7 +253,7 @@ func TestIBCTransfer(t *testing.T) { // create TX resultTx := doIBCTransfer(t, port, seed) - waitForHeight(resultTx.Height + 1) + tests.WaitForHeight(resultTx.Height+1, port) // check if tx was commited assert.Equal(t, uint32(0), resultTx.CheckTx.Code) @@ -286,7 +286,7 @@ func TestTxs(t *testing.T) { // create TX _, resultTx := doSend(t, port, seed) - waitForHeight(resultTx.Height + 1) + tests.WaitForHeight(resultTx.Height+1, port) // check if tx is findable res, body := request(t, port, "GET", fmt.Sprintf("/txs/%s", resultTx.Hash), nil) @@ -380,7 +380,7 @@ func startTMAndLCD() (*nm.Node, net.Listener, error) { return nil, nil, err } - waitForStart() + tests.WaitForStart(port) return node, lcd, nil } @@ -407,7 +407,7 @@ func startTM(cfg *tmcfg.Config, logger log.Logger, genDoc *tmtypes.GenesisDoc, p } // wait for rpc - waitForRPC() + tests.WaitForRPC(GetConfig().RPC.ListenAddress) logger.Info("Tendermint running!") return n, err @@ -490,71 +490,3 @@ func doIBCTransfer(t *testing.T, port, seed string) (resultTx ctypes.ResultBroad return resultTx } - -func waitForHeight(height int64) { - for { - var resultBlock ctypes.ResultBlock - - url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest") - res, err := http.Get(url) - if err != nil { - panic(err) - } - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - panic(err) - } - res.Body.Close() - - err = cdc.UnmarshalJSON([]byte(body), &resultBlock) - if err != nil { - fmt.Println("RES", res) - fmt.Println("BODY", string(body)) - panic(err) - } - - if resultBlock.Block.Height >= height { - return - } - time.Sleep(time.Millisecond * 100) - } -} - -// wait for 2 blocks -func waitForStart() { - waitHeight := int64(2) - for { - time.Sleep(time.Second) - - url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest") - res, err := http.Get(url) - if err != nil { - panic(err) - } - - // waiting for server to start ... - if res.StatusCode != http.StatusOK { - res.Body.Close() - continue - } - - body, err := ioutil.ReadAll(res.Body) - if err != nil { - panic(err) - } - res.Body.Close() - - resultBlock := new(ctypes.ResultBlock) - err = cdc.UnmarshalJSON([]byte(body), &resultBlock) - if err != nil { - fmt.Println("RES", res) - fmt.Println("BODY", string(body)) - panic(err) - } - - if resultBlock.Block.Height >= waitHeight { - return - } - } -} diff --git a/tests/util.go b/tests/util.go new file mode 100644 index 0000000000..a6f026f242 --- /dev/null +++ b/tests/util.go @@ -0,0 +1,107 @@ +package tests + +import ( + "fmt" + "io/ioutil" + "net/http" + "time" + + amino "github.com/tendermint/go-amino" + ctypes "github.com/tendermint/tendermint/rpc/core/types" + rpcclient "github.com/tendermint/tendermint/rpc/lib/client" +) + +// TODO: these functions just print to Stdout. +// consider using the logger. + +// Uses localhost +func WaitForHeight(height int64, port string) { + for { + var resultBlock ctypes.ResultBlock + + url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest") + res, err := http.Get(url) + if err != nil { + panic(err) + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + panic(err) + } + res.Body.Close() + + err = cdc.UnmarshalJSON([]byte(body), &resultBlock) + if err != nil { + fmt.Println("RES", res) + fmt.Println("BODY", string(body)) + panic(err) + } + + if resultBlock.Block.Height >= height { + return + } + time.Sleep(time.Millisecond * 100) + } +} + +// wait for 2 blocks. +// uses localhost +func WaitForStart(port string) { + waitHeight := int64(2) + for { + time.Sleep(time.Second) + + url := fmt.Sprintf("http://localhost:%v%v", port, "/blocks/latest") + res, err := http.Get(url) + if err != nil { + panic(err) + } + + // waiting for server to start ... + if res.StatusCode != http.StatusOK { + res.Body.Close() + continue + } + + body, err := ioutil.ReadAll(res.Body) + if err != nil { + panic(err) + } + res.Body.Close() + + resultBlock := new(ctypes.ResultBlock) + err = cdc.UnmarshalJSON([]byte(body), &resultBlock) + if err != nil { + fmt.Println("RES", res) + fmt.Println("BODY", string(body)) + panic(err) + } + + if resultBlock.Block.Height >= waitHeight { + return + } + } +} + +// Wait for the RPC server to respond to /status +func WaitForRPC(laddr string) { + fmt.Println("LADDR", laddr) + client := rpcclient.NewJSONRPCClient(laddr) + ctypes.RegisterAmino(client.Codec()) + result := new(ctypes.ResultStatus) + for { + _, err := client.Call("status", map[string]interface{}{}, result) + if err == nil { + return + } + fmt.Printf("Waiting for RPC server to start on %s:%v\n", laddr, err) + time.Sleep(time.Millisecond) + } +} + +var cdc = amino.NewCodec() + +func init() { + ctypes.RegisterAmino(cdc) +} From 12f20d160a3096813254e6cbc4f634ee083e859e Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Apr 2018 01:37:46 -0400 Subject: [PATCH 14/22] interim gen app tx refactor --- server/init.go | 326 ++++++++++++++++++++++--------------------------- 1 file changed, 147 insertions(+), 179 deletions(-) diff --git a/server/init.go b/server/init.go index 4420bdf017..edb256f8e8 100644 --- a/server/init.go +++ b/server/init.go @@ -4,7 +4,6 @@ import ( "encoding/json" "fmt" "io/ioutil" - "os" "path" "path/filepath" @@ -25,9 +24,82 @@ import ( dbm "github.com/tendermint/tmlibs/db" ) +// genesis piece structure for creating combined genesis +type GenesisTx struct { + NodeID string `json:"node_id"` + IP string `json:"ip"` + Validator tmtypes.GenesisValidator `json:"validator"` + AppGenTx json.RawMessage `json:"app_gen_tx"` +} + +var ( + flagOverwrite = "overwrite" + flagGenTxs = "gen-txs" + flagIP = "ip" + flagChainID = "ip" +) + +// get cmd to initialize all files for tendermint and application +func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { + cmd := &cobra.Command{ + Use: "gen-tx", + Short: "Create genesis transaction file (under [--home]/gentx-[nodeID].json)", + Args: cobra.NoArgs, + RunE: func(_ *cobra.Command, args []string) error { + + config := ctx.Config + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) + if err != nil { + return err + } + nodeID := string(nodeKey.ID()) + pubKey := ReadOrCreatePrivValidator(config) + + appGenTx, toPrint, validator, err := appInit.GenAppTx(cdc, pubKey) + if err != nil { + return err + } + + ip := viper.GetString(flagIP) + if len(ip) == 0 { + ip, err = externalIP() + if err != nil { + return err + } + } + + tx := GenesisTx{ + NodeID: nodeID, + IP: ip, + Validator: validator, + AppGenTx: appGenTx, + } + bz, err := wire.MarshalJSONIndent(cdc, tx) + if err != nil { + return err + } + name := fmt.Sprintf("gentx-%v.json", nodeID) + file := filepath.Join(viper.GetString("home"), name) + if err != nil { + return err + err = cmn.WriteFile(file, bz, 0644) + } + + out, err := wire.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.FlagsAppTx) + return cmd +} + // get cmd to initialize all files for tendermint and application func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { - flagOverwrite, flagPieceFile, flagIP := "overwrite", "piece-file", "ip" cmd := &cobra.Command{ Use: "init", Short: "Initialize genesis config, priv-validator file, and p2p-node file", @@ -35,16 +107,46 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { RunE: func(_ *cobra.Command, _ []string) error { config := ctx.Config - pubkey := ReadOrCreatePrivValidator(config) - - chainID, validators, appState, cliPrint, err := appInit.GenAppParams(cdc, pubkey) + nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) if err != nil { return err } + nodeID := string(nodeKey.ID()) + pubKey := ReadOrCreatePrivValidator(config) + + chainID := viper.GetString(flagChainID) + if chainID == "" { + chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + } genFile := config.GenesisFile() if !viper.GetBool(flagOverwrite) && cmn.FileExists(genFile) { - return fmt.Errorf("genesis config file already exists: %v", genFile) + return fmt.Errorf("genesis.json file already exists: %v", genFile) + } + + // process genesis transactions, or otherwise create one for defaults + var appGenTxs, cliPrints []json.RawMessage + var validators []tmtypes.GenesisValidator + var persistentPeers string + genTxsDir := viper.GetString(flagGenTxs) + if genTxsDir != "" { + validators, persistentPeers, appGenTxs, cliPrints = processGenTxs(genTxsDir, cdc, appInit) + config.P2P.PersistentPeers = persistentPeers + configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get + cfg.WriteConfigFile(configFilePath, config) + } else { + appTx, cliPrint, validator, err := appInit.GenAppTx(cdc, pubKey) + if err != nil { + return err + } + validators = []tmtypes.GenesisValidator{validator} + appGenTxs = []json.RawMessage{appTx} + cliPrints = []json.RawMessage{cliPrint} + } + + appState, err := appInit.GenAppParams(cdc, appGenTxs) + if err != nil { + return err } err = WriteGenesisFile(cdc, genFile, chainID, validators, appState) @@ -52,22 +154,15 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return err } - nodeKey, err := p2p.LoadOrGenNodeKey(config.NodeKeyFile()) - if err != nil { - return err - } - nodeID := string(nodeKey.ID()) - // print out some key information - toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - AppMessage json.RawMessage `json:"app_message"` + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppMessage []json.RawMessage `json:"app_messages"` }{ chainID, nodeID, - cliPrint, + cliPrints, } out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { @@ -75,179 +170,51 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { } fmt.Println(string(out)) - // write the piece file is path specified - if viper.GetBool(flagPieceFile) { - //create the piece - ip := viper.GetString(flagIP) - if len(ip) == 0 { - ip, err = externalIP() - if err != nil { - return err - } - } - piece := GenesisPiece{ - ChainID: chainID, - NodeID: nodeID, - IP: ip, - AppState: appState, - Validators: validators, - } - bz, err := wire.MarshalJSONIndent(cdc, piece) - if err != nil { - return err - } - name := fmt.Sprintf("piece%v.json", nodeID) - file := filepath.Join(viper.GetString("home"), name) - return cmn.WriteFile(file, bz, 0644) - } - return nil }, } - if appInit.AppendAppState != nil { - cmd.AddCommand(FromPiecesCmd(ctx, cdc, appInit)) - cmd.Flags().BoolP(flagPieceFile, "a", false, "create an append file (under [--home]/[nodeID]piece.json) for others to import") - } - cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the config file") - cmd.Flags().String(flagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") - cmd.Flags().AddFlagSet(appInit.Flags) + cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file") + cmd.Flags().String(flagChainID, "", "designated chain-id for the genesis") + cmd.Flags().AddFlagSet(appInit.FlagsAppParams) return cmd } -// genesis piece structure for creating combined genesis -type GenesisPiece struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - IP string `json:"ip"` - AppState json.RawMessage `json:"app_state"` - Validators []tmtypes.GenesisValidator `json:"validators"` -} - -// get cmd to initialize all files for tendermint and application -func FromPiecesCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { - return &cobra.Command{ - Use: "from-pieces [directory]", - Short: "Create genesis from directory of genesis pieces", - Args: cobra.ExactArgs(1), - RunE: func(_ *cobra.Command, args []string) error { - pieceDir := args[0] - - // ensure that the privVal and nodeKey file already exist - config := ctx.Config - privValFile := config.PrivValidatorFile() - nodeKeyFile := config.NodeKeyFile() - if !cmn.FileExists(privValFile) { - return fmt.Errorf("privVal file must already exist, please initialize with init cmd: %v", privValFile) - } - if !cmn.FileExists(nodeKeyFile) { - return fmt.Errorf("nodeKey file must already exist, please initialize with init cmd: %v", nodeKeyFile) - } - - // remove genFile for creation - genFile := config.GenesisFile() - os.Remove(genFile) - - // deterministically walk the directory for genesis-piece files to import - err := filepath.Walk(pieceDir, appendPiece(ctx, cdc, appInit, nodeKeyFile, genFile)) - if err != nil { - return err - } - - return nil - }, - } -} - // append a genesis-piece -func appendPiece(ctx *Context, cdc *wire.Codec, appInit AppInit, nodeKeyFile, genFile string) filepath.WalkFunc { - return func(pieceFile string, _ os.FileInfo, err error) error { - fmt.Printf("debug pieceFile: %v\n", pieceFile) - if err != nil { - return err - } - if path.Ext(pieceFile) != ".json" { +func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( + validators []tmtypes.GenesisValidator, appGenTxs, cliPrints []json.RawMessage, persistentPeers string, err error) { + + fos, err := ioutil.ReadDir(genTxsDir) + for _, fo := range fos { + filename := fo.Name() + if !fo.IsDir() && (path.Ext(filename) != ".json") { return nil } - // get the piece file bytes - bz, err := ioutil.ReadFile(pieceFile) + // get the genTx + bz, err := ioutil.ReadFile(filename) + if err != nil { + return err + } + var genTx GenesisTx + err = cdc.UnmarshalJSON(bz, &genTx) if err != nil { return err } - // get the piece - var piece GenesisPiece - err = cdc.UnmarshalJSON(bz, &piece) - if err != nil { - return err - } + // combine some stuff + validators = append(validators, genTx.Validator) + appGenTxs = append(appGenTxs, genTx.AppGenTxs) + cliPrints = append(cliPrints, genTx.CliPrints) - // if the first file, create the genesis from scratch with piece inputs - if !cmn.FileExists(genFile) { - return WriteGenesisFile(cdc, genFile, piece.ChainID, piece.Validators, piece.AppState) - } - - // read in the genFile - bz, err = ioutil.ReadFile(genFile) - if err != nil { - return err - } - var genMap map[string]json.RawMessage - err = cdc.UnmarshalJSON(bz, &genMap) - if err != nil { - return err - } - appState := genMap["app_state"] - - // verify chain-ids are the same - var genChainID string - err = cdc.UnmarshalJSON(genMap["chain_id"], &genChainID) - if err != nil { - return err - } - if piece.ChainID != genChainID { - return fmt.Errorf("piece chain id's are mismatched, %s != %s", piece.ChainID, genChainID) - } - - // combine the validator set - var validators []tmtypes.GenesisValidator - err = cdc.UnmarshalJSON(genMap["validators"], &validators) - if err != nil { - return err - } - validators = append(validators, piece.Validators...) - - // combine the app state - appState, err = appInit.AppendAppState(cdc, appState, piece.AppState) - if err != nil { - return err - } - - // write the appended genesis file - err = WriteGenesisFile(cdc, genFile, piece.ChainID, validators, appState) - if err != nil { - return err - } - - // Add a persistent peer if the config (if it's not me) - myIP, err := externalIP() - if err != nil { - return err - } - if myIP == piece.IP { - return nil - } + // Add a persistent peer comma := "," - if len(ctx.Config.P2P.PersistentPeers) == 0 { + if len(persistentPeers) == 0 { comma = "" } - //newPeer := fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) - ctx.Config.P2P.PersistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) - configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get - cfg.WriteConfigFile(configFilePath, ctx.Config) - - return nil + persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) } + + return nil } //________________________________________________________________________________________ @@ -299,15 +266,17 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js // Core functionality passed from the application to the server init command type AppInit struct { - // flags required for GenAppParams - Flags *pflag.FlagSet + // flags required for application init functions + FlagsAppParams *pflag.FlagSet + FlagsAppTx *pflag.FlagSet // GenAppParams creates the core parameters initialization. It takes in a // pubkey meant to represent the pubkey of the validator of this machine. - GenAppParams func(*wire.Codec, crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) + GenAppParams func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) - // append appState1 with appState2 - AppendAppState func(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) + // create the application genesis tx + GenAppTx func(cdc *wire.Codec, pk crypto.PubKey) ( + appTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) } // simple default application init @@ -316,7 +285,8 @@ var DefaultAppInit = AppInit{ } // Create one account with a whole bunch of mycoin in it -func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { +func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage) ( + validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { var addr sdk.Address @@ -330,8 +300,6 @@ func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, bz, err := cdc.MarshalJSON(mm) cliPrint = json.RawMessage(bz) - chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) - validators = []tmtypes.GenesisValidator{{ PubKey: pubKey, Power: 10, From b9477ecbbec2a537a57db5c6d95839e07ccc0b4b Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Apr 2018 16:12:14 -0400 Subject: [PATCH 15/22] init refactor uses genesis transaction now --- cmd/gaia/app/app.go | 183 +++++++++++------------- cmd/gaia/cli_test/cli_test.go | 61 ++++---- examples/democoin/cmd/democoind/main.go | 9 +- mock/app.go | 24 ++-- mock/app_test.go | 5 +- server/init.go | 149 ++++++++++++------- server/init_test.go | 3 +- server/start_test.go | 6 +- 8 files changed, 237 insertions(+), 203 deletions(-) diff --git a/cmd/gaia/app/app.go b/cmd/gaia/app/app.go index 37c062595e..eb63c6f1a0 100644 --- a/cmd/gaia/app/app.go +++ b/cmd/gaia/app/app.go @@ -3,7 +3,6 @@ package app import ( "encoding/json" "errors" - "strings" "github.com/spf13/pflag" "github.com/spf13/viper" @@ -185,141 +184,123 @@ func (ga *GenesisAccount) ToAccount() (acc *auth.BaseAccount) { } var ( - flagAccounts = "accounts" - flagChainID = "chain-id" - flagOWK = "overwrite-keys" + flagName = "name" + //flagOWK = "overwrite-keys" ) // get app init parameters for server init command func GaiaAppInit() server.AppInit { - fs := pflag.NewFlagSet("", pflag.ContinueOnError) - fs.String(flagAccounts, "foobar-10fermion,10baz-true", "genesis accounts in form: name1-coins-isval:name2-coins-isval:...") - fs.String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created") - fs.BoolP(flagOWK, "k", false, "overwrite the for the accounts created, if false and key exists init will fail") + 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{ - Flags: fs, - GenAppParams: GaiaGenAppParams, - AppendAppState: GaiaAppendAppState, + 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 GaiaGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { +func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { - printMap := make(map[string]string) - var candidates []stake.Candidate - poolAssets := int64(0) - - chainID = viper.GetString(flagChainID) - if len(chainID) == 0 { - chainID = cmn.Fmt("test-chain-%v", cmn.RandStr(6)) + 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 - accountsStr := viper.GetString(flagAccounts) - accounts := strings.Split(accountsStr, ":") - genaccs := make([]GenesisAccount, len(accounts)) - for i, account := range accounts { - p := strings.Split(account, "-") - if len(p) != 3 { - err = errors.New("input account has bad form, each account must be in form name-coins-isval, for example: foobar-10fermion,10baz-true") - return - } - name := p[0] - var coins sdk.Coins - coins, err = sdk.ParseCoins(p[1]) - if err != nil { - return - } - isValidator := false - if p[2] == "true" { - isValidator = true - } + genaccs := make([]GenesisAccount, len(appGenTxs)) + for i, appGenTx := range appGenTxs { - var addr sdk.Address - var secret string - addr, secret, err = server.GenerateCoinKey() + var genTx GaiaGenTx + err = cdc.UnmarshalJSON(appGenTx, &genTx) if err != nil { return } - printMap["secret-"+name] = secret - - // create the genesis account - accAuth := auth.NewBaseAccountWithAddress(addr) - accAuth.Coins = coins + // 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 isValidator { + 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) - // only use this machines pubkey the first time, all others are dummies - var pk crypto.PubKey - if i == 0 { - pk = pubKey - } else { - pk = crypto.GenPrivKeyEd25519().PubKey() - } - - freePower := int64(100) - validator := tmtypes.GenesisValidator{ - PubKey: pk, - Power: freePower, - } - desc := stake.NewDescription(name, "", "", "") - candidate := stake.NewCandidate(addr, pk, desc) - candidate.Assets = sdk.NewRat(freePower) - poolAssets += freePower - validators = append(validators, validator) - candidates = append(candidates, candidate) + // pool logic + stakeData.Pool.TotalSupply += FreePower + stakeData.Pool.BondedPool += FreePower + stakeData.Pool.BondedShares = sdk.NewRat(stakeData.Pool.BondedPool) } } - // create the print message - bz, err := cdc.MarshalJSON(printMap) - cliPrint = json.RawMessage(bz) - - stakeData := stake.GetDefaultGenesisState() - stakeData.Candidates = candidates - - // assume everything is bonded from the get-go - stakeData.Pool.TotalSupply = poolAssets - stakeData.Pool.BondedPool = poolAssets - stakeData.Pool.BondedShares = sdk.NewRat(poolAssets) - + // create the final app state genesisState := GenesisState{ Accounts: genaccs, StakeData: stakeData, } - appState, err = wire.MarshalJSONIndent(cdc, genesisState) return } -// append gaia app_state together, stitch the accounts together take the -// staking parameters from the first appState -func GaiaAppendAppState(cdc *wire.Codec, appState1, appState2 json.RawMessage) (appState json.RawMessage, err error) { - var genState1, genState2 GenesisState - err = cdc.UnmarshalJSON(appState1, &genState1) - if err != nil { - panic(err) - } - err = cdc.UnmarshalJSON(appState2, &genState2) - if err != nil { - panic(err) - } - genState1.Accounts = append(genState1.Accounts, genState2.Accounts...) - genState1.StakeData.Candidates = append(genState1.StakeData.Candidates, genState2.StakeData.Candidates...) +// Generate a gaia genesis transaction +func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { - // pool logic - CombinedSupply := genState1.StakeData.Pool.TotalSupply + genState2.StakeData.Pool.TotalSupply - CombinedBondedPool := genState1.StakeData.Pool.BondedPool + genState2.StakeData.Pool.BondedPool - CombinedBondedShares := genState1.StakeData.Pool.BondedShares.Add(genState2.StakeData.Pool.BondedShares) - genState1.StakeData.Pool.TotalSupply = CombinedSupply - genState1.StakeData.Pool.BondedPool = CombinedBondedPool - genState1.StakeData.Pool.BondedShares = CombinedBondedShares + var addr sdk.Address + var secret string + addr, secret, err = server.GenerateCoinKey() + if err != nil { + return + } - return cdc.MarshalJSON(genState1) + 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/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index b3b2c4e7eb..b70d25551d 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -23,8 +23,7 @@ func TestGaiaCLISend(t *testing.T) { pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) - keys, chainID := executeInit(t, "gaiad init -o --accounts=foo-100000fermion-true", "foo") - require.Equal(t, 1, len(keys)) + key, chainID := executeInit(t, "gaiad init -o --name=foo") // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -34,14 +33,14 @@ 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, keys[0]) + 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") fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion")) + assert.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("fermion")) executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass @@ -49,7 +48,7 @@ func TestGaiaCLISend(t *testing.T) { barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(99990), fooAcc.GetCoins().AmountOf("fermion")) + assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion")) } func TestGaiaCLIDeclareCandidacy(t *testing.T) { @@ -57,8 +56,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) - keys, chainID := executeInit(t, "gaiad init -o --accounts=bar-100000fermion-true:foo-100000fermion-false", "bar", "foo") - require.Equal(t, 2, len(keys)) + key, chainID := executeInit(t, "gaiad init -o --name=foo") // get a free port, also setup some common flags servAddr := server.FreeTCPAddr(t) @@ -68,41 +66,46 @@ 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, keys[1]) - fooAddr, fooPubKey := executeGetAddrPK(t, "gaiacli keys show foo --output=json") + 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") + time.Sleep(time.Second * 3) // waiting for some blocks to pass + barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(100000), fooAcc.GetCoins().AmountOf("fermion")) + assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion")) // declare candidacy declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags) - declStr += fmt.Sprintf(" --name=%v", "foo") - declStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) - declStr += fmt.Sprintf(" --pubkey=%v", fooPubKey) + declStr += fmt.Sprintf(" --name=%v", "bar") + declStr += fmt.Sprintf(" --address-candidate=%v", barAddr) + declStr += fmt.Sprintf(" --pubkey=%v", barPubKey) declStr += fmt.Sprintf(" --amount=%v", "3fermion") - declStr += fmt.Sprintf(" --moniker=%v", "foo-vally") + declStr += fmt.Sprintf(" --moniker=%v", "bar-vally") fmt.Printf("debug declStr: %v\n", declStr) executeWrite(t, declStr, pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass - fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - assert.Equal(t, int64(99997), fooAcc.GetCoins().AmountOf("fermion")) - candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) - assert.Equal(t, candidate.Address.String(), fooAddr) + barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("fermion")) + candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) + assert.Equal(t, candidate.Address.String(), barAddr) assert.Equal(t, int64(3), candidate.Assets.Evaluate()) // TODO timeout issues if not connected to the internet // unbond a single share //unbondStr := fmt.Sprintf("gaiacli unbond %v", flags) - //unbondStr += fmt.Sprintf(" --name=%v", "foo") - //unbondStr += fmt.Sprintf(" --address-candidate=%v", fooAddr) - //unbondStr += fmt.Sprintf(" --address-delegator=%v", fooAddr) + //unbondStr += fmt.Sprintf(" --name=%v", "bar") + //unbondStr += fmt.Sprintf(" --address-candidate=%v", barAddr) + //unbondStr += fmt.Sprintf(" --address-delegator=%v", barAddr) //unbondStr += fmt.Sprintf(" --shares=%v", "1") //unbondStr += fmt.Sprintf(" --sequence=%v", "1") //fmt.Printf("debug unbondStr: %v\n", unbondStr) //executeWrite(t, unbondStr, pass) //time.Sleep(time.Second * 3) // waiting for some blocks to pass - //fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) - //assert.Equal(t, int64(99998), fooAcc.GetCoins().AmountOf("fermion")) - //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, fooAddr)) + //barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + //assert.Equal(t, int64(99998), barAcc.GetCoins().AmountOf("fermion")) + //candidate = executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) //assert.Equal(t, int64(2), candidate.Assets.Evaluate()) } @@ -130,7 +133,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, names ...string) (keys []string, chainID string) { +func executeInit(t *testing.T, cmdStr string) (key, chainID string) { out := tests.ExecuteT(t, cmdStr, 1) var initRes map[string]json.RawMessage @@ -144,12 +147,8 @@ func executeInit(t *testing.T, cmdStr string, names ...string) (keys []string, c err = json.Unmarshal(initRes["app_message"], &appMessageRes) require.NoError(t, err) - for _, name := range names { - var key string - err = json.Unmarshal(appMessageRes["secret-"+name], &key) - require.NoError(t, err) - keys = append(keys, key) - } + err = json.Unmarshal(appMessageRes["secret"], &key) + require.NoError(t, err) return } diff --git a/examples/democoin/cmd/democoind/main.go b/examples/democoin/cmd/democoind/main.go index 0eb378005d..afca80bce3 100644 --- a/examples/democoin/cmd/democoind/main.go +++ b/examples/democoin/cmd/democoind/main.go @@ -8,8 +8,6 @@ import ( "github.com/spf13/cobra" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" - tmtypes "github.com/tendermint/tendermint/types" "github.com/tendermint/tmlibs/cli" dbm "github.com/tendermint/tmlibs/db" "github.com/tendermint/tmlibs/log" @@ -21,12 +19,13 @@ import ( // init parameters var CoolAppInit = server.AppInit{ - GenAppParams: CoolGenAppParams, + AppGenState: CoolAppGenState, + AppGenTx: server.SimpleAppGenTx, } // coolGenAppParams sets up the app_state and appends the cool app state -func CoolGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { - chainID, validators, appState, cliPrint, err = server.SimpleGenAppParams(cdc, pubKey) +func CoolAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { + appState, err = server.SimpleAppGenState(cdc, appGenTxs) if err != nil { return } diff --git a/mock/app.go b/mock/app.go index 09f09b830c..84f762db0e 100644 --- a/mock/app.go +++ b/mock/app.go @@ -8,7 +8,6 @@ import ( 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" @@ -106,17 +105,9 @@ func InitChainer(key sdk.StoreKey) func(sdk.Context, abci.RequestInitChain) abci } } -// GenAppParams can be passed into InitCmd, returns a static string of a few +// AppGenState can be passed into InitCmd, returns a static string of a few // key-values that can be parsed by InitChainer -func GenAppParams(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { - - chainID = fmt.Sprintf("test-chain-%v", cmn.RandStr(6)) - - validators = []tmtypes.GenesisValidator{{ - PubKey: pubKey, - Power: 10, - }} - +func AppGenState(_ *wire.Codec, _ []json.RawMessage) (appState json.RawMessage, err error) { appState = json.RawMessage(`{ "values": [ { @@ -131,3 +122,14 @@ func GenAppParams(_ *wire.Codec, pubKey crypto.PubKey) (chainID string, validato }`) return } + +// Return a validator, not much else +func AppGenTx(_ *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { + + validator = tmtypes.GenesisValidator{ + PubKey: pk, + Power: 10, + } + return +} diff --git a/mock/app_test.go b/mock/app_test.go index fe0948a84c..7c84f9a1d1 100644 --- a/mock/app_test.go +++ b/mock/app_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/require" abci "github.com/tendermint/abci/types" - crypto "github.com/tendermint/go-crypto" ) // TestInitApp makes sure we can initialize this thing without an error @@ -22,9 +21,9 @@ func TestInitApp(t *testing.T) { require.NoError(t, err) // initialize it future-way - pubKey := crypto.GenPrivKeyEd25519().PubKey() - _, _, appState, _, err := GenAppParams(nil, pubKey) + appState, err := AppGenState(nil, nil) require.NoError(t, err) + //TODO test validators in the init chain? req := abci.RequestInitChain{ AppStateBytes: appState, diff --git a/server/init.go b/server/init.go index edb256f8e8..5916e38349 100644 --- a/server/init.go +++ b/server/init.go @@ -4,11 +4,13 @@ import ( "encoding/json" "fmt" "io/ioutil" + "os" "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" "github.com/spf13/viper" @@ -30,13 +32,14 @@ type GenesisTx struct { IP string `json:"ip"` Validator tmtypes.GenesisValidator `json:"validator"` AppGenTx json.RawMessage `json:"app_gen_tx"` + CLIPrint json.RawMessage `json:"cli_print"` } var ( flagOverwrite = "overwrite" flagGenTxs = "gen-txs" flagIP = "ip" - flagChainID = "ip" + flagChainID = "chain-id" ) // get cmd to initialize all files for tendermint and application @@ -55,7 +58,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { nodeID := string(nodeKey.ID()) pubKey := ReadOrCreatePrivValidator(config) - appGenTx, toPrint, validator, err := appInit.GenAppTx(cdc, pubKey) + appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey) if err != nil { return err } @@ -73,6 +76,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { IP: ip, Validator: validator, AppGenTx: appGenTx, + CLIPrint: cliPrint, } bz, err := wire.MarshalJSONIndent(cdc, tx) if err != nil { @@ -85,7 +89,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { err = cmn.WriteFile(file, bz, 0644) } - out, err := wire.MarshalJSONIndent(cdc, toPrint) + out, err := wire.MarshalJSONIndent(cdc, cliPrint) if err != nil { return err } @@ -94,7 +98,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { }, } cmd.Flags().String(flagIP, "", "external facing IP to use if left blank IP will be retrieved from this machine") - cmd.Flags().AddFlagSet(appInit.FlagsAppTx) + cmd.Flags().AddFlagSet(appInit.FlagsAppGenTx) return cmd } @@ -125,26 +129,31 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { } // process genesis transactions, or otherwise create one for defaults - var appGenTxs, cliPrints []json.RawMessage + var appMessage json.RawMessage + var appGenTxs []json.RawMessage var validators []tmtypes.GenesisValidator var persistentPeers string + genTxsDir := viper.GetString(flagGenTxs) if genTxsDir != "" { - validators, persistentPeers, appGenTxs, cliPrints = processGenTxs(genTxsDir, cdc, appInit) + validators, appGenTxs, persistentPeers, err = processGenTxs(genTxsDir, cdc, appInit) + if err != nil { + return err + } config.P2P.PersistentPeers = persistentPeers configFilePath := filepath.Join(viper.GetString("home"), "config", "config.toml") //TODO this is annoying should be easier to get cfg.WriteConfigFile(configFilePath, config) } else { - appTx, cliPrint, validator, err := appInit.GenAppTx(cdc, pubKey) + appGenTx, am, validator, err := appInit.AppGenTx(cdc, pubKey) + appMessage = am if err != nil { return err } validators = []tmtypes.GenesisValidator{validator} - appGenTxs = []json.RawMessage{appTx} - cliPrints = []json.RawMessage{cliPrint} + appGenTxs = []json.RawMessage{appGenTx} } - appState, err := appInit.GenAppParams(cdc, appGenTxs) + appState, err := appInit.AppGenState(cdc, appGenTxs) if err != nil { return err } @@ -156,13 +165,13 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { // print out some key information toPrint := struct { - ChainID string `json:"chain_id"` - NodeID string `json:"node_id"` - AppMessage []json.RawMessage `json:"app_messages"` + ChainID string `json:"chain_id"` + NodeID string `json:"node_id"` + AppMessage json.RawMessage `json:"app_message"` }{ chainID, nodeID, - cliPrints, + appMessage, } out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { @@ -174,47 +183,55 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { }, } cmd.Flags().BoolP(flagOverwrite, "o", false, "overwrite the genesis.json file") - cmd.Flags().String(flagChainID, "", "designated chain-id for the genesis") - cmd.Flags().AddFlagSet(appInit.FlagsAppParams) + cmd.Flags().String(flagChainID, "", "genesis file chain-id, if left blank will be randomly created") + cmd.Flags().String(flagGenTxs, "", "directory containing the genesis transactions") + 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 } // append a genesis-piece func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( - validators []tmtypes.GenesisValidator, appGenTxs, cliPrints []json.RawMessage, persistentPeers string, err error) { + validators []tmtypes.GenesisValidator, appGenTxs []json.RawMessage, persistentPeers string, err error) { - fos, err := ioutil.ReadDir(genTxsDir) + // XXX sort the files by contents just incase people renamed their files + var fos []os.FileInfo + fos, err = ioutil.ReadDir(genTxsDir) + if err != nil { + return + } for _, fo := range fos { filename := fo.Name() if !fo.IsDir() && (path.Ext(filename) != ".json") { - return nil + return } // get the genTx - bz, err := ioutil.ReadFile(filename) + var bz []byte + bz, err = ioutil.ReadFile(filename) if err != nil { - return err + return } var genTx GenesisTx err = cdc.UnmarshalJSON(bz, &genTx) if err != nil { - return err + return } // combine some stuff validators = append(validators, genTx.Validator) - appGenTxs = append(appGenTxs, genTx.AppGenTxs) - cliPrints = append(cliPrints, genTx.CliPrints) + appGenTxs = append(appGenTxs, genTx.AppGenTx) // Add a persistent peer comma := "," if len(persistentPeers) == 0 { comma = "" } - persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, piece.NodeID, piece.IP) + persistentPeers += fmt.Sprintf("%s%s@%s:46656", comma, genTx.NodeID, genTx.IP) } - return nil + return } //________________________________________________________________________________________ @@ -267,43 +284,44 @@ func addAppStateToGenesis(cdc *wire.Codec, genesisConfigPath string, appState js type AppInit struct { // flags required for application init functions - FlagsAppParams *pflag.FlagSet - FlagsAppTx *pflag.FlagSet + FlagsAppGenState *pflag.FlagSet + FlagsAppGenTx *pflag.FlagSet - // GenAppParams creates the core parameters initialization. It takes in a + // AppGenState creates the core parameters initialization. It takes in a // pubkey meant to represent the pubkey of the validator of this machine. - GenAppParams func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) + AppGenState func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) // create the application genesis tx - GenAppTx func(cdc *wire.Codec, pk crypto.PubKey) ( - appTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) + AppGenTx func(cdc *wire.Codec, pk crypto.PubKey) ( + appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) } +//_____________________________________________________________________ + // simple default application init var DefaultAppInit = AppInit{ - GenAppParams: SimpleGenAppParams, + AppGenState: SimpleAppGenState, + AppGenTx: SimpleAppGenTx, } -// Create one account with a whole bunch of mycoin in it -func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage) ( - validators []tmtypes.GenesisValidator, appState, cliPrint json.RawMessage, err error) { +// simple genesis tx +type SimpleGenTx struct { + Addr sdk.Address `json:"addr"` +} - var addr sdk.Address +// create the genesis app state +func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { - var secret string - addr, secret, err = GenerateCoinKey() - if err != nil { + if len(appGenTxs) != 1 { + err = errors.New("must provide a single genesis transaction") return } - mm := map[string]string{"secret": secret} - bz, err := cdc.MarshalJSON(mm) - cliPrint = json.RawMessage(bz) - - validators = []tmtypes.GenesisValidator{{ - PubKey: pubKey, - Power: 10, - }} + var genTx SimpleGenTx + err = cdc.UnmarshalJSON(appGenTxs[0], &genTx) + if err != nil { + return + } appState = json.RawMessage(fmt.Sprintf(`{ "accounts": [{ @@ -315,7 +333,40 @@ func SimpleGenAppParams(cdc *wire.Codec, pubKey crypto.PubKey, _ json.RawMessage } ] }] -}`, addr.String())) +}`, genTx.Addr.String())) + return +} + +// Generate a genesis transaction +func SimpleAppGenTx(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 = GenerateCoinKey() + if err != nil { + return + } + + var bz []byte + simpleGenTx := SimpleGenTx{addr} + bz, err = cdc.MarshalJSON(simpleGenTx) + 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: 10, + } return } diff --git a/server/init_test.go b/server/init_test.go index 5db4835160..1bdf0a085d 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -21,7 +21,8 @@ func TestInit(t *testing.T) { ctx := NewContext(cfg, logger) cdc := wire.NewCodec() appInit := AppInit{ - GenAppParams: mock.GenAppParams, + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, } cmd := InitCmd(ctx, cdc, appInit) err = cmd.RunE(nil, nil) diff --git a/server/start_test.go b/server/start_test.go index 85f1a7135e..3bf2eac7e4 100644 --- a/server/start_test.go +++ b/server/start_test.go @@ -28,7 +28,8 @@ func TestStartStandAlone(t *testing.T) { ctx := NewContext(cfg, logger) cdc := wire.NewCodec() appInit := AppInit{ - GenAppParams: mock.GenAppParams, + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, } initCmd := InitCmd(ctx, cdc, appInit) err = initCmd.RunE(nil, nil) @@ -58,7 +59,8 @@ func TestStartWithTendermint(t *testing.T) { ctx := NewContext(cfg, logger) cdc := wire.NewCodec() appInit := AppInit{ - GenAppParams: mock.GenAppParams, + AppGenState: mock.AppGenState, + AppGenTx: mock.AppGenTx, } initCmd := InitCmd(ctx, cdc, appInit) err = initCmd.RunE(nil, nil) From 7e2ac801377fb8947540c3b19be037cecdfc0683 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Apr 2018 16:38:13 -0400 Subject: [PATCH 16/22] cli testing fix --- cmd/gaia/cli_test/cli_test.go | 29 +++++++++++++++++++---------- tests/gobash.go | 11 ++++------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index b70d25551d..00d94861d1 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -13,13 +13,14 @@ import ( "github.com/cosmos/cosmos-sdk/cmd/gaia/app" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/tests" + "github.com/cosmos/cosmos-sdk/wire" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/cosmos/cosmos-sdk/x/stake" ) func TestGaiaCLISend(t *testing.T) { - tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) + tests.ExecuteT(t, "gaiad unsafe_reset_all") pass := "1234567890" executeWrite(t, "gaiacli keys delete foo", pass) executeWrite(t, "gaiacli keys delete bar", pass) @@ -53,9 +54,10 @@ func TestGaiaCLISend(t *testing.T) { func TestGaiaCLIDeclareCandidacy(t *testing.T) { - tests.ExecuteT(t, "gaiad unsafe_reset_all", 1) + tests.ExecuteT(t, "gaiad unsafe_reset_all") 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") // get a free port, also setup some common flags @@ -70,11 +72,14 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { 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") + + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10fermion --to=%v --name=foo", flags, barAddr), pass) time.Sleep(time.Second * 3) // waiting for some blocks to pass - barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) - assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) + fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", fooAddr, flags)) assert.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("fermion")) + barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) + assert.Equal(t, int64(10), barAcc.GetCoins().AmountOf("fermion")) // declare candidacy declStr := fmt.Sprintf("gaiacli declare-candidacy %v", flags) @@ -85,7 +90,7 @@ func TestGaiaCLIDeclareCandidacy(t *testing.T) { declStr += fmt.Sprintf(" --moniker=%v", "bar-vally") fmt.Printf("debug declStr: %v\n", declStr) executeWrite(t, declStr, pass) - time.Sleep(time.Second * 3) // waiting for some blocks to pass + time.Sleep(time.Second) // waiting for some blocks to pass barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %v %v", barAddr, flags)) assert.Equal(t, int64(7), barAcc.GetCoins().AmountOf("fermion")) candidate := executeGetCandidate(t, fmt.Sprintf("gaiacli candidate %v --address-candidate=%v", flags, barAddr)) @@ -116,6 +121,7 @@ func executeWrite(t *testing.T, cmdStr string, writes ...string) { _, err := wc.Write([]byte(write + "\n")) require.NoError(t, err) } + fmt.Printf("debug waiting cmdStr: %v\n", cmdStr) cmd.Wait() } @@ -126,6 +132,7 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) { _, err := wc.Write([]byte(write + "\n")) require.NoError(t, err) } + fmt.Printf("debug waiting cmdStr: %v\n", cmdStr) cmd.Wait() bz := make([]byte, 100000) @@ -134,7 +141,7 @@ func executeWritePrint(t *testing.T, cmdStr string, writes ...string) { } func executeInit(t *testing.T, cmdStr string) (key, chainID string) { - out := tests.ExecuteT(t, cmdStr, 1) + out := tests.ExecuteT(t, cmdStr) var initRes map[string]json.RawMessage err := json.Unmarshal([]byte(out), &initRes) @@ -154,26 +161,28 @@ func executeInit(t *testing.T, cmdStr string) (key, chainID string) { } func executeGetAddrPK(t *testing.T, cmdStr string) (addr, pubKey string) { - out := tests.ExecuteT(t, cmdStr, 2) + out := tests.ExecuteT(t, cmdStr) var ko keys.KeyOutput keys.UnmarshalJSON([]byte(out), &ko) return ko.Address, ko.PubKey } func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { - out := tests.ExecuteT(t, cmdStr, 2) + out := tests.ExecuteT(t, cmdStr) var initRes map[string]json.RawMessage err := json.Unmarshal([]byte(out), &initRes) require.NoError(t, err, "out %v, err %v", out, err) value := initRes["value"] var acc auth.BaseAccount - _ = json.Unmarshal(value, &acc) //XXX pubkey can't be decoded go amino issue + cdc := wire.NewCodec() + wire.RegisterCrypto(cdc) + err = cdc.UnmarshalJSON(value, &acc) require.NoError(t, err, "value %v, err %v", string(value), err) return acc } func executeGetCandidate(t *testing.T, cmdStr string) stake.Candidate { - out := tests.ExecuteT(t, cmdStr, 2) + out := tests.ExecuteT(t, cmdStr) var candidate stake.Candidate cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &candidate) diff --git a/tests/gobash.go b/tests/gobash.go index c106c1f3f2..baa84f417f 100644 --- a/tests/gobash.go +++ b/tests/gobash.go @@ -1,7 +1,6 @@ package tests import ( - "fmt" "io" "os/exec" "strings" @@ -27,13 +26,11 @@ func getCmd(t *testing.T, command string) *exec.Cmd { } // Execute the command, return standard output and error, try a few times if requested -func ExecuteT(t *testing.T, command string, trials int) (out string) { +func ExecuteT(t *testing.T, command string) (out string) { cmd := getCmd(t, command) bz, err := cmd.CombinedOutput() - if err != nil && trials > 1 { - fmt.Printf("trial %v, retrying: %v\n", trials, command) - time.Sleep(time.Second * 10) - return ExecuteT(t, command, trials-1) + if err != nil { + panic(err) } require.NoError(t, err, string(bz)) out = strings.Trim(string(bz), "\n") //trim any new lines @@ -48,7 +45,7 @@ func GoExecuteT(t *testing.T, command string) (cmd *exec.Cmd, pipeIn io.WriteClo require.NoError(t, err) pipeOut, err = cmd.StdoutPipe() require.NoError(t, err) - go cmd.Start() + cmd.Start() time.Sleep(time.Second) return cmd, pipeIn, pipeOut } From d1c6216c0f554525a6cd2ed4349b5acdc4e556b0 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Wed, 25 Apr 2018 17:17:40 -0400 Subject: [PATCH 17/22] gen-tx fix --- server/init.go | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/server/init.go b/server/init.go index 5916e38349..98b724caf5 100644 --- a/server/init.go +++ b/server/init.go @@ -32,7 +32,6 @@ type GenesisTx struct { IP string `json:"ip"` Validator tmtypes.GenesisValidator `json:"validator"` AppGenTx json.RawMessage `json:"app_gen_tx"` - CLIPrint json.RawMessage `json:"cli_print"` } var ( @@ -76,20 +75,28 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { IP: ip, Validator: validator, AppGenTx: appGenTx, - CLIPrint: cliPrint, } bz, err := wire.MarshalJSONIndent(cdc, tx) if err != nil { return err } + genTxFile := json.RawMessage(bz) name := fmt.Sprintf("gentx-%v.json", nodeID) file := filepath.Join(viper.GetString("home"), name) + err = cmn.WriteFile(file, bz, 0644) if err != nil { return err - err = cmn.WriteFile(file, bz, 0644) } - out, err := wire.MarshalJSONIndent(cdc, cliPrint) + // print out some key information + toPrint := struct { + AppMessage json.RawMessage `json:"app_message"` + GenTxFile json.RawMessage `json:"gen_tx_file"` + }{ + cliPrint, + genTxFile, + } + out, err := wire.MarshalJSONIndent(cdc, toPrint) if err != nil { return err } @@ -202,7 +209,7 @@ func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( return } for _, fo := range fos { - filename := fo.Name() + filename := path.Join(genTxsDir, fo.Name()) if !fo.IsDir() && (path.Ext(filename) != ".json") { return } From 05c5809bae10a858b36457366d47395d69168850 Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Apr 2018 00:27:40 -0400 Subject: [PATCH 18/22] gaia init automatic key processing --- client/keys/utils.go | 7 +- cmd/gaia/app/app.go | 165 ++------------------------------ cmd/gaia/app/genesis.go | 175 ++++++++++++++++++++++++++++++++++ cmd/gaia/cli_test/cli_test.go | 20 +--- cmd/gaia/cmd/gaiacli/main.go | 4 +- cmd/gaia/cmd/gaiad/main.go | 4 +- server/init.go | 42 ++++++-- server/tm_cmds.go | 4 +- 8 files changed, 233 insertions(+), 188 deletions(-) create mode 100644 cmd/gaia/app/genesis.go 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) From ade42e74b7d3b6b700e9de05b3d95f34b67f345a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Apr 2018 00:49:53 -0400 Subject: [PATCH 19/22] better init test --- cmd/gaia/app/genesis.go | 82 ++++++++++++++++++------------------ cmd/gaia/app/genesis_test.go | 33 +++++++++++++++ server/init.go | 74 ++++++++++++++++---------------- server/init_test.go | 15 ++++++- 4 files changed, 125 insertions(+), 79 deletions(-) create mode 100644 cmd/gaia/app/genesis_test.go diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 66fd1f98d9..513430ec9a 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -65,8 +65,8 @@ func GaiaAppInit() server.AppInit { return server.AppInit{ FlagsAppGenState: fsAppGenState, FlagsAppGenTx: fsAppGenTx, - AppGenState: GaiaAppGenState, AppGenTx: GaiaAppGenTx, + AppGenState: GaiaAppGenState, } } @@ -77,7 +77,45 @@ type GaiaGenTx struct { PubKey crypto.PubKey `json:"pub_key"` } -// power given to validators in gaia init functions +// 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 +} // Create the core parameters for genesis initialization for gaia // note that the pubkey input is this machines pubkey @@ -133,43 +171,3 @@ func GaiaAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState jso 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/app/genesis_test.go b/cmd/gaia/app/genesis_test.go new file mode 100644 index 0000000000..94bcdd0df4 --- /dev/null +++ b/cmd/gaia/app/genesis_test.go @@ -0,0 +1,33 @@ +package app + +import ( + "testing" + + "github.com/cosmos/cosmos-sdk/x/auth" + "github.com/stretchr/testify/assert" + crypto "github.com/tendermint/go-crypto" +) + +func TestToAccount(t *testing.T) { + priv = crypto.GenPrivKeyEd25519() + addr = priv.PubKey().Address() + authAcc := auth.NewBaseAccountWithAddress(addr) + genAcc := NewGenesisAccount(authAcc) + assert.Equal(t, authAcc, genAcc.ToAccount()) +} + +func TestGaiaAppGenTx(t *testing.T) { + cdc := MakeCodec() + + //TODO test that key overwrite flags work / no overwrites if set off + //TODO test validator created has provided pubkey + //TODO test the account created has the correct pubkey +} + +func TestGaiaAppGenState(t *testing.T) { + cdc := MakeCodec() + + // TODO test must provide at least genesis transaction + // TODO test with both one and two genesis transactions: + // TODO correct: genesis account created, canididates created, pool token variance +} diff --git a/server/init.go b/server/init.go index d23d78b818..af735f0927 100644 --- a/server/init.go +++ b/server/init.go @@ -58,7 +58,7 @@ func GenTxCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return err } nodeID := string(nodeKey.ID()) - pubKey := ReadOrCreatePrivValidator(config) + pubKey := readOrCreatePrivValidator(config) appGenTx, cliPrint, validator, err := appInit.AppGenTx(cdc, pubKey) if err != nil { @@ -126,7 +126,7 @@ func InitCmd(ctx *Context, cdc *wire.Codec, appInit AppInit) *cobra.Command { return err } nodeID := string(nodeKey.ID()) - pubKey := ReadOrCreatePrivValidator(config) + pubKey := readOrCreatePrivValidator(config) chainID := viper.GetString(flagChainID) if chainID == "" { @@ -247,7 +247,7 @@ func processGenTxs(genTxsDir string, cdc *wire.Codec, appInit AppInit) ( //________________________________________________________________________________________ // read of create the private key file for this config -func ReadOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { +func readOrCreatePrivValidator(tmConfig *cfg.Config) crypto.PubKey { // private validator privValFile := tmConfig.PrivValidatorFile() var privValidator *pvm.FilePV @@ -297,21 +297,21 @@ type AppInit struct { FlagsAppGenState *pflag.FlagSet FlagsAppGenTx *pflag.FlagSet - // AppGenState creates the core parameters initialization. It takes in a - // pubkey meant to represent the pubkey of the validator of this machine. - AppGenState func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) - // create the application genesis tx AppGenTx func(cdc *wire.Codec, pk crypto.PubKey) ( appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) + + // AppGenState creates the core parameters initialization. It takes in a + // pubkey meant to represent the pubkey of the validator of this machine. + AppGenState func(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) } //_____________________________________________________________________ // simple default application init var DefaultAppInit = AppInit{ - AppGenState: SimpleAppGenState, AppGenTx: SimpleAppGenTx, + AppGenState: SimpleAppGenState, } // simple genesis tx @@ -319,34 +319,6 @@ type SimpleGenTx struct { Addr sdk.Address `json:"addr"` } -// create the genesis app state -func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { - - if len(appGenTxs) != 1 { - err = errors.New("must provide a single genesis transaction") - return - } - - var genTx SimpleGenTx - err = cdc.UnmarshalJSON(appGenTxs[0], &genTx) - if err != nil { - return - } - - appState = json.RawMessage(fmt.Sprintf(`{ - "accounts": [{ - "address": "%s", - "coins": [ - { - "denom": "mycoin", - "amount": 9007199254740992 - } - ] - }] -}`, genTx.Addr.String())) - return -} - // Generate a genesis transaction func SimpleAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { @@ -380,6 +352,36 @@ func SimpleAppGenTx(cdc *wire.Codec, pk crypto.PubKey) ( return } +// create the genesis app state +func SimpleAppGenState(cdc *wire.Codec, appGenTxs []json.RawMessage) (appState json.RawMessage, err error) { + + if len(appGenTxs) != 1 { + err = errors.New("must provide a single genesis transaction") + return + } + + var genTx SimpleGenTx + err = cdc.UnmarshalJSON(appGenTxs[0], &genTx) + if err != nil { + return + } + + appState = json.RawMessage(fmt.Sprintf(`{ + "accounts": [{ + "address": "%s", + "coins": [ + { + "denom": "mycoin", + "amount": 9007199254740992 + } + ] + }] +}`, genTx.Addr.String())) + return +} + +//___________________________________________________________________________________________ + // GenerateCoinKey returns the address of a public key, along with the secret // phrase to recover the private key. func GenerateCoinKey() (sdk.Address, string, error) { diff --git a/server/init_test.go b/server/init_test.go index 1bdf0a085d..eca5295052 100644 --- a/server/init_test.go +++ b/server/init_test.go @@ -12,7 +12,8 @@ import ( tcmd "github.com/tendermint/tendermint/cmd/tendermint/commands" ) -func TestInit(t *testing.T) { +// TODO update +func TestInitCmd(t *testing.T) { defer setupViper(t)() logger := log.NewNopLogger() @@ -28,3 +29,15 @@ func TestInit(t *testing.T) { err = cmd.RunE(nil, nil) require.NoError(t, err) } + +func TestGenTxCmd(t *testing.T) { + // TODO +} + +func TestSimpleAppGenTx(t *testing.T) { + // TODO +} + +func TestSimpleAppGenState(t *testing.T) { + // TODO +} From 514b3fba4ebebfd609e28e357c2e8844bbe76e9a Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Apr 2018 14:16:17 -0400 Subject: [PATCH 20/22] fix genesis tests --- cmd/gaia/app/genesis_test.go | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/cmd/gaia/app/genesis_test.go b/cmd/gaia/app/genesis_test.go index 94bcdd0df4..03ff46e50d 100644 --- a/cmd/gaia/app/genesis_test.go +++ b/cmd/gaia/app/genesis_test.go @@ -3,21 +3,23 @@ package app import ( "testing" + sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/auth" "github.com/stretchr/testify/assert" crypto "github.com/tendermint/go-crypto" ) func TestToAccount(t *testing.T) { - priv = crypto.GenPrivKeyEd25519() - addr = priv.PubKey().Address() + priv := crypto.GenPrivKeyEd25519() + addr := sdk.Address(priv.PubKey().Address()) authAcc := auth.NewBaseAccountWithAddress(addr) - genAcc := NewGenesisAccount(authAcc) - assert.Equal(t, authAcc, genAcc.ToAccount()) + genAcc := NewGenesisAccount(&authAcc) + assert.Equal(t, authAcc, *genAcc.ToAccount()) } func TestGaiaAppGenTx(t *testing.T) { cdc := MakeCodec() + _ = cdc //TODO test that key overwrite flags work / no overwrites if set off //TODO test validator created has provided pubkey @@ -26,6 +28,7 @@ func TestGaiaAppGenTx(t *testing.T) { func TestGaiaAppGenState(t *testing.T) { cdc := MakeCodec() + _ = cdc // TODO test must provide at least genesis transaction // TODO test with both one and two genesis transactions: From 3a4813ff01b25b4a2b67bbd089cd70af256092db Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Apr 2018 14:20:20 -0400 Subject: [PATCH 21/22] added test_nocli for fast non-cli tests --- Makefile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Makefile b/Makefile index 4381eea82f..855d963570 100644 --- a/Makefile +++ b/Makefile @@ -85,6 +85,9 @@ godocs: test: test_unit # test_cli +test_nocli: + go test `go list ./... | grep -v github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` + # Must be run in each package seperately for the visualization # Added here for easy reference # coverage: From 9b645836e36389466a5e088b9a3c240963e4bc8c Mon Sep 17 00:00:00 2001 From: rigelrozanski Date: Thu, 26 Apr 2018 14:33:02 -0400 Subject: [PATCH 22/22] changelog for better init --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 618db746aa..539c997355 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,10 @@ FEATURES: * MountStoreWithDB without providing a custom store works. * Repo is now lint compliant / GoMetaLinter with tendermint-lint integrated into CI * Better key output, pubkey go-amino hex bytes now output by default +* gaiad init overhaul + * Create genesis transactions with `gaiad init gen-tx` + * New genesis account keys are automatically added to the client keybase (introduce `--client-home` flag) + * Initialize with genesis txs using `--gen-txs` flag BREAKING CHANGES @@ -25,6 +29,7 @@ BREAKING CHANGES * Type as a prefix naming convention applied (ex. BondMsg -> MsgBond) * Removed redundancy in names (ex. stake.StakeKeeper -> stake.Keeper) * Removed SealedAccountMapper +* gaiad init now requires use of `--name` flag BUG FIXES * Gaia now uses stake, ported from github.com/cosmos/gaia