From adafa79dc6aeae372ca1393ccc653bfe73168629 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 1 Aug 2018 09:06:54 -0400 Subject: [PATCH 1/2] Merge pull request #1856: gen-tx: Support User Given Key Passwords --- PENDING.md | 1 + client/input.go | 7 ++++- cmd/gaia/app/genesis.go | 57 ++++++++++++++++++++++++---------- cmd/gaia/cli_test/cli_test.go | 58 +++++++++++++++++------------------ cmd/gaia/testnets/README.md | 7 +++-- tests/gobash.go | 23 +++++++++----- 6 files changed, 97 insertions(+), 56 deletions(-) diff --git a/PENDING.md b/PENDING.md index 5337626eae4c..f13f3021e8fe 100644 --- a/PENDING.md +++ b/PENDING.md @@ -27,6 +27,7 @@ BREAKING CHANGES * [x/gov] Governance parameters are now stored in globalparams store * [lcd] \#1866 Updated lcd /slashing/signing_info endpoint to take cosmosvalpub instead of cosmosvaladdr * [types] sdk.NewCoin now takes sdk.Int, sdk.NewInt64Coin takes int64 +* [cli] Genesis/key creation (`init`) now supports user-provided key passwords FEATURES * [lcd] Can now query governance proposals by ProposalStatus diff --git a/client/input.go b/client/input.go index 03140a33c327..e7d13f3bfdbe 100644 --- a/client/input.go +++ b/client/input.go @@ -28,12 +28,17 @@ func GetPassword(prompt string, buf *bufio.Reader) (pass string, err error) { } else { pass, err = readLineFromBuf(buf) } + if err != nil { return "", err } + if len(pass) < MinPassLength { - return "", errors.Errorf("password must be at least %d characters", MinPassLength) + // Return the given password to the upstream client so it can handle a + // non-STDIN failure gracefully. + return pass, errors.Errorf("password must be at least %d characters", MinPassLength) } + return pass, nil } diff --git a/cmd/gaia/app/genesis.go b/cmd/gaia/app/genesis.go index af547e844620..1731fe2dc5d4 100644 --- a/cmd/gaia/app/genesis.go +++ b/cmd/gaia/app/genesis.go @@ -3,19 +3,25 @@ package app import ( "encoding/json" "errors" + "fmt" - "github.com/spf13/pflag" - "github.com/tendermint/tendermint/crypto" - tmtypes "github.com/tendermint/tendermint/types" - + "github.com/cosmos/cosmos-sdk/client" "github.com/cosmos/cosmos-sdk/server" "github.com/cosmos/cosmos-sdk/server/config" 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" + + "github.com/spf13/pflag" + + "github.com/tendermint/tendermint/crypto" + tmtypes "github.com/tendermint/tendermint/types" ) +// DefaultKeyPass contains the default key password for genesis transactions +const DefaultKeyPass = "12345678" + var ( // bonded tokens given to genesis validators/accounts freeFermionVal = int64(100) @@ -81,30 +87,49 @@ type GaiaGenTx struct { PubKey string `json:"pub_key"` } -// Generate a gaia genesis transaction with flags -func GaiaAppGenTx(cdc *wire.Codec, pk crypto.PubKey, genTxConfig config.GenTx) ( - appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { +// GaiaAppGenTx generates a Gaia genesis transaction. +func GaiaAppGenTx( + cdc *wire.Codec, pk crypto.PubKey, genTxConfig config.GenTx, +) (appGenTx, cliPrint json.RawMessage, validator tmtypes.GenesisValidator, err error) { if genTxConfig.Name == "" { return nil, nil, tmtypes.GenesisValidator{}, errors.New("Must specify --name (validator moniker)") } - var addr sdk.AccAddress - var secret string - addr, secret, err = server.GenerateSaveCoinKey(genTxConfig.CliRoot, genTxConfig.Name, "1234567890", genTxConfig.Overwrite) + buf := client.BufferStdin() + prompt := fmt.Sprintf("Password for account '%s' (default %s):", genTxConfig.Name, DefaultKeyPass) + + keyPass, err := client.GetPassword(prompt, buf) + if err != nil && keyPass != "" { + // An error was returned that either failed to read the password from + // STDIN or the given password is not empty but failed to meet minimum + // length requirements. + return appGenTx, cliPrint, validator, err + } + + if keyPass == "" { + keyPass = DefaultKeyPass + } + + addr, secret, err := server.GenerateSaveCoinKey( + genTxConfig.CliRoot, + genTxConfig.Name, + keyPass, + genTxConfig.Overwrite, + ) if err != nil { - return + return appGenTx, cliPrint, validator, err } + mm := map[string]string{"secret": secret} - var bz []byte - bz, err = cdc.MarshalJSON(mm) + bz, err := cdc.MarshalJSON(mm) if err != nil { - return + return appGenTx, cliPrint, validator, err } cliPrint = json.RawMessage(bz) - appGenTx, _, validator, err = GaiaAppGenTxNF(cdc, pk, addr, genTxConfig.Name) - return + + return appGenTx, cliPrint, validator, err } // Generate a gaia genesis transaction without flags diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index 20d11435b3e3..f3ef2f5fe759 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -25,7 +25,6 @@ import ( ) var ( - pass = "1234567890" gaiadHome = "" gaiacliHome = "" ) @@ -35,11 +34,12 @@ func init() { } func TestGaiaCLISend(t *testing.T) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome), "") + 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) + chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) // get a free port, also setup some common flags servAddr, port, err := server.FreeTCPAddr() @@ -59,7 +59,7 @@ func TestGaiaCLISend(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -68,7 +68,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(40), fooAcc.GetCoins().AmountOf("steak").Int64()) // test autosequencing - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -77,7 +77,7 @@ func TestGaiaCLISend(t *testing.T) { require.Equal(t, int64(30), fooAcc.GetCoins().AmountOf("steak").Int64()) // test memo - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo --memo 'testmemo'", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -87,11 +87,11 @@ func TestGaiaCLISend(t *testing.T) { } func TestGaiaCLICreateValidator(t *testing.T) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome), "") + 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) chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) // get a free port, also setup some common flags servAddr, port, err := server.FreeTCPAddr() @@ -109,7 +109,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { barAddr, barPubKey := executeGetAddrPK(t, fmt.Sprintf("gaiacli keys show bar --output=json --home=%s", gaiacliHome)) barCeshPubKey := sdk.MustBech32ifyValPub(barPubKey) - executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), pass) + executeWrite(t, fmt.Sprintf("gaiacli send %v --amount=10steak --to=%s --from=foo", flags, barAddr), app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -124,7 +124,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { cvStr += fmt.Sprintf(" --amount=%v", "2steak") cvStr += fmt.Sprintf(" --moniker=%v", "bar-vally") - executeWrite(t, cvStr, pass) + executeWrite(t, cvStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) barAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", barAddr, flags)) @@ -140,7 +140,7 @@ func TestGaiaCLICreateValidator(t *testing.T) { unbondStr += fmt.Sprintf(" --address-validator=%s", barAddr) unbondStr += fmt.Sprintf(" --shares-amount=%v", "1") - success := executeWrite(t, unbondStr, pass) + success := executeWrite(t, unbondStr, app.DefaultKeyPass) require.True(t, success) tests.WaitForNextNBlocksTM(2, port) @@ -153,11 +153,11 @@ func TestGaiaCLICreateValidator(t *testing.T) { } func TestGaiaCLISubmitProposal(t *testing.T) { - tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s foo", gaiacliHome), pass) - executeWrite(t, fmt.Sprintf("gaiacli keys delete --home=%s bar", gaiacliHome), pass) + tests.ExecuteT(t, fmt.Sprintf("gaiad --home=%s unsafe_reset_all", gaiadHome), "") + 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) chainID := executeInit(t, fmt.Sprintf("gaiad init -o --name=foo --home=%s --home-client=%s", gaiadHome, gaiacliHome)) - executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), pass) + executeWrite(t, fmt.Sprintf("gaiacli keys add --home=%s bar", gaiacliHome), app.DefaultKeyPass) // get a free port, also setup some common flags servAddr, port, err := server.FreeTCPAddr() @@ -187,7 +187,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { spStr += fmt.Sprintf(" --title=%s", "Test") spStr += fmt.Sprintf(" --description=%s", "test") - executeWrite(t, spStr, pass) + executeWrite(t, spStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) @@ -205,7 +205,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { depositStr += fmt.Sprintf(" --deposit=%s", "10steak") depositStr += fmt.Sprintf(" --proposal-id=%s", "1") - executeWrite(t, depositStr, pass) + executeWrite(t, depositStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) fooAcc = executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) @@ -219,7 +219,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { voteStr += fmt.Sprintf(" --proposal-id=%s", "1") voteStr += fmt.Sprintf(" --option=%s", "Yes") - executeWrite(t, voteStr, pass) + executeWrite(t, voteStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) vote := executeGetVote(t, fmt.Sprintf("gaiacli gov query-vote --proposal-id=1 --voter=%s --output=json %v", fooAddr, flags)) @@ -291,7 +291,7 @@ func executeWrite(t *testing.T, cmdStr string, writes ...string) bool { } func executeInit(t *testing.T, cmdStr string) (chainID string) { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, app.DefaultKeyPass) var initRes map[string]json.RawMessage err := json.Unmarshal([]byte(out), &initRes) @@ -304,7 +304,7 @@ func executeInit(t *testing.T, cmdStr string) (chainID string) { } func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKey) { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var ko keys.KeyOutput keys.UnmarshalJSON([]byte(out), &ko) @@ -315,7 +315,7 @@ func executeGetAddrPK(t *testing.T, cmdStr string) (sdk.AccAddress, crypto.PubKe } func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { - out := tests.ExecuteT(t, cmdStr) + 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) @@ -329,7 +329,7 @@ func executeGetAccount(t *testing.T, cmdStr string) auth.BaseAccount { } func executeGetValidator(t *testing.T, cmdStr string) stake.Validator { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var validator stake.Validator cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &validator) @@ -338,7 +338,7 @@ func executeGetValidator(t *testing.T, cmdStr string) stake.Validator { } func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var proposal gov.Proposal cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &proposal) @@ -347,7 +347,7 @@ func executeGetProposal(t *testing.T, cmdStr string) gov.Proposal { } func executeGetVote(t *testing.T, cmdStr string) gov.Vote { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var vote gov.Vote cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &vote) @@ -356,7 +356,7 @@ func executeGetVote(t *testing.T, cmdStr string) gov.Vote { } func executeGetVotes(t *testing.T, cmdStr string) []gov.Vote { - out := tests.ExecuteT(t, cmdStr) + out := tests.ExecuteT(t, cmdStr, "") var votes []gov.Vote cdc := app.MakeCodec() err := cdc.UnmarshalJSON([]byte(out), &votes) diff --git a/cmd/gaia/testnets/README.md b/cmd/gaia/testnets/README.md index 7c339a8c1393..ddfeef54c617 100644 --- a/cmd/gaia/testnets/README.md +++ b/cmd/gaia/testnets/README.md @@ -476,13 +476,16 @@ gaiacli account --block= ## Create your Own Testnet -To create your own testnet, first each validator will need to install gaiad and run gen-tx +To create your own testnet, first each validator will need to install gaiad and +run `gen-tx`: ```bash gaiad init gen-tx --name ``` -This populations `$HOME/.gaiad/gen-tx/` with a json file. +The validator will be prompted to enter a password for their new account. + +This populates `$HOME/.gaiad/gen-tx/` with a json file. Now these json files need to be aggregated together via Github, a Google form, pastebin or other methods. diff --git a/tests/gobash.go b/tests/gobash.go index 71db2d2ddaca..11f4407f2332 100644 --- a/tests/gobash.go +++ b/tests/gobash.go @@ -2,6 +2,7 @@ package tests import ( "fmt" + "io" "io/ioutil" "strings" "testing" @@ -10,11 +11,12 @@ import ( cmn "github.com/tendermint/tendermint/libs/common" ) -// Execute the command, return stdout, logging stdout/err to t. -func ExecuteT(t *testing.T, cmd string) (out string) { +// ExecuteT executes the command, pipes any input to STDIN and return STDOUT, +// logging STDOUT/STDERR to t. +func ExecuteT(t *testing.T, cmd, input string) (out string) { t.Log("Running", cmn.Cyan(cmd)) - // Split cmd to name and args. + // split cmd to name and args split := strings.Split(cmd, " ") require.True(t, len(split) > 0, "no command provided") name, args := split[0], []string(nil) @@ -22,27 +24,32 @@ func ExecuteT(t *testing.T, cmd string) (out string) { args = split[1:] } - // Start process and wait. proc, err := StartProcess("", name, args) require.NoError(t, err) - // Get the output. + // if input is provided, pass it to STDIN and close the pipe + if input != "" { + _, err = io.WriteString(proc.StdinPipe, input) + require.NoError(t, err) + proc.StdinPipe.Close() + } + outbz, errbz, err := proc.ReadAll() if err != nil { fmt.Println("Err on proc.ReadAll()", err, args) } + proc.Wait() - // Log output. if len(outbz) > 0 { t.Log("Stdout:", cmn.Green(string(outbz))) } + if len(errbz) > 0 { t.Log("Stderr:", cmn.Red(string(errbz))) } - // Collect STDOUT output. - out = strings.Trim(string(outbz), "\n") //trim any new lines + out = strings.Trim(string(outbz), "\n") return out } From bac686f71d068225597e2b921ef7421cf4c1cf13 Mon Sep 17 00:00:00 2001 From: Aleksandr Bezobchuk Date: Wed, 1 Aug 2018 14:26:41 -0400 Subject: [PATCH 2/2] Fix broken CLI test(s) --- cmd/gaia/cli_test/cli_test.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/gaia/cli_test/cli_test.go b/cmd/gaia/cli_test/cli_test.go index f3ef2f5fe759..8d652bc43525 100644 --- a/cmd/gaia/cli_test/cli_test.go +++ b/cmd/gaia/cli_test/cli_test.go @@ -176,7 +176,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { fooAcc := executeGetAccount(t, fmt.Sprintf("gaiacli account %s %v", fooAddr, flags)) require.Equal(t, int64(50), fooAcc.GetCoins().AmountOf("steak").Int64()) - proposalsQuery := tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals %v", flags)) + proposalsQuery := tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals %v", flags), "") require.Equal(t, "No matching proposals found", proposalsQuery) // submit a test proposal @@ -197,7 +197,7 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(1), proposal1.GetProposalID()) require.Equal(t, gov.StatusDepositPeriod, proposal1.GetStatus()) - proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals %v", flags)) + proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals %v", flags), "") require.Equal(t, " 1 - Test", proposalsQuery) depositStr := fmt.Sprintf("gaiacli gov deposit %v", flags) @@ -231,10 +231,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) { require.Equal(t, int64(1), votes[0].ProposalID) require.Equal(t, gov.OptionYes, votes[0].Option) - proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --status=DepositPeriod %v", flags)) + proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --status=DepositPeriod %v", flags), "") require.Equal(t, "No matching proposals found", proposalsQuery) - proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --status=VotingPeriod %v", flags)) + proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --status=VotingPeriod %v", flags), "") require.Equal(t, " 1 - Test", proposalsQuery) // submit a second test proposal @@ -245,10 +245,10 @@ func TestGaiaCLISubmitProposal(t *testing.T) { spStr += fmt.Sprintf(" --title=%s", "Apples") spStr += fmt.Sprintf(" --description=%s", "test") - executeWrite(t, spStr, pass) + executeWrite(t, spStr, app.DefaultKeyPass) tests.WaitForNextNBlocksTM(2, port) - proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --latest=1 %v", flags)) + proposalsQuery = tests.ExecuteT(t, fmt.Sprintf("gaiacli gov query-proposals --latest=1 %v", flags), "") require.Equal(t, " 2 - Apples", proposalsQuery) }