Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

R4R: gen-tx: Support User Given Key Passwords #1856

Merged
merged 2 commits into from
Aug 1, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PENDING.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
7 changes: 6 additions & 1 deletion client/input.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typically we try to keep comments as non-verbose as possible, which often means they are not sentences - I think this makes sense - here just a general comment

return pass, errors.Errorf("password must be at least %d characters", MinPassLength)
}

return pass, nil
}

Expand Down
57 changes: 41 additions & 16 deletions cmd/gaia/app/genesis.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what's the thinking here around providing the default password here if nothing is provided? Which situations will this come up in? I was thinking we'd just fail if somebody doesn't provide a pass?

Copy link
Contributor Author

@alexanderbez alexanderbez Jul 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm lazy and don't want to enter anything (keeping inline with the current UX)? If we think absolutely requiring a user-provided password is a better UX experience, then I can remove it @rigelrozanski .

Copy link
Contributor

@ValarDragon ValarDragon Jul 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better solution would be to have a key type with no password. Using a default password only burns computation time.

This will be easier to do if we figure out a good way to refactor the keybase.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mhmmm, I'll need to think on that for a bit. What shall we do for now? Just not supply a default?

Copy link
Contributor

@ValarDragon ValarDragon Jul 30, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't really have a preference rn. I would like just having no passwords as an option later. (I'll try to spend some time today writing a way to do the keybase refactor)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Awesome!


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
Expand Down
70 changes: 35 additions & 35 deletions cmd/gaia/cli_test/cli_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
)

var (
pass = "1234567890"
gaiadHome = ""
gaiacliHome = ""
)
Expand All @@ -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()
Expand All @@ -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))
Expand All @@ -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))
Expand All @@ -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))
Expand All @@ -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()
Expand All @@ -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))
Expand All @@ -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))
Expand All @@ -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)

Expand All @@ -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)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice the default pass here from the app is good 👍

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()
Expand All @@ -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
Expand All @@ -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))
Expand All @@ -197,15 +197,15 @@ 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)
depositStr += fmt.Sprintf(" --from=%s", "foo")
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))
Expand All @@ -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))
Expand All @@ -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
Expand All @@ -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)
}

Expand Down Expand Up @@ -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)
Expand All @@ -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)

Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand All @@ -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)
Expand Down
7 changes: 5 additions & 2 deletions cmd/gaia/testnets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -476,13 +476,16 @@ gaiacli account <account_cosmosaccaddr> --block=<block_height>

## 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 <account_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.

Expand Down
Loading