Accounts Revamp Fixes: "Overall" Wallet Improvements (#6736)

* change default wallet dir path to not be hidden

* gaz + pass wallet dir

* gaz + move const to flags

* move to flags

* move to flags

* use filepath join in order to create a valid dir name

* add wallet dir

* return err no wallet found issues

* fix up edit remote

* all tests passing

* fix test

* create or open wallet

* ivan feedback

* enter password for account with pubkey

* Update validator/accounts/v2/accounts_create.go

Co-authored-by: Ivan Martinez <ivanthegreatdev@gmail.com>

* works

* preston feedback

* nothing to export

* fmt

* test for create or open

* gaz

Co-authored-by: shayzluf <thezluf@gmail.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
Co-authored-by: Ivan Martinez <ivanthegreatdev@gmail.com>
This commit is contained in:
Raul Jordan
2020-07-28 20:20:13 -05:00
committed by GitHub
parent 1a1c1bb813
commit 9d08ba49de
25 changed files with 381 additions and 265 deletions

View File

@@ -374,10 +374,10 @@ func TestStore_HasParent(t *testing.T) {
want bool
}{
{r: [32]byte{'a'}, want: false},
{m: map[[32]byte]uint64{[32]byte{'a'}: 0}, r: [32]byte{'a'}, want: false},
{m: map[[32]byte]uint64{[32]byte{'a'}: 0}, r: [32]byte{'a'},
{m: map[[32]byte]uint64{{'a'}: 0}, r: [32]byte{'a'}, want: false},
{m: map[[32]byte]uint64{{'a'}: 0}, r: [32]byte{'a'},
n: []*Node{{Parent: NonExistentNode}}, want: false},
{m: map[[32]byte]uint64{[32]byte{'a'}: 0},
{m: map[[32]byte]uint64{{'a'}: 0},
n: []*Node{{Parent: 0}}, r: [32]byte{'a'},
want: true},
}

View File

@@ -23,6 +23,7 @@ go_library(
"//validator:__subpackages__",
],
deps = [
"//shared/bytesutil:go_default_library",
"//shared/featureconfig:go_default_library",
"//shared/params:go_default_library",
"//shared/petnames:go_default_library",
@@ -73,7 +74,9 @@ go_test(
"//validator/keymanager/v2/remote:go_default_library",
"@com_github_dustin_go_humanize//:go_default_library",
"@com_github_google_uuid//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
"@com_github_urfave_cli_v2//:go_default_library",
"@com_github_wealdtech_go_eth2_wallet_encryptor_keystorev4//:go_default_library",
],

View File

@@ -20,25 +20,10 @@ var log = logrus.WithField("prefix", "accounts-v2")
// a wallet from the user's specified path.
func CreateAccount(cliCtx *cli.Context) error {
ctx := context.Background()
walletDir, err := inputDirectory(cliCtx, walletDirPromptText, flags.WalletDirFlag)
if err != nil {
return errors.Wrapf(err, "Could not retrieve input directory")
}
ok, err := hasDir(walletDir)
wallet, err := createOrOpenWallet(cliCtx, CreateWallet)
if err != nil {
return err
}
// Create a new wallet if no directory exists.
if !ok {
err = CreateWallet(cliCtx)
if err != nil {
return errors.Wrapf(err, "Could not create wallet")
}
}
wallet, err := OpenWallet(cliCtx)
if err != nil {
return errors.Wrap(err, "could not open wallet")
}
skipMnemonicConfirm := cliCtx.Bool(flags.SkipMnemonicConfirmFlag.Name)
keymanager, err := wallet.InitializeKeymanager(ctx, skipMnemonicConfirm)
if err != nil {
@@ -52,7 +37,7 @@ func CreateAccount(cliCtx *cli.Context) error {
if !ok {
return errors.New("not a direct keymanager")
}
password, err := inputPassword(cliCtx, newAccountPasswordPromptText, confirmPass)
password, err := inputPassword(cliCtx, flags.AccountPasswordFileFlag, newAccountPasswordPromptText, confirmPass)
if err != nil {
return errors.Wrap(err, "could not input new account password")
}

View File

@@ -14,15 +14,17 @@ func TestCreateAccount_Derived(t *testing.T) {
walletDir, passwordsDir, passwordFile := setupWalletAndPasswordsDir(t)
numAccounts := int64(5)
cliCtx := setupWalletCtx(t, &testWalletConfig{
walletDir: walletDir,
passwordsDir: passwordsDir,
passwordFile: passwordFile,
keymanagerKind: v2keymanager.Derived,
numAccounts: numAccounts,
walletDir: walletDir,
passwordsDir: passwordsDir,
walletPasswordFile: passwordFile,
accountPasswordFile: passwordFile,
keymanagerKind: v2keymanager.Derived,
numAccounts: numAccounts,
})
// We attempt to create the wallet.
require.NoError(t, CreateWallet(cliCtx))
_, err := CreateWallet(cliCtx)
require.NoError(t, err)
// We attempt to open the newly created wallet.
ctx := context.Background()

View File

@@ -28,9 +28,10 @@ func ExportAccount(cliCtx *cli.Context) error {
if err != nil {
return errors.Wrap(err, "could not parse output directory")
}
wallet, err := OpenWallet(cliCtx)
if err != nil {
if errors.Is(err, ErrNoWalletFound) {
return errors.Wrap(err, "nothing to export, no wallet found")
} else if err != nil {
return errors.Wrap(err, "could not open wallet")
}
keymanager, err := wallet.InitializeKeymanager(context.Background(), true /* skip mnemonic confirm */)

View File

@@ -36,10 +36,12 @@ func TestZipAndUnzip(t *testing.T) {
require.NoError(t, err)
require.NoError(t, wallet.SaveWallet())
ctx := context.Background()
keymanagerCfg := direct.DefaultConfig()
keymanagerCfg.AccountPasswordsDirectory = passwordsDir
keymanager, err := direct.NewKeymanager(
ctx,
wallet,
direct.DefaultConfig(),
keymanagerCfg,
)
require.NoError(t, err)
_, err = keymanager.CreateAccount(ctx, password)
@@ -80,6 +82,7 @@ func TestExport_Noninteractive(t *testing.T) {
require.NoError(t, wallet.SaveWallet())
ctx := context.Background()
keymanagerCfg := direct.DefaultConfig()
keymanagerCfg.AccountPasswordsDirectory = passwordsDir
encodedCfg, err := direct.MarshalConfigFile(ctx, keymanagerCfg)
require.NoError(t, err)
require.NoError(t, wallet.WriteKeymanagerConfigToDisk(ctx, encodedCfg))

View File

@@ -23,53 +23,41 @@ import (
// ImportAccount uses the archived account made from ExportAccount to import an account and
// asks the users for account passwords.
func ImportAccount(cliCtx *cli.Context) error {
walletDir, err := inputDirectory(cliCtx, walletDirPromptText, flags.WalletDirFlag)
if err != nil && !errors.Is(err, ErrNoWalletFound) {
return errors.Wrap(err, "could not parse wallet directory")
}
// Check if the user has a wallet at the specified path. If so, only let them continue if it is a non-HD wallet.
walletExists, err := hasDir(walletDir)
if err != nil {
return errors.Wrap(err, "could not check if wallet exists")
}
if walletExists {
keymanagerKind, err := readKeymanagerKindFromWalletPath(walletDir)
if err != nil {
return errors.Wrap(err, "could not read keymanager kind for existing wallet")
ctx := context.Background()
wallet, err := createOrOpenWallet(cliCtx, func(cliCtx *cli.Context) (*Wallet, error) {
w, err := NewWallet(cliCtx, v2keymanager.Direct)
if err != nil && !errors.Is(err, ErrWalletExists) {
return nil, errors.Wrap(err, "could not create new wallet")
}
if keymanagerKind != v2keymanager.Direct {
return fmt.Errorf(
"importing non-HD accounts into a non-direct wallet is not allowed, given wallet path contains a %s wallet",
keymanagerKind.String(),
)
if err = createDirectKeymanagerWallet(cliCtx, w); err != nil {
return nil, errors.Wrap(err, "could not initialize wallet")
}
}
passwordsDir, err := inputDirectory(cliCtx, passwordsDirPromptText, flags.WalletPasswordsDirFlag)
log.WithField("wallet-path", w.walletDir).Info(
"Successfully created new wallet",
)
return w, err
})
if err != nil {
return err
return errors.Wrap(err, "could not initialize wallet")
}
if wallet.KeymanagerKind() != v2keymanager.Direct {
return errors.New(
"only non-HD wallets can import accounts, try creating a new wallet with wallet-v2 create",
)
}
keysDir, err := inputDirectory(cliCtx, importKeysDirPromptText, flags.KeysDirFlag)
if err != nil {
return errors.Wrap(err, "could not parse keys directory")
}
accountsPath := filepath.Join(walletDir, v2keymanager.Direct.String())
if err := os.MkdirAll(accountsPath, DirectoryPermissions); err != nil {
return errors.Wrap(err, "could not create wallet directory")
if err := wallet.SaveWallet(); err != nil {
return errors.Wrap(err, "could not save wallet")
}
if err := os.MkdirAll(passwordsDir, DirectoryPermissions); err != nil {
return errors.Wrap(err, "could not create passwords directory")
}
wallet := &Wallet{
accountsPath: accountsPath,
passwordsDir: passwordsDir,
keymanagerKind: v2keymanager.Direct,
}
var accountsImported []string
ctx := context.Background()
var pubKeysImported [][]byte
if err := filepath.Walk(keysDir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
}
if info.IsDir() {
return nil
}
@@ -90,11 +78,12 @@ func ImportAccount(cliCtx *cli.Context) error {
return nil
}
accountName, err := wallet.importKeystore(ctx, path)
accountName, pubKey, err := wallet.importKeystore(ctx, path)
if err != nil {
return errors.Wrap(err, "could not import keystore")
}
accountsImported = append(accountsImported, accountName)
pubKeysImported = append(pubKeysImported, pubKey)
return nil
}); err != nil {
return errors.Wrap(err, "could not walk files")
@@ -102,8 +91,8 @@ func ImportAccount(cliCtx *cli.Context) error {
au := aurora.NewAurora(true)
fmt.Printf("Importing accounts: %s\n", au.BrightGreen(strings.Join(accountsImported, ", ")).Bold())
for _, accountName := range accountsImported {
if err := wallet.enterPasswordForAccount(cliCtx, accountName); err != nil {
for i, accountName := range accountsImported {
if err := wallet.enterPasswordForAccount(cliCtx, accountName, pubKeysImported[i]); err != nil {
return errors.Wrap(err, "could not verify password for keystore")
}
}
@@ -123,25 +112,25 @@ func ImportAccount(cliCtx *cli.Context) error {
return nil
}
func (w *Wallet) importKeystore(ctx context.Context, keystoreFilePath string) (string, error) {
func (w *Wallet) importKeystore(ctx context.Context, keystoreFilePath string) (string, []byte, error) {
keystoreBytes, err := ioutil.ReadFile(keystoreFilePath)
if err != nil {
return "", errors.Wrap(err, "could not read keystore file")
return "", nil, errors.Wrap(err, "could not read keystore file")
}
keystoreFile := &v2keymanager.Keystore{}
if err := json.Unmarshal(keystoreBytes, keystoreFile); err != nil {
return "", errors.Wrap(err, "could not decode keystore json")
return "", nil, errors.Wrap(err, "could not decode keystore json")
}
pubKeyBytes, err := hex.DecodeString(keystoreFile.Pubkey)
if err != nil {
return "", errors.Wrap(err, "could not decode public key string in keystore")
return "", nil, errors.Wrap(err, "could not decode public key string in keystore")
}
accountName := petnames.DeterministicName(pubKeyBytes, "-")
keystoreFileName := filepath.Base(keystoreFilePath)
if err := w.WriteFileAtPath(ctx, accountName, keystoreFileName, keystoreBytes); err != nil {
return "", errors.Wrap(err, "could not write keystore to account dir")
return "", nil, errors.Wrap(err, "could not write keystore to account dir")
}
return accountName, nil
return accountName, pubKeyBytes, nil
}
func logAccountsImported(ctx context.Context, wallet *Wallet, keymanager *direct.Keymanager, accountNames []string) error {

View File

@@ -34,17 +34,19 @@ func TestImport_Noninteractive(t *testing.T) {
})
cliCtx := setupWalletCtx(t, &testWalletConfig{
walletDir: walletDir,
passwordsDir: passwordsDir,
keysDir: keysDir,
keymanagerKind: v2keymanager.Direct,
passwordFile: passwordFilePath,
walletDir: walletDir,
passwordsDir: passwordsDir,
keysDir: keysDir,
keymanagerKind: v2keymanager.Direct,
walletPasswordFile: passwordFilePath,
accountPasswordFile: passwordFilePath,
})
wallet, err := NewWallet(cliCtx, v2keymanager.Direct)
require.NoError(t, err)
require.NoError(t, wallet.SaveWallet())
ctx := context.Background()
keymanagerCfg := direct.DefaultConfig()
keymanagerCfg.AccountPasswordsDirectory = passwordsDir
encodedCfg, err := direct.MarshalConfigFile(ctx, keymanagerCfg)
require.NoError(t, err)
require.NoError(t, wallet.WriteKeymanagerConfigToDisk(ctx, encodedCfg))

View File

@@ -24,8 +24,10 @@ func ListAccounts(cliCtx *cli.Context) error {
// Read the wallet from the specified path.
ctx := context.Background()
wallet, err := OpenWallet(cliCtx)
if err != nil {
return errors.Wrapf(err, "could not read wallet at specified path %s", wallet.AccountsDir())
if errors.Is(err, ErrNoWalletFound) {
return errors.Wrap(err, "no wallet found at path, create a new wallet with wallet-v2 create")
} else if err != nil {
return errors.Wrap(err, "could not open wallet")
}
keymanager, err := wallet.InitializeKeymanager(ctx, true /* skip mnemonic confirm */)
if err != nil {
@@ -103,7 +105,7 @@ func listDirectKeymanagerAccounts(
if err != nil {
return errors.Wrap(err, "could not get timestamp from keystore file name")
}
fmt.Printf("%s | Created %s\n", au.BrightGreen(accountNames[i]).Bold(), humanize.Time(unixTimestamp))
fmt.Printf("%s | %s | Created %s\n", au.BrightBlue(fmt.Sprintf("Account %d", i)).Bold(), au.BrightGreen(accountNames[i]).Bold(), humanize.Time(unixTimestamp))
fmt.Printf("%s %#x\n", au.BrightMagenta("[validating public key]").Bold(), pubKeys[i])
if !showDepositData {
continue

View File

@@ -127,10 +127,10 @@ func TestListAccounts_DirectKeymanager(t *testing.T) {
func TestListAccounts_DerivedKeymanager(t *testing.T) {
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
cliCtx := setupWalletCtx(t, &testWalletConfig{
walletDir: walletDir,
passwordsDir: passwordsDir,
keymanagerKind: v2keymanager.Derived,
passwordFile: passwordFilePath,
walletDir: walletDir,
passwordsDir: passwordsDir,
keymanagerKind: v2keymanager.Derived,
walletPasswordFile: passwordFilePath,
})
wallet, err := NewWallet(cliCtx, v2keymanager.Derived)
require.NoError(t, err)

View File

@@ -20,8 +20,8 @@ specified input, capable of creating a direct, derived, or remote wallet.
this command outputs a deposit data string which is required to become a validator in eth2.`,
Flags: []cli.Flag{
flags.WalletDirFlag,
flags.WalletPasswordsDirFlag,
flags.PasswordFileFlag,
flags.WalletPasswordFileFlag,
flags.AccountPasswordFileFlag,
flags.NumAccountsFlag,
featureconfig.AltonaTestnet,
featureconfig.MedallaTestnet,
@@ -38,8 +38,7 @@ this command outputs a deposit data string which is required to become a validat
Description: "Lists all validator accounts in a user's wallet directory",
Flags: []cli.Flag{
flags.WalletDirFlag,
flags.WalletPasswordsDirFlag,
flags.PasswordFileFlag,
flags.WalletPasswordFileFlag,
flags.ShowDepositDataFlag,
featureconfig.AltonaTestnet,
featureconfig.MedallaTestnet,
@@ -56,7 +55,6 @@ this command outputs a deposit data string which is required to become a validat
Description: `exports the account of a given directory into a zip of the provided output path. This zip can be used to later import the account to another directory`,
Flags: []cli.Flag{
flags.WalletDirFlag,
flags.WalletPasswordsDirFlag,
flags.BackupDirFlag,
flags.AccountsFlag,
featureconfig.AltonaTestnet,
@@ -76,7 +74,7 @@ this command outputs a deposit data string which is required to become a validat
flags.WalletDirFlag,
flags.WalletPasswordsDirFlag,
flags.KeysDirFlag,
flags.PasswordFileFlag,
flags.WalletPasswordFileFlag,
featureconfig.AltonaTestnet,
featureconfig.MedallaTestnet,
},

View File

@@ -24,12 +24,12 @@ var WalletCommands = &cli.Command{
flags.RemoteSignerCertPathFlag,
flags.RemoteSignerKeyPathFlag,
flags.RemoteSignerCACertPathFlag,
flags.PasswordFileFlag,
flags.WalletPasswordFileFlag,
featureconfig.AltonaTestnet,
featureconfig.MedallaTestnet,
},
Action: func(cliCtx *cli.Context) error {
if err := CreateWallet(cliCtx); err != nil {
if _, err := CreateWallet(cliCtx); err != nil {
log.Fatalf("Could not create a wallet: %v", err)
}
return nil
@@ -44,6 +44,7 @@ var WalletCommands = &cli.Command{
flags.RemoteSignerCertPathFlag,
flags.RemoteSignerKeyPathFlag,
flags.RemoteSignerCACertPathFlag,
flags.WalletPasswordsDirFlag,
featureconfig.AltonaTestnet,
featureconfig.MedallaTestnet,
},
@@ -61,7 +62,7 @@ var WalletCommands = &cli.Command{
flags.WalletDirFlag,
flags.WalletPasswordsDirFlag,
flags.MnemonicFileFlag,
flags.PasswordFileFlag,
flags.WalletPasswordFileFlag,
flags.NumAccountsFlag,
featureconfig.AltonaTestnet,
featureconfig.MedallaTestnet,

View File

@@ -3,7 +3,6 @@ package v2
import (
"fmt"
"io/ioutil"
"path/filepath"
"strings"
"unicode"
@@ -17,16 +16,15 @@ import (
)
const (
importDirPromptText = "Enter the file location of the exported wallet zip to import"
importKeysDirPromptText = "Enter the directory where your keystores to import are located"
exportDirPromptText = "Enter a file location to write the exported wallet to"
exportDirPromptText = "Enter a file location to write the exported account(s) to"
walletDirPromptText = "Enter a wallet directory"
passwordsDirPromptText = "Directory where passwords will be stored"
newWalletPasswordPromptText = "New wallet password"
confirmPasswordPromptText = "Confirm password"
walletPasswordPromptText = "Wallet password"
newAccountPasswordPromptText = "New account password"
passwordForAccountPromptText = "Enter password for account %s"
passwordForAccountPromptText = "Enter password for account with public key %#x"
)
type passwordConfirm int
@@ -44,7 +42,7 @@ const (
)
func inputDirectory(cliCtx *cli.Context, promptText string, flag *cli.StringFlag) (string, error) {
directory := appendDirName(cliCtx.String(flag.Name), flag.Name)
directory := cliCtx.String(flag.Name)
if cliCtx.IsSet(flag.Name) {
return directory, nil
}
@@ -84,17 +82,7 @@ func inputDirectory(cliCtx *cli.Context, promptText string, flag *cli.StringFlag
if inputtedDir == prompt.Default {
return directory, nil
}
return appendDirName(inputtedDir, flag.Name), nil
}
func appendDirName(inputtedDir string, flagName string) string {
switch flagName {
case flags.WalletDirFlag.Name:
inputtedDir = filepath.Join(inputtedDir, WalletDefaultDirName)
case flags.WalletPasswordsDirFlag.Name:
inputtedDir = filepath.Join(inputtedDir, PasswordsDefaultDirName)
}
return inputtedDir
return inputtedDir, nil
}
func validateDirectoryPath(input string) error {
@@ -104,9 +92,14 @@ func validateDirectoryPath(input string) error {
return nil
}
func inputPassword(cliCtx *cli.Context, promptText string, confirmPassword passwordConfirm) (string, error) {
if cliCtx.IsSet(flags.PasswordFileFlag.Name) {
passwordFilePath := cliCtx.String(flags.PasswordFileFlag.Name)
func inputPassword(
cliCtx *cli.Context,
passwordFileFlag *cli.StringFlag,
promptText string,
confirmPassword passwordConfirm,
) (string, error) {
if cliCtx.IsSet(passwordFileFlag.Name) {
passwordFilePath := cliCtx.String(passwordFileFlag.Name)
data, err := ioutil.ReadFile(passwordFilePath)
if err != nil {
return "", errors.Wrap(err, "could not read password file")
@@ -152,9 +145,9 @@ func inputPassword(cliCtx *cli.Context, promptText string, confirmPassword passw
return strings.TrimRight(walletPassword, "\r\n"), nil
}
func inputWeakPassword(cliCtx *cli.Context, promptText string) (string, error) {
if cliCtx.IsSet(flags.PasswordFileFlag.Name) {
passwordFilePath := cliCtx.String(flags.PasswordFileFlag.Name)
func inputWeakPassword(cliCtx *cli.Context, passwordFileFlag *cli.StringFlag, promptText string) (string, error) {
if cliCtx.IsSet(passwordFileFlag.Name) {
passwordFilePath := cliCtx.String(passwordFileFlag.Name)
data, err := ioutil.ReadFile(passwordFilePath)
if err != nil {
return "", errors.Wrap(err, "could not read password file")
@@ -227,71 +220,63 @@ func inputRemoteKeymanagerConfig(cliCtx *cli.Context) (*remote.Config, error) {
crt := cliCtx.String(flags.RemoteSignerCertPathFlag.Name)
key := cliCtx.String(flags.RemoteSignerKeyPathFlag.Name)
ca := cliCtx.String(flags.RemoteSignerCACertPathFlag.Name)
if addr != "" && crt != "" && key != "" && ca != "" {
if !(isValidUnicode(addr) && isValidUnicode(crt) && isValidUnicode(key) && isValidUnicode(ca)) {
return nil, errors.New("flag inputs contain non-unicode characters")
}
newCfg := &remote.Config{
RemoteCertificate: &remote.CertificateConfig{
ClientCertPath: strings.TrimRight(crt, "\r\n"),
ClientKeyPath: strings.TrimRight(key, "\r\n"),
CACertPath: strings.TrimRight(ca, "\r\n"),
log.Info("Input desired configuration")
var err error
if addr == "" {
prompt := promptui.Prompt{
Label: "Remote gRPC address (such as host.example.com:4000)",
Validate: func(input string) error {
if input == "" {
return errors.New("remote host address cannot be empty")
}
if !isValidUnicode(input) {
return errors.New("not valid unicode")
}
return nil
},
RemoteAddr: strings.TrimRight(addr, "\r\n"),
}
log.Infof("New configuration")
fmt.Printf("%s\n", newCfg)
return newCfg, nil
addr, err = prompt.Run()
if err != nil {
return nil, err
}
}
log.Infof("Input desired configuration")
prompt := promptui.Prompt{
Label: "Remote gRPC address (such as host.example.com:4000)",
Validate: func(input string) error {
if input == "" {
return errors.New("remote host address cannot be empty")
}
if !isValidUnicode(input) {
return errors.New("not valid unicode")
}
return nil
},
if crt == "" {
prompt := promptui.Prompt{
Label: "Path to TLS crt (such as /path/to/client.crt)",
Validate: validateCertPath,
}
crt, err = prompt.Run()
if err != nil {
return nil, err
}
}
remoteAddr, err := prompt.Run()
if err != nil {
return nil, err
if key == "" {
prompt := promptui.Prompt{
Label: "Path to TLS key (such as /path/to/client.key)",
Validate: validateCertPath,
}
key, err = prompt.Run()
if err != nil {
return nil, err
}
}
prompt = promptui.Prompt{
Label: "Path to TLS crt (such as /path/to/client.crt)",
Validate: validateCertPath,
}
clientCrtPath, err := prompt.Run()
if err != nil {
return nil, err
}
prompt = promptui.Prompt{
Label: "Path to TLS key (such as /path/to/client.key)",
Validate: validateCertPath,
}
clientKeyPath, err := prompt.Run()
if err != nil {
return nil, err
}
prompt = promptui.Prompt{
Label: "(Optional) Path to certificate authority (CA) crt (such as /path/to/ca.crt)",
Validate: validateCACertPath,
}
caCrtPath, err := prompt.Run()
if err != nil {
return nil, err
if ca == "" {
prompt := promptui.Prompt{
Label: "Path to certificate authority (CA) crt (such as /path/to/ca.crt)",
Validate: validateCertPath,
}
ca, err = prompt.Run()
if err != nil {
return nil, err
}
}
newCfg := &remote.Config{
RemoteCertificate: &remote.CertificateConfig{
ClientCertPath: strings.TrimRight(clientCrtPath, "\r\n"),
ClientKeyPath: strings.TrimRight(clientKeyPath, "\r\n"),
CACertPath: strings.TrimRight(caCrtPath, "\r\n"),
ClientCertPath: strings.TrimRight(crt, "\r\n"),
ClientKeyPath: strings.TrimRight(key, "\r\n"),
CACertPath: strings.TrimRight(ca, "\r\n"),
},
RemoteAddr: strings.TrimRight(remoteAddr, "\r\n"),
RemoteAddr: strings.TrimRight(addr, "\r\n"),
}
fmt.Printf("%s\n", newCfg)
return newCfg, nil
@@ -310,16 +295,6 @@ func validateCertPath(input string) error {
return nil
}
func validateCACertPath(input string) error {
if input != "" && !fileExists(input) {
return fmt.Errorf("no crt found at path: %s", input)
}
if !isValidUnicode(input) {
return errors.New("not valid unicode")
}
return nil
}
func formatPromptError(err error) error {
switch err {
case promptui.ErrAbort:

View File

@@ -15,6 +15,7 @@ import (
petname "github.com/dustinkirkland/golang-petname"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/bytesutil"
"github.com/prysmaticlabs/prysm/validator/flags"
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/derived"
@@ -25,11 +26,22 @@ import (
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
)
const (
// KeymanagerConfigFileName for the keymanager used by the wallet: direct, derived, or remote.
KeymanagerConfigFileName = "keymanageropts.json"
// DirectoryPermissions for directories created under the wallet path.
DirectoryPermissions = os.ModePerm
)
var (
// ErrNoWalletFound signifies there was no wallet directory found on-disk.
ErrNoWalletFound = errors.New(
"no wallet found at path, please create a new wallet using `./prysm.sh validator wallet-v2 create`",
)
// ErrWalletExists is an error returned when a wallet already exists in the path provided.
ErrWalletExists = errors.New("you already have a wallet at the specified path. You can " +
"edit your wallet configuration by running ./prysm.sh validator wallet-v2 edit-config",
)
keymanagerKindSelections = map[v2keymanager.Kind]string{
v2keymanager.Derived: "HD Wallet (Recommended)",
v2keymanager.Direct: "Non-HD Wallet (Most Basic)",
@@ -37,29 +49,12 @@ var (
}
)
const (
// WalletDefaultDirName for accounts-v2.
WalletDefaultDirName = ".prysm-wallet-v2"
// PasswordsDefaultDirName where account passwords are stored.
PasswordsDefaultDirName = ".prysm-wallet-v2-passwords"
// KeymanagerConfigFileName for the keymanager used by the wallet: direct, derived, or remote.
KeymanagerConfigFileName = "keymanageropts.json"
// DirectoryPermissions for directories created under the wallet path.
DirectoryPermissions = os.ModePerm
)
var (
// ErrWalletExists is an error returned when a wallet already exists in the path provided.
ErrWalletExists = errors.New("you already have a wallet at the specified path. You can " +
"edit your wallet configuration by running ./prysm.sh validator wallet-v2 edit-config",
)
)
// Wallet is a primitive in Prysm's v2 account management which
// has the capability of creating new accounts, reading existing accounts,
// and providing secure access to eth2 secrets depending on an
// associated keymanager (either direct, derived, or remote signing enabled).
type Wallet struct {
walletDir string
accountsPath string
passwordsDir string
keymanagerKind v2keymanager.Kind
@@ -77,9 +72,6 @@ func NewWallet(
keymanagerKind v2keymanager.Kind,
) (*Wallet, error) {
walletDir, err := inputDirectory(cliCtx, walletDirPromptText, flags.WalletDirFlag)
if err != nil && !errors.Is(err, ErrNoWalletFound) {
return nil, errors.Wrap(err, "could not parse wallet directory")
}
// Check if the user has a wallet at the specified path.
// If a user does not have a wallet, we instantiate one
// based on specified options.
@@ -94,9 +86,15 @@ func NewWallet(
w := &Wallet{
accountsPath: accountsPath,
keymanagerKind: keymanagerKind,
walletDir: walletDir,
}
if keymanagerKind == v2keymanager.Derived {
walletPassword, err := inputPassword(cliCtx, newWalletPasswordPromptText, confirmPass)
walletPassword, err := inputPassword(
cliCtx,
flags.WalletPasswordFileFlag,
newWalletPasswordPromptText,
confirmPass,
)
if err != nil {
return nil, errors.Wrap(err, "could not get password")
}
@@ -121,11 +119,16 @@ func NewWallet(
func OpenWallet(cliCtx *cli.Context) (*Wallet, error) {
// Read a wallet's directory from user input.
walletDir, err := inputDirectory(cliCtx, walletDirPromptText, flags.WalletDirFlag)
if errors.Is(err, ErrNoWalletFound) {
return nil, errors.New("no wallet found, create a new one with ./prysm.sh validator wallet-v2 create")
} else if err != nil {
if err != nil {
return nil, err
}
ok, err := hasDir(walletDir)
if err != nil {
return nil, errors.Wrap(err, "could not parse wallet directory")
}
if !ok {
return nil, ErrNoWalletFound
}
keymanagerKind, err := readKeymanagerKindFromWalletPath(walletDir)
if err != nil {
return nil, errors.Wrap(err, "could not read keymanager kind for wallet")
@@ -136,19 +139,31 @@ func OpenWallet(cliCtx *cli.Context) (*Wallet, error) {
keymanagerKind: keymanagerKind,
}
if keymanagerKind == v2keymanager.Derived {
walletPassword, err := inputPassword(cliCtx, walletPasswordPromptText, noConfirmPass)
walletPassword, err := inputPassword(
cliCtx,
flags.WalletPasswordFileFlag,
walletPasswordPromptText,
noConfirmPass,
)
if err != nil {
return nil, err
}
w.walletPassword = walletPassword
}
if keymanagerKind == v2keymanager.Direct {
passwordsDir, err := inputDirectory(cliCtx, passwordsDirPromptText, flags.WalletPasswordsDirFlag)
keymanagerCfg, err := w.ReadKeymanagerConfigFromDisk(context.Background())
if err != nil {
return nil, err
}
w.passwordsDir = passwordsDir
directCfg, err := direct.UnmarshalConfigFile(keymanagerCfg)
if err != nil {
return nil, err
}
w.passwordsDir = directCfg.AccountPasswordsDirectory
au := aurora.NewAurora(true)
log.Infof("%s %s", au.BrightMagenta("(account passwords path)"), w.passwordsDir)
}
log.Info("Successfully opened wallet")
return w, nil
}
@@ -380,12 +395,12 @@ func (w *Wallet) ReadPasswordFromDisk(ctx context.Context, passwordFileName stri
// enterPasswordForAccount checks if a user has a password specified for the new account
// either from a file or from stdin. Then, it saves the password to the wallet.
func (w *Wallet) enterPasswordForAccount(cliCtx *cli.Context, accountName string) error {
func (w *Wallet) enterPasswordForAccount(cliCtx *cli.Context, accountName string, pubKey []byte) error {
au := aurora.NewAurora(true)
var password string
var err error
if cliCtx.IsSet(flags.PasswordFileFlag.Name) {
passwordFilePath := cliCtx.String(flags.PasswordFileFlag.Name)
if cliCtx.IsSet(flags.AccountPasswordFileFlag.Name) {
passwordFilePath := cliCtx.String(flags.AccountPasswordFileFlag.Name)
data, err := ioutil.ReadFile(passwordFilePath)
if err != nil {
return err
@@ -393,7 +408,7 @@ func (w *Wallet) enterPasswordForAccount(cliCtx *cli.Context, accountName string
password = string(data)
err = w.checkPasswordForAccount(accountName, password)
if err != nil && strings.Contains(err.Error(), "invalid checksum") {
return fmt.Errorf("invalid password entered for account %s", accountName)
return fmt.Errorf("invalid password entered for account with public key %#x", pubKey)
}
if err != nil {
return err
@@ -403,7 +418,11 @@ func (w *Wallet) enterPasswordForAccount(cliCtx *cli.Context, accountName string
// Loop asking for the password until the user enters it correctly.
for attemptingPassword {
// Ask the user for the password to their account.
password, err = inputWeakPassword(cliCtx, fmt.Sprintf(passwordForAccountPromptText, au.BrightGreen(accountName)))
password, err = inputWeakPassword(
cliCtx,
flags.AccountPasswordFileFlag,
fmt.Sprintf(passwordForAccountPromptText, bytesutil.Trunc(pubKey)),
)
if err != nil {
return errors.Wrap(err, "could not input password")
}
@@ -474,6 +493,27 @@ func readKeymanagerKindFromWalletPath(walletPath string) (v2keymanager.Kind, err
return v2keymanager.ParseKind(list[0])
}
func createOrOpenWallet(cliCtx *cli.Context, creationFunc func(cliCtx *cli.Context) (*Wallet, error)) (*Wallet, error) {
directory := cliCtx.String(flags.WalletDirFlag.Name)
ok, err := hasDir(directory)
if err != nil {
return nil, errors.Wrapf(err, "could not check if wallet dir %s exists", directory)
}
var wallet *Wallet
if !ok {
wallet, err = creationFunc(cliCtx)
if err != nil {
return nil, errors.Wrapf(err, "Could not create wallet")
}
} else {
wallet, err = OpenWallet(cliCtx)
if err != nil {
return nil, errors.Wrap(err, "could not open wallet")
}
}
return wallet, nil
}
// Returns true if a file is not a directory and exists
// at the specified path.
func fileExists(filename string) bool {

View File

@@ -15,53 +15,55 @@ import (
// CreateWallet from user input with a desired keymanager. If a
// wallet already exists in the path, it suggests the user alternatives
// such as how to edit their existing wallet configuration.
func CreateWallet(cliCtx *cli.Context) error {
func CreateWallet(cliCtx *cli.Context) (*Wallet, error) {
keymanagerKind, err := inputKeymanagerKind(cliCtx)
if err != nil {
return err
return nil, err
}
w, err := NewWallet(cliCtx, keymanagerKind)
if err != nil && !errors.Is(err, ErrWalletExists) {
return errors.Wrap(err, "could not check if wallet directory exists")
return nil, errors.Wrap(err, "could not check if wallet directory exists")
}
if errors.Is(err, ErrWalletExists) {
return ErrWalletExists
return nil, ErrWalletExists
}
switch w.KeymanagerKind() {
case v2keymanager.Direct:
if err = createDirectKeymanagerWallet(cliCtx, w); err != nil {
return errors.Wrap(err, "could not initialize wallet with direct keymanager")
return nil, errors.Wrap(err, "could not initialize wallet with direct keymanager")
}
log.WithField("wallet-path", w.accountsPath).Infof(
log.WithField("wallet-path", w.walletDir).Info(
"Successfully created wallet with on-disk keymanager configuration. " +
"Make a new validator account with ./prysm.sh validator accounts-v2 create",
)
case v2keymanager.Derived:
if err = createDerivedKeymanagerWallet(cliCtx, w); err != nil {
return errors.Wrap(err, "could not initialize wallet with derived keymanager")
return nil, errors.Wrap(err, "could not initialize wallet with derived keymanager")
}
log.WithField("wallet-path", w.accountsPath).Infof(
log.WithField("wallet-path", w.walletDir).Info(
"Successfully created HD wallet and saved configuration to disk. " +
"Make a new validator account with ./prysm.sh validator accounts-2 create",
)
case v2keymanager.Remote:
if err = createRemoteKeymanagerWallet(cliCtx, w); err != nil {
return errors.Wrap(err, "could not initialize wallet with remote keymanager")
return nil, errors.Wrap(err, "could not initialize wallet with remote keymanager")
}
log.WithField("wallet-path", w.accountsPath).Infof(
log.WithField("wallet-path", w.walletDir).Info(
"Successfully created wallet with remote keymanager configuration",
)
default:
return errors.Wrapf(err, "keymanager type %s is not supported", w.KeymanagerKind())
return nil, errors.Wrapf(err, "keymanager type %s is not supported", w.KeymanagerKind())
}
return nil
return w, nil
}
func createDirectKeymanagerWallet(cliCtx *cli.Context, wallet *Wallet) error {
if err := wallet.SaveWallet(); err != nil {
return errors.Wrap(err, "could not save wallet to disk")
}
keymanagerConfig, err := direct.MarshalConfigFile(context.Background(), direct.DefaultConfig())
defaultConfig := direct.DefaultConfig()
defaultConfig.AccountPasswordsDirectory = wallet.passwordsDir
keymanagerConfig, err := direct.MarshalConfigFile(context.Background(), defaultConfig)
if err != nil {
return errors.Wrap(err, "could not marshal keymanager config file")
}

View File

@@ -6,6 +6,7 @@ import (
"os"
"testing"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/shared/testutil"
"github.com/prysmaticlabs/prysm/shared/testutil/assert"
"github.com/prysmaticlabs/prysm/shared/testutil/require"
@@ -14,9 +15,43 @@ import (
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/derived"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/remote"
logTest "github.com/sirupsen/logrus/hooks/test"
"github.com/urfave/cli/v2"
)
func TestCreateOrOpenWallet(t *testing.T) {
hook := logTest.NewGlobal()
walletDir, passwordsDir, _ := setupWalletAndPasswordsDir(t)
cliCtx := setupWalletCtx(t, &testWalletConfig{
walletDir: walletDir,
passwordsDir: passwordsDir,
keymanagerKind: v2keymanager.Direct,
})
createDirectWallet := func(cliCtx *cli.Context) (*Wallet, error) {
w, err := NewWallet(cliCtx, v2keymanager.Direct)
if err != nil && !errors.Is(err, ErrWalletExists) {
return nil, errors.Wrap(err, "could not create new wallet")
}
if err = createDirectKeymanagerWallet(cliCtx, w); err != nil {
return nil, errors.Wrap(err, "could not initialize wallet")
}
log.WithField("wallet-path", w.walletDir).Info(
"Successfully created new wallet",
)
return w, err
}
createdWallet, err := createOrOpenWallet(cliCtx, createDirectWallet)
require.NoError(t, err)
testutil.AssertLogsContain(t, hook, "Successfully created new wallet")
testutil.AssertLogsDoNotContain(t, hook, "Successfully opened wallet")
openedWallet, err := createOrOpenWallet(cliCtx, createDirectWallet)
require.NoError(t, err)
testutil.AssertLogsContain(t, hook, "Successfully opened wallet")
assert.Equal(t, createdWallet.KeymanagerKind(), openedWallet.KeymanagerKind())
assert.Equal(t, createdWallet.AccountsDir(), openedWallet.AccountsDir())
}
func TestCreateWallet_Direct(t *testing.T) {
walletDir, passwordsDir, _ := setupWalletAndPasswordsDir(t)
cliCtx := setupWalletCtx(t, &testWalletConfig{
@@ -26,7 +61,8 @@ func TestCreateWallet_Direct(t *testing.T) {
})
// We attempt to create the wallet.
require.NoError(t, CreateWallet(cliCtx))
_, err := CreateWallet(cliCtx)
require.NoError(t, err)
// We attempt to open the newly created wallet.
ctx := context.Background()
@@ -40,20 +76,23 @@ func TestCreateWallet_Direct(t *testing.T) {
assert.NoError(t, err)
// We assert the created configuration was as desired.
assert.DeepEqual(t, direct.DefaultConfig(), cfg)
wantedCfg := direct.DefaultConfig()
wantedCfg.AccountPasswordsDirectory = passwordsDir
assert.DeepEqual(t, wantedCfg, cfg)
}
func TestCreateWallet_Derived(t *testing.T) {
walletDir, passwordsDir, passwordFile := setupWalletAndPasswordsDir(t)
cliCtx := setupWalletCtx(t, &testWalletConfig{
walletDir: walletDir,
passwordsDir: passwordsDir,
passwordFile: passwordFile,
keymanagerKind: v2keymanager.Derived,
walletDir: walletDir,
passwordsDir: passwordsDir,
walletPasswordFile: passwordFile,
keymanagerKind: v2keymanager.Derived,
})
// We attempt to create the wallet.
require.NoError(t, CreateWallet(cliCtx))
_, err := CreateWallet(cliCtx)
require.NoError(t, err)
// We attempt to open the newly created wallet.
ctx := context.Background()
@@ -101,7 +140,8 @@ func TestCreateWallet_Remote(t *testing.T) {
cliCtx := cli.NewContext(&app, set, nil)
// We attempt to create the wallet.
require.NoError(t, CreateWallet(cliCtx))
_, err := CreateWallet(cliCtx)
require.NoError(t, err)
// We attempt to open the newly created wallet.
ctx := context.Background()

View File

@@ -5,7 +5,9 @@ import (
"fmt"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/validator/flags"
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct"
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/remote"
"github.com/urfave/cli/v2"
)
@@ -21,7 +23,30 @@ func EditWalletConfiguration(cliCtx *cli.Context) error {
}
switch wallet.KeymanagerKind() {
case v2keymanager.Direct:
return errors.New("no configuration options available to edit for direct keymanager")
enc, err := wallet.ReadKeymanagerConfigFromDisk(ctx)
if err != nil {
return errors.Wrap(err, "could not read config")
}
cfg, err := direct.UnmarshalConfigFile(enc)
if err != nil {
return errors.Wrap(err, "could not unmarshal config")
}
log.Info("Current configuration")
// Prints the current configuration to stdout.
fmt.Println(cfg)
passwordsDir, err := inputDirectory(cliCtx, passwordsDirPromptText, flags.WalletPasswordsDirFlag)
if err != nil {
return errors.Wrap(err, "could not get password directory")
}
defaultCfg := direct.DefaultConfig()
defaultCfg.AccountPasswordsDirectory = passwordsDir
encodedCfg, err := direct.MarshalConfigFile(ctx, defaultCfg)
if err != nil {
return errors.Wrap(err, "could not marshal config file")
}
if err := wallet.WriteKeymanagerConfigToDisk(ctx, encodedCfg); err != nil {
return errors.Wrap(err, "could not write config to disk")
}
case v2keymanager.Derived:
return errors.New("derived keymanager is not yet supported")
case v2keymanager.Remote:
@@ -33,8 +58,9 @@ func EditWalletConfiguration(cliCtx *cli.Context) error {
if err != nil {
return errors.Wrap(err, "could not unmarshal config")
}
log.Infof("Current configuration")
fmt.Printf("%s\n", cfg)
log.Info("Current configuration")
// Prints the current configuration to stdout.
fmt.Println(cfg)
newCfg, err := inputRemoteKeymanagerConfig(cliCtx)
if err != nil {
return errors.Wrap(err, "could not get keymanager config")

View File

@@ -58,9 +58,10 @@ func TestEditWalletConfiguration(t *testing.T) {
assert.NoError(t, set.Set(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath))
cliCtx = cli.NewContext(&app, set, nil)
assert.NoError(t, EditWalletConfiguration(cliCtx))
err = EditWalletConfiguration(cliCtx)
require.NoError(t, err)
encoded, err := wallet.ReadKeymanagerConfigFromDisk(ctx)
assert.NoError(t, err)
require.NoError(t, err)
cfg, err := remote.UnmarshalConfigFile(encoded)
assert.NoError(t, err)

View File

@@ -39,13 +39,13 @@ func TestRecoverDerivedWallet(t *testing.T) {
set := flag.NewFlagSet("test", 0)
set.String(flags.WalletDirFlag.Name, walletDir, "")
set.String(flags.WalletPasswordsDirFlag.Name, passwordsDir, "")
set.String(flags.PasswordFileFlag.Name, passwordFilePath, "")
set.String(flags.WalletPasswordFileFlag.Name, passwordFilePath, "")
set.String(flags.KeymanagerKindFlag.Name, v2keymanager.Derived.String(), "")
set.String(flags.MnemonicFileFlag.Name, mnemonicFilePath, "")
set.Int64(flags.NumAccountsFlag.Name, numAccounts, "")
assert.NoError(t, set.Set(flags.WalletDirFlag.Name, walletDir))
assert.NoError(t, set.Set(flags.WalletPasswordsDirFlag.Name, passwordsDir))
assert.NoError(t, set.Set(flags.PasswordFileFlag.Name, passwordFilePath))
assert.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, passwordFilePath))
assert.NoError(t, set.Set(flags.KeymanagerKindFlag.Name, v2keymanager.Derived.String()))
assert.NoError(t, set.Set(flags.MnemonicFileFlag.Name, mnemonicFilePath))
assert.NoError(t, set.Set(flags.NumAccountsFlag.Name, strconv.Itoa(int(numAccounts))))

View File

@@ -28,14 +28,15 @@ func init() {
}
type testWalletConfig struct {
walletDir string
passwordsDir string
exportDir string
keysDir string
accountsToExport string
passwordFile string
numAccounts int64
keymanagerKind v2keymanager.Kind
walletDir string
passwordsDir string
exportDir string
keysDir string
accountsToExport string
walletPasswordFile string
accountPasswordFile string
numAccounts int64
keymanagerKind v2keymanager.Kind
}
func setupWalletCtx(
@@ -50,7 +51,8 @@ func setupWalletCtx(
set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "")
set.String(flags.BackupDirFlag.Name, cfg.exportDir, "")
set.String(flags.AccountsFlag.Name, cfg.accountsToExport, "")
set.String(flags.PasswordFileFlag.Name, cfg.passwordFile, "")
set.String(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile, "")
set.String(flags.AccountPasswordFileFlag.Name, cfg.accountPasswordFile, "")
set.Bool(flags.SkipMnemonicConfirmFlag.Name, true, "")
set.Int64(flags.NumAccountsFlag.Name, cfg.numAccounts, "")
assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir))
@@ -59,7 +61,8 @@ func setupWalletCtx(
assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String()))
assert.NoError(tb, set.Set(flags.BackupDirFlag.Name, cfg.exportDir))
assert.NoError(tb, set.Set(flags.AccountsFlag.Name, cfg.accountsToExport))
assert.NoError(tb, set.Set(flags.PasswordFileFlag.Name, cfg.passwordFile))
assert.NoError(tb, set.Set(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile))
assert.NoError(tb, set.Set(flags.AccountPasswordFileFlag.Name, cfg.accountPasswordFile))
assert.NoError(tb, set.Set(flags.SkipMnemonicConfirmFlag.Name, "true"))
assert.NoError(tb, set.Set(flags.NumAccountsFlag.Name, strconv.Itoa(int(cfg.numAccounts))))
return cli.NewContext(&app, set, nil)
@@ -92,8 +95,8 @@ func TestCreateAndReadWallet(t *testing.T) {
keymanagerKind: v2keymanager.Direct,
})
wallet, err := NewWallet(cliCtx, v2keymanager.Direct)
require.NoError(t, wallet.SaveWallet())
require.NoError(t, err)
require.NoError(t, createDirectKeymanagerWallet(cliCtx, wallet))
// We should be able to now read the wallet as well.
_, err = OpenWallet(cliCtx)
require.NoError(t, err)

View File

@@ -12,6 +12,13 @@ import (
"github.com/urfave/cli/v2"
)
const (
// WalletDefaultDirName for accounts-v2.
WalletDefaultDirName = "prysm-wallet-v2"
// PasswordsDefaultDirName where account-v2 passwords are stored.
PasswordsDefaultDirName = "prysm-wallet-v2-passwords"
)
var (
// DisableAccountMetricsFlag defines the graffiti value included in proposed blocks, default false.
DisableAccountMetricsFlag = &cli.BoolFlag{
@@ -124,19 +131,24 @@ var (
WalletDirFlag = &cli.StringFlag{
Name: "wallet-dir",
Usage: "Path to a wallet directory on-disk for Prysm validator accounts",
Value: DefaultValidatorDir(),
Value: filepath.Join(DefaultValidatorDir(), WalletDefaultDirName),
}
// WalletPasswordsDirFlag defines the path for a passwords directory for
// Prysm accounts-v2.
WalletPasswordsDirFlag = &cli.StringFlag{
Name: "passwords-dir",
Usage: "Path to a directory on-disk where account passwords are stored",
Value: DefaultValidatorDir(),
Value: filepath.Join(DefaultValidatorDir(), PasswordsDefaultDirName),
}
// PasswordFileFlag is used to enter a file to get a password for new account creation, non-interactively.
PasswordFileFlag = &cli.StringFlag{
Name: "password-file",
Usage: "Path to a plaintext password.txt file",
// AccountPasswordFileFlag is path to a file containing a password for a new validator account.
AccountPasswordFileFlag = &cli.StringFlag{
Name: "account-password-file",
Usage: "Path to a plain-text, .txt file containing a password for a new validator account",
}
// WalletPasswordFileFlag is the path to a file containing your wallet password.
WalletPasswordFileFlag = &cli.StringFlag{
Name: "wallet-password-file",
Usage: "Path to a plain-text, .txt file containing your wallet password",
}
// MnemonicFileFlag is used to enter a file to mnemonic phrase for new wallet creation, non-interactively.
MnemonicFileFlag = &cli.StringFlag{

View File

@@ -20,8 +20,10 @@ go_library(
"//shared/petnames:go_default_library",
"//shared/roughtime:go_default_library",
"//validator/accounts/v2/iface:go_default_library",
"//validator/flags:go_default_library",
"//validator/keymanager/v2:go_default_library",
"@com_github_google_uuid//:go_default_library",
"@com_github_logrusorgru_aurora//:go_default_library",
"@com_github_pkg_errors//:go_default_library",
"@com_github_prysmaticlabs_go_ssz//:go_default_library",
"@com_github_sirupsen_logrus//:go_default_library",

View File

@@ -9,9 +9,11 @@ import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"sync"
"github.com/google/uuid"
"github.com/logrusorgru/aurora"
"github.com/pkg/errors"
"github.com/prysmaticlabs/go-ssz"
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
@@ -21,6 +23,7 @@ import (
"github.com/prysmaticlabs/prysm/shared/petnames"
"github.com/prysmaticlabs/prysm/shared/roughtime"
"github.com/prysmaticlabs/prysm/validator/accounts/v2/iface"
"github.com/prysmaticlabs/prysm/validator/flags"
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
"github.com/sirupsen/logrus"
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
@@ -47,7 +50,8 @@ const (
// Config for a direct keymanager.
type Config struct {
EIPVersion string `json:"direct_eip_version"`
EIPVersion string `json:"direct_eip_version"`
AccountPasswordsDirectory string `json:"direct_accounts_passwords_directory"`
}
// Keymanager implementation for direct keystores utilizing EIP-2335.
@@ -61,7 +65,8 @@ type Keymanager struct {
// DefaultConfig for a direct keymanager implementation.
func DefaultConfig() *Config {
return &Config{
EIPVersion: eipVersion,
EIPVersion: eipVersion,
AccountPasswordsDirectory: flags.WalletPasswordsDirFlag.Value,
}
}
@@ -106,6 +111,30 @@ func MarshalConfigFile(ctx context.Context, cfg *Config) ([]byte, error) {
return json.MarshalIndent(cfg, "", "\t")
}
// Config for the direct keymanager.
func (dr *Keymanager) Config() *Config {
return dr.cfg
}
// String pretty-print of a direct keymanager configuration.
func (c *Config) String() string {
au := aurora.NewAurora(true)
var b strings.Builder
strAddr := fmt.Sprintf("%s: %s\n", au.BrightMagenta("EIP Version"), c.EIPVersion)
if _, err := b.WriteString(strAddr); err != nil {
log.Error(err)
return ""
}
strCrt := fmt.Sprintf(
"%s: %s\n", au.BrightMagenta("Accounts Passwords Directory"), c.AccountPasswordsDirectory,
)
if _, err := b.WriteString(strCrt); err != nil {
log.Error(err)
return ""
}
return b.String()
}
// ValidatingAccountNames for a direct keymanager.
func (dr *Keymanager) ValidatingAccountNames() ([]string, error) {
return dr.wallet.ListDirs()

View File

@@ -72,7 +72,7 @@ var appFlags = []cli.Flag{
flags.SlasherRPCProviderFlag,
flags.SlasherCertFlag,
flags.WalletPasswordsDirFlag,
flags.PasswordFileFlag,
flags.WalletPasswordFileFlag,
flags.WalletDirFlag,
cmd.MinimalConfigFlag,
cmd.E2EConfigFlag,

View File

@@ -83,7 +83,6 @@ var appHelpFlagGroups = []flagGroup{
flags.KeyManagerOpts,
flags.KeystorePathFlag,
flags.PasswordFlag,
flags.PasswordFileFlag,
flags.DisablePenaltyRewardLogFlag,
flags.UnencryptedKeysFlag,
flags.GraffitiFlag,
@@ -98,6 +97,7 @@ var appHelpFlagGroups = []flagGroup{
flags.DisableAccountMetricsFlag,
flags.WalletDirFlag,
flags.WalletPasswordsDirFlag,
flags.WalletPasswordFileFlag,
},
},
{