Remove flag requirement from accounts keys (#5757)

* Remove flag requirements for keystore-path and password

* Add test for HandleEmptyFlags

* Add comment

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
Ivan Martinez 2020-05-06 01:55:25 -04:00 committed by GitHub
parent ae66f63ec2
commit 67a2698463
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 89 additions and 39 deletions

View File

@ -14,8 +14,10 @@ go_library(
"//shared/cmd:go_default_library",
"//shared/keystore:go_default_library",
"//shared/params:go_default_library",
"//validator/flags:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@in_gopkg_urfave_cli_v2//:go_default_library",
],
)
@ -28,5 +30,7 @@ go_test(
"//shared/keystore:go_default_library",
"//shared/params:go_default_library",
"//shared/testutil:go_default_library",
"//validator/flags:go_default_library",
"@in_gopkg_urfave_cli_v2//:go_default_library",
],
)

View File

@ -17,7 +17,9 @@ import (
"github.com/prysmaticlabs/prysm/shared/cmd"
"github.com/prysmaticlabs/prysm/shared/keystore"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/validator/flags"
"github.com/sirupsen/logrus"
"gopkg.in/urfave/cli.v2"
)
var log = logrus.WithField("prefix", "accounts")
@ -137,27 +139,6 @@ func Exists(keystorePath string) (bool, error) {
// CreateValidatorAccount creates a validator account from the given cli context.
func CreateValidatorAccount(path string, passphrase string) (string, string, error) {
if passphrase == "" {
log.Info("Creating a new validator account for eth2")
enteredPassphrase, err := cmd.EnterPassword()
if err != nil {
return path, enteredPassphrase, err
}
passphrase = enteredPassphrase
}
if path == "" {
path = DefaultValidatorDir()
log.Infof("Please specify a keystore path to save your private keys (default: %q):", path)
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
return path, passphrase, err
}
if text = strings.Replace(text, "\n", "", -1); text != "" {
path = text
}
}
// Forces user to create directory if using non-default path.
if path != DefaultValidatorDir() {
exists, err := Exists(path)
@ -174,6 +155,18 @@ func CreateValidatorAccount(path string, passphrase string) (string, string, err
return path, passphrase, nil
}
// PrintPublicAndPrivateKeys uses the passed in path and prints out the public and private keys in that directory.
func PrintPublicAndPrivateKeys(path string, passphrase string) error {
keystores, err := DecryptKeysFromKeystore(path, passphrase)
if err != nil {
return errors.Wrapf(err, "failed to decrypt keystore keys at path %s", path)
}
for _, v := range keystores {
fmt.Printf("Public key: %#x private key: %#x\n", v.PublicKey.Marshal(), v.SecretKey.Marshal())
}
return nil
}
// DefaultValidatorDir returns OS-specific default keystore directory.
func DefaultValidatorDir() string {
// Try to place the data folder in the user's home dir
@ -191,6 +184,36 @@ func DefaultValidatorDir() string {
return ""
}
// HandleEmptyFlags checks what the set flags are and allows the user to manually enter them if they're empty.
func HandleEmptyFlags(cliCtx *cli.Context) (string, string, error) {
path := cliCtx.String(flags.KeystorePathFlag.Name)
passphrase := cliCtx.String(flags.PasswordFlag.Name)
if path == "" {
path = DefaultValidatorDir()
log.Infof("Please specify the keystore path for your private keys (default: %q):", path)
reader := bufio.NewReader(os.Stdin)
text, err := reader.ReadString('\n')
if err != nil {
return path, passphrase, errors.Wrap(err, "could not read input path")
}
if text = strings.Replace(text, "\n", "", -1); text != "" {
path = text
}
}
if passphrase == "" {
log.Info("Please enter the password for your private keys")
enteredPassphrase, err := cmd.EnterPassword()
if err != nil {
return path, enteredPassphrase, errors.Wrap(err, "could not read entered passphrase")
}
passphrase = enteredPassphrase
}
return path, passphrase, nil
}
// homeDir returns home directory path.
func homeDir() string {
if home := os.Getenv("HOME"); home != "" {

View File

@ -1,6 +1,7 @@
package accounts
import (
"flag"
"fmt"
"io/ioutil"
"os"
@ -9,6 +10,8 @@ import (
"github.com/prysmaticlabs/prysm/shared/keystore"
"github.com/prysmaticlabs/prysm/shared/params"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/validator/flags"
"gopkg.in/urfave/cli.v2"
)
func TestNewValidatorAccount_AccountExists(t *testing.T) {
@ -49,3 +52,25 @@ func TestNewValidatorAccount_CreateValidatorAccount(t *testing.T) {
t.Errorf("expected error not thrown, want: %v, got: %v", wantErrString, err)
}
}
func TestHandleEmptyFlags_FlagsSetF(t *testing.T) {
passedPath := "~/path/given"
passedPassword := "password"
app := &cli.App{}
set := flag.NewFlagSet("test", 0)
set.String(flags.KeystorePathFlag.Name, passedPath, "set keystore path")
set.String(flags.PasswordFlag.Name, passedPassword, "set keystore password")
ctx := cli.NewContext(app, set, nil)
path, passphrase, err := HandleEmptyFlags(ctx)
if err != nil {
t.Fatal(err)
}
if passedPath != path {
t.Fatalf("Expected set path to be unchanged, expected %s, received %s", passedPath, path)
}
if passedPassword != passphrase {
t.Fatalf("Expected set password to be unchanged, expected %s, received %s", passedPassword, passphrase)
}
}

View File

@ -81,8 +81,8 @@ func init() {
func main() {
app := cli.App{}
app.Name = "validator"
app.Usage = `launches an Ethereum Serenity validator client that interacts with a beacon chain,
starts proposer services, shardp2p connections, and more`
app.Usage = `launches an Ethereum 2.0 validator client that interacts with a beacon chain,
starts proposer and attester services, p2p connections, and more`
app.Version = version.GetVersion()
app.Action = startNode
app.Commands = []*cli.Command{
@ -93,22 +93,26 @@ func main() {
Subcommands: []*cli.Command{
{
Name: "create",
Description: `creates a new validator account keystore containing private keys for Ethereum Serenity -
Description: `creates a new validator account keystore containing private keys for Ethereum 2.0 -
this command outputs a deposit data string which can be used to deposit Ether into the ETH1.0 deposit
contract in order to activate the validator client`,
Flags: []cli.Flag{
flags.KeystorePathFlag,
flags.PasswordFlag,
},
Action: func(ctx *cli.Context) error {
featureconfig.ConfigureValidator(ctx)
Action: func(cliCtx *cli.Context) error {
featureconfig.ConfigureValidator(cliCtx)
if featureconfig.Get().MinimalConfig {
log.Warn("Using Minimal Config")
params.UseMinimalConfig()
}
if keystoreDir, _, err := accounts.CreateValidatorAccount(ctx.String(flags.KeystorePathFlag.Name), ctx.String(flags.PasswordFlag.Name)); err != nil {
log.WithError(err).Fatalf("Could not create validator at path: %s", keystoreDir)
keystorePath, passphrase, err := accounts.HandleEmptyFlags(cliCtx)
if err != nil {
log.WithError(err).Error("Could not list keys")
}
if _, _, err := accounts.CreateValidatorAccount(keystorePath, passphrase); err != nil {
log.WithError(err).Fatalf("Could not create validator at path: %s", keystorePath)
}
return nil
},
@ -120,19 +124,13 @@ contract in order to activate the validator client`,
flags.KeystorePathFlag,
flags.PasswordFlag,
},
Action: func(ctx *cli.Context) error {
if ctx.String(flags.KeystorePathFlag.Name) == "" {
log.Fatalf("%s is required", flags.KeystorePathFlag.Name)
}
if ctx.String(flags.PasswordFlag.Name) == "" {
log.Fatalf("%s is required", flags.PasswordFlag.Name)
}
keystores, err := accounts.DecryptKeysFromKeystore(ctx.String(flags.KeystorePathFlag.Name), ctx.String(flags.PasswordFlag.Name))
Action: func(cliCtx *cli.Context) error {
keystorePath, passphrase, err := accounts.HandleEmptyFlags(cliCtx)
if err != nil {
log.WithError(err).Fatalf("Failed to decrypt keystore keys at path %s", ctx.String(flags.KeystorePathFlag.Name))
log.WithError(err).Error("Could not list keys")
}
for _, v := range keystores {
fmt.Printf("Public key: %#x private key: %#x\n", v.PublicKey.Marshal(), v.SecretKey.Marshal())
if err := accounts.PrintPublicAndPrivateKeys(keystorePath, passphrase); err != nil {
log.WithError(err).Errorf("Could not list private and public keys in path %s", keystorePath)
}
return nil
},