diff --git a/Makefile b/Makefile index 914ce3683..de4634824 100644 --- a/Makefile +++ b/Makefile @@ -152,7 +152,7 @@ godocs: test: test_unit test_cli: - @go test -count 1 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -tags=cli_test + @go test -p 4 `go list github.com/cosmos/cosmos-sdk/cmd/gaia/cli_test` -tags=cli_test test_examples: @go test -count 1 -p 1 `go list github.com/cosmos/cosmos-sdk/docs/examples/basecoin/cli_test` -tags=cli_test diff --git a/PENDING.md b/PENDING.md index fbb089f95..c38baa625 100644 --- a/PENDING.md +++ b/PENDING.md @@ -6,6 +6,7 @@ BREAKING CHANGES * Gaia CLI (`gaiacli`) * [cli] [\#2595](https://github.com/cosmos/cosmos-sdk/issues/2595) Remove `keys new` in favor of `keys add` incorporating existing functionality with addition of key recovery functionality. + * [cli] [\#2971](https://github.com/cosmos/cosmos-sdk/pull/2971) Additional verification when running `gaiad gentx` * Gaia - [#128](https://github.com/tendermint/devops/issues/128) Updated CircleCI job to trigger website build on every push to master/develop. @@ -39,7 +40,7 @@ IMPROVEMENTS * SDK - \#1277 Complete bank module specification - + * Tendermint diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index 60e96307b..d81d7d987 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -209,6 +209,7 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm if err := cdc.UnmarshalJSON(genDoc.AppState, &appState); err != nil { return appGenTxs, persistentPeers, err } + addrMap := make(map[string]GenesisAccount, len(appState.Accounts)) for i := 0; i < len(appState.Accounts); i++ { acc := appState.Accounts[i] @@ -257,13 +258,17 @@ func CollectStdTxs(cdc *codec.Codec, moniker string, genTxsDir string, genDoc tm msg := msgs[0].(stake.MsgCreateValidator) addr := string(sdk.AccAddress(msg.ValidatorAddr)) acc, ok := addrMap[addr] + if !ok { return appGenTxs, persistentPeers, fmt.Errorf( "account %v not in genesis.json: %+v", addr, addrMap) } + if acc.Coins.AmountOf(msg.Delegation.Denom).LT(msg.Delegation.Amount) { - err = fmt.Errorf("insufficient fund for the delegation: %v < %v", - acc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount) + return appGenTxs, persistentPeers, fmt.Errorf( + "insufficient fund for delegation %v: %v < %v", + acc.Address, acc.Coins.AmountOf(msg.Delegation.Denom), msg.Delegation.Amount, + ) } // exclude itself from persistent peers diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 524b5aac5..3ddaa144d 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -33,12 +33,12 @@ import ( ) func TestGaiaCLIMinimumFees(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) // start gaiad server with minimum fees - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --minimum_fees=2feeToken", gaiadHome, servAddr)) + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v --minimum_fees=2feeToken", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -57,12 +57,12 @@ func TestGaiaCLIMinimumFees(t *testing.T) { } func TestGaiaCLIFeesDeduction(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) // start gaiad server with minimum fees - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --minimum_fees=1fooToken", gaiadHome, servAddr)) + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v --minimum_fees=1fooToken", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -100,13 +100,12 @@ func TestGaiaCLIFeesDeduction(t *testing.T) { } func TestGaiaCLISend(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) - + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) tests.WaitForNextNBlocksTM(1, port) @@ -153,12 +152,12 @@ func TestGaiaCLISend(t *testing.T) { } func TestGaiaCLIGasAuto(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -206,12 +205,12 @@ func TestGaiaCLIGasAuto(t *testing.T) { } func TestGaiaCLICreateValidator(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --chain-id=%v --node=%s", gaiacliHome, chainID, servAddr) // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -305,12 +304,12 @@ func TestGaiaCLICreateValidator(t *testing.T) { } func TestGaiaCLISubmitProposal(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -459,13 +458,12 @@ func TestGaiaCLISubmitProposal(t *testing.T) { } func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - chainID, servAddr, port := initializeFixtures(t, gaiadHome, gaiacliHome) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr := initializeFixtures(t) flags := fmt.Sprintf("--home=%s --node=%v --chain-id=%v", gaiacliHome, servAddr, chainID) // start gaiad server - proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf( - "gaiad start --home=%s --rpc.laddr=%v", gaiadHome, servAddr)) + proc := tests.GoExecuteTWithStdout(t, fmt.Sprintf("gaiad start --home=%s --rpc.laddr=%v --p2p.laddr=%v", gaiadHome, servAddr, p2pAddr)) defer proc.Stop(false) tests.WaitForTMStart(port) @@ -562,11 +560,9 @@ func TestGaiaCLISendGenerateSignAndBroadcast(t *testing.T) { } func TestGaiaCLIConfig(t *testing.T) { - gaiadHome, gaiacliHome := getTestingHomeDirs(t) - servAddr, port, err := server.FreeTCPAddr() - require.NoError(t, err) + t.Parallel() + chainID, servAddr, port, gaiadHome, gaiacliHome, _ := initializeFixtures(t) node := fmt.Sprintf("%s:%s", servAddr, port) - chainID := executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome)) executeWrite(t, fmt.Sprintf("gaiacli --home=%s config", gaiadHome), gaiacliHome, node, "y") config, err := ioutil.ReadFile(path.Join(gaiacliHome, "config", "config.toml")) require.NoError(t, err) @@ -604,40 +600,34 @@ trust_node = true //___________________________________________________________________________________ // helper methods -func getTestingHomeDirs(t *testing.T) (string, string) { - tmpDir, err := ioutil.TempDir("", t.Name()) - require.NoError(t, err) - gaiadHome := fmt.Sprintf("%s%s.test_gaiad", tmpDir, string(os.PathSeparator)) - gaiacliHome := fmt.Sprintf("%s%s.test_gaiacli", tmpDir, string(os.PathSeparator)) +func getTestingHomeDirs(name string) (string, string) { + tmpDir := os.TempDir() + gaiadHome := fmt.Sprintf("%s%s%s%s.test_gaiad", tmpDir, string(os.PathSeparator), name, string(os.PathSeparator)) + gaiacliHome := fmt.Sprintf("%s%s%s%s.test_gaiacli", tmpDir, string(os.PathSeparator), name, string(os.PathSeparator)) return gaiadHome, gaiacliHome } -func initializeFixtures(t *testing.T, gaiadHome, gaiacliHome string) (chainID, servAddr, port string) { +func initializeFixtures(t *testing.T) (chainID, servAddr, port, gaiadHome, gaiacliHome, p2pAddr string) { + gaiadHome, gaiacliHome = getTestingHomeDirs(t.Name()) tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe-reset-all", gaiadHome), "") os.RemoveAll(filepath.Join(gaiadHome, "config", "gentx")) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s --force foo", gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s --force bar", gaiacliHome)) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), app.DefaultKeyPass) + executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), app.DefaultKeyPass) executeWriteCheckErr(t, fmt.Sprintf("gaiacli keys add --home=%s foo", gaiacliHome), app.DefaultKeyPass) executeWriteCheckErr(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) - fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf( - "gaiacli keys show foo --output=json --home=%s", gaiacliHome)) + fooAddr, _ := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show foo --output=json --home=%s", gaiacliHome)) chainID = executeInit(t, fmt.Sprintf("gaiad init -o --moniker=foo --home=%s", gaiadHome)) - genFile := filepath.Join(gaiadHome, "config", "genesis.json") - genDoc := readGenesisFile(t, genFile) - var appState app.GenesisState - err := codec.Cdc.UnmarshalJSON(genDoc.AppState, &appState) - require.NoError(t, err) - appState.Accounts = []app.GenesisAccount{app.NewDefaultGenesisAccount(fooAddr)} - appStateJSON, err := codec.Cdc.MarshalJSON(appState) - require.NoError(t, err) - genDoc.AppState = appStateJSON - genDoc.SaveAs(genFile) + executeWriteCheckErr(t, fmt.Sprintf( - "gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome), - app.DefaultKeyPass) + "gaiad add-genesis-account %s 150%s,1000fooToken --home=%s", fooAddr, stakeTypes.DefaultBondDenom, gaiadHome)) + executeWrite(t, fmt.Sprintf("cat %s%sconfig%sgenesis.json", gaiadHome, string(os.PathSeparator), string(os.PathSeparator))) + executeWriteCheckErr(t, fmt.Sprintf( + "gaiad gentx --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome), app.DefaultKeyPass) executeWriteCheckErr(t, fmt.Sprintf("gaiad collect-gentxs --home=%s", gaiadHome), app.DefaultKeyPass) // get a free port, also setup some common flags - servAddr, port, err = server.FreeTCPAddr() + servAddr, port, err := server.FreeTCPAddr() + require.NoError(t, err) + p2pAddr, _, err = server.FreeTCPAddr() require.NoError(t, err) return } diff --git a/cmd/gaia/init/gentx.go b/cmd/gaia/init/gentx.go index b8392d3bd..b68481b3b 100644 --- a/cmd/gaia/init/gentx.go +++ b/cmd/gaia/init/gentx.go @@ -64,18 +64,25 @@ following delegation and commission default parameters: if err != nil { return err } + genDoc, err := loadGenesisDoc(cdc, config.GenesisFile()) if err != nil { return err } + genesisState := app.GenesisState{} + if err = cdc.UnmarshalJSON(genDoc.AppState, &genesisState); err != nil { + return err + } + kb, err := keys.GetKeyBaseFromDir(viper.GetString(flagClientHome)) if err != nil { return err } name := viper.GetString(client.FlagName) - if _, err := kb.Get(name); err != nil { + key, err := kb.Get(name) + if err != nil { return err } @@ -86,8 +93,23 @@ following delegation and commission default parameters: return err } } - // Run gaiad tx create-validator + + // Set flags for creating gentx prepareFlagsForTxCreateValidator(config, nodeID, ip, genDoc.ChainID, valPubKey) + + // Fetch the amount of coins staked + amount := viper.GetString(cli.FlagAmount) + coins, err := sdk.ParseCoins(amount) + if err != nil { + return err + } + + err = accountInGenesis(genesisState, key.GetAddress(), coins) + if err != nil { + return err + } + + // Run gaiad tx create-validator txBldr := authtxb.NewTxBuilderFromCLI().WithCodec(cdc) cliCtx := context.NewCLIContext().WithCodec(cdc) cliCtx, txBldr, msg, err := cli.BuildCreateValidatorMsg(cliCtx, txBldr) @@ -113,13 +135,16 @@ following delegation and commission default parameters: return err } + // Fetch output file name outputDocument, err := makeOutputFilepath(config.RootDir, nodeID) if err != nil { return err } + if err := writeSignedGenTx(cdc, outputDocument, signedTx); err != nil { return err } + fmt.Fprintf(os.Stderr, "Genesis transaction written to %q\n", outputDocument) return nil }, @@ -135,6 +160,34 @@ following delegation and commission default parameters: return cmd } +func accountInGenesis(genesisState app.GenesisState, key sdk.AccAddress, coins sdk.Coins) error { + accountIsInGenesis := false + bondDenom := genesisState.StakeData.Params.BondDenom + + // Check if the account is in genesis + for _, acc := range genesisState.Accounts { + // Ensure that account is in genesis + if acc.Address.Equals(key) { + + // Ensure account contains enough funds of default bond denom + if coins.AmountOf(bondDenom).GT(acc.Coins.AmountOf(bondDenom)) { + return fmt.Errorf( + "Account %s is in genesis, but the only has %s%s available to stake, not %s%s", + key, acc.Coins.AmountOf(bondDenom), bondDenom, coins.AmountOf(bondDenom), bondDenom, + ) + } + accountIsInGenesis = true + break + } + } + + if accountIsInGenesis { + return nil + } + + return fmt.Errorf("Account %s in not in the app_state.accounts array of genesis.json", key) +} + func prepareFlagsForTxCreateValidator(config *cfg.Config, nodeID, ip, chainID string, valPubKey crypto.PubKey) { viper.Set(tmcli.HomeFlag, viper.GetString(flagClientHome)) // --home diff --git a/tests/gobash.go b/tests/gobash.go index 87d56a297..9c4312c6d 100644 --- a/tests/gobash.go +++ b/tests/gobash.go @@ -92,12 +92,18 @@ func GoExecuteTWithStdout(t *testing.T, cmd string) (proc *Process) { require.NoError(t, err) // Without this, the test halts ?! + // (theory: because stdout and/or err aren't connected to anything the process halts) go func() { _, err := ioutil.ReadAll(proc.StdoutPipe) if err != nil { fmt.Println("-------------ERR-----------------------", err) return } + _, err = ioutil.ReadAll(proc.StderrPipe) + if err != nil { + fmt.Println("-------------ERR-----------------------", err) + return + } }() err = proc.Cmd.Start() diff --git a/tests/util.go b/tests/util.go index 48649eaf7..783824373 100644 --- a/tests/util.go +++ b/tests/util.go @@ -6,11 +6,12 @@ import ( "net/http" "time" + "strings" + amino "github.com/tendermint/go-amino" tmclient "github.com/tendermint/tendermint/rpc/client" ctypes "github.com/tendermint/tendermint/rpc/core/types" rpcclient "github.com/tendermint/tendermint/rpc/lib/client" - "strings" ) // Wait for the next tendermint block from the Tendermint RPC @@ -109,8 +110,6 @@ func waitForHeight(height int64, url string) { var resultBlock ctypes.ResultBlock err = cdc.UnmarshalJSON(body, &resultBlock) if err != nil { - fmt.Println("RES", res) - fmt.Println("BODY", string(body)) panic(err) } @@ -135,7 +134,7 @@ func WaitForTMStart(port string) { } // WaitForStart waits for the node to start by pinging the url -// every 100ms for 5s until it returns 200. If it takes longer than 5s, +// every 100ms for 10s until it returns 200. If it takes longer than 5s, // it panics. func WaitForStart(url string) { var err error @@ -143,7 +142,7 @@ func WaitForStart(url string) { // ping the status endpoint a few times a second // for a few seconds until we get a good response. // otherwise something probably went wrong - for i := 0; i < 50; i++ { + for i := 0; i < 100; i++ { time.Sleep(time.Millisecond * 100) var res *http.Response