mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-07 20:43:57 -05:00
Refactor validator accounts import to remove cli context dependency (#10890)
Co-authored-by: Raul Jordan <raul@prysmaticlabs.com> Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
@@ -7,6 +7,7 @@ go_library(
|
||||
"backup.go",
|
||||
"delete.go",
|
||||
"exit.go",
|
||||
"import.go",
|
||||
"list.go",
|
||||
"wallet_utils.go",
|
||||
],
|
||||
@@ -36,6 +37,7 @@ go_test(
|
||||
"backup_test.go",
|
||||
"delete_test.go",
|
||||
"exit_test.go",
|
||||
"import_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/runtime/tos"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -139,13 +138,13 @@ var Commands = &cli.Command{
|
||||
if err := cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
return tos.VerifyTosAcceptedOrPrompt(cliCtx)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
if err := features.ConfigureValidator(cliCtx); err != nil {
|
||||
if err := tos.VerifyTosAcceptedOrPrompt(cliCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := accounts.ImportAccountsCli(cliCtx); err != nil {
|
||||
return features.ConfigureValidator(cliCtx)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
if err := accountsImport(cliCtx); err != nil {
|
||||
log.Fatalf("Could not import accounts: %v", err)
|
||||
}
|
||||
return nil
|
||||
|
||||
@@ -181,7 +181,7 @@ func TestBackupAccounts_Noninteractive_Imported(t *testing.T) {
|
||||
|
||||
// We attempt to import accounts we wrote to the keys directory
|
||||
// into our newly created wallet.
|
||||
require.NoError(t, accounts.ImportAccountsCli(cliCtx))
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
// Next, we attempt to backup the accounts.
|
||||
require.NoError(t, accountsBackup(cliCtx))
|
||||
|
||||
@@ -83,6 +83,7 @@ type testWalletConfig struct {
|
||||
deletePublicKeys string
|
||||
keysDir string
|
||||
backupDir string
|
||||
passwordsDir string
|
||||
walletDir string
|
||||
}
|
||||
|
||||
@@ -169,7 +170,7 @@ func TestDeleteAccounts_Noninteractive(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// We attempt to import accounts.
|
||||
require.NoError(t, accounts.ImportAccountsCli(cliCtx))
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
// We attempt to delete the accounts specified.
|
||||
require.NoError(t, accountsDelete(cliCtx))
|
||||
|
||||
@@ -75,7 +75,7 @@ func TestExitAccountsCli_OK(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, accounts.ImportAccountsCli(cliCtx))
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
_, keymanager, err := walletWithKeymanager(cliCtx)
|
||||
require.NoError(t, err)
|
||||
@@ -175,7 +175,7 @@ func TestExitAccountsCli_OK_AllPublicKeys(t *testing.T) {
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.NoError(t, accounts.ImportAccountsCli(cliCtx))
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
_, keymanager, err := walletWithKeymanager(cliCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
113
cmd/validator/accounts/import.go
Normal file
113
cmd/validator/accounts/import.go
Normal file
@@ -0,0 +1,113 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/cmd"
|
||||
"github.com/prysmaticlabs/prysm/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/iface"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/userprompt"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/validator/client"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func accountsImport(c *cli.Context) error {
|
||||
w, err := walletImport(c)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not initialize wallet")
|
||||
}
|
||||
km, err := w.InitializeKeymanager(c.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
dialOpts := client.ConstructDialOptions(
|
||||
c.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name),
|
||||
c.String(flags.CertFlag.Name),
|
||||
c.Uint(flags.GrpcRetriesFlag.Name),
|
||||
c.Duration(flags.GrpcRetryDelayFlag.Name),
|
||||
)
|
||||
grpcHeaders := strings.Split(c.String(flags.GrpcHeadersFlag.Name), ",")
|
||||
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWallet(w),
|
||||
accounts.WithKeymanager(km),
|
||||
accounts.WithGRPCDialOpts(dialOpts),
|
||||
accounts.WithBeaconRPCProvider(c.String(flags.BeaconRPCProviderFlag.Name)),
|
||||
accounts.WithGRPCHeaders(grpcHeaders),
|
||||
}
|
||||
|
||||
opts = append(opts, accounts.WithImportPrivateKeys(c.IsSet(flags.ImportPrivateKeyFileFlag.Name)))
|
||||
opts = append(opts, accounts.WithPrivateKeyFile(c.String(flags.ImportPrivateKeyFileFlag.Name)))
|
||||
opts = append(opts, accounts.WithReadPasswordFile(c.IsSet(flags.AccountPasswordFileFlag.Name)))
|
||||
opts = append(opts, accounts.WithPasswordFilePath(c.String(flags.AccountPasswordFileFlag.Name)))
|
||||
|
||||
keysDir, err := userprompt.InputDirectory(c, userprompt.ImportKeysDirPromptText, flags.KeysDirFlag)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse keys directory")
|
||||
}
|
||||
opts = append(opts, accounts.WithKeysDir(keysDir))
|
||||
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return acc.Import(c.Context)
|
||||
}
|
||||
|
||||
func walletImport(c *cli.Context) (*wallet.Wallet, error) {
|
||||
return wallet.OpenWalletOrElseCli(c, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
walletDir, err := userprompt.InputDirectory(cliCtx, userprompt.WalletDirPromptText, flags.WalletDirFlag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exists, err := wallet.Exists(walletDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, wallet.CheckExistsErrMsg)
|
||||
}
|
||||
if exists {
|
||||
isValid, err := wallet.IsValid(walletDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, wallet.CheckValidityErrMsg)
|
||||
}
|
||||
if !isValid {
|
||||
return nil, errors.New(wallet.InvalidWalletErrMsg)
|
||||
}
|
||||
walletPassword, err := wallet.InputPassword(
|
||||
cliCtx,
|
||||
flags.WalletPasswordFileFlag,
|
||||
wallet.PasswordPromptText,
|
||||
false, /* Do not confirm password */
|
||||
wallet.ValidateExistingPass,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
})
|
||||
}
|
||||
|
||||
cfg, err := accounts.ExtractWalletCreationConfigFromCli(cliCtx, keymanager.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w := wallet.New(&wallet.Config{
|
||||
KeymanagerKind: cfg.WalletCfg.KeymanagerKind,
|
||||
WalletDir: cfg.WalletCfg.WalletDir,
|
||||
WalletPassword: cfg.WalletCfg.WalletPassword,
|
||||
})
|
||||
if err = accounts.CreateLocalKeymanagerWallet(cliCtx.Context, w); err != nil {
|
||||
return nil, errors.Wrap(err, "could not create keymanager")
|
||||
}
|
||||
log.WithField("wallet-path", cfg.WalletCfg.WalletDir).Info(
|
||||
"Successfully created new wallet",
|
||||
)
|
||||
return w, nil
|
||||
})
|
||||
}
|
||||
262
cmd/validator/accounts/import_test.go
Normal file
262
cmd/validator/accounts/import_test.go
Normal file
@@ -0,0 +1,262 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/iface"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager/local"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
)
|
||||
|
||||
func TestImport_Noninteractive(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := accounts.CreateWalletWithKeymanager(cliCtx.Context, &accounts.CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
keymanager, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accounts, err := keymanager.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(accounts), 0)
|
||||
|
||||
// Create 2 keys.
|
||||
createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
createKeystore(t, keysDir)
|
||||
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
w, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, len(keys))
|
||||
}
|
||||
|
||||
// TestImport_DuplicateKeys is a regression test that ensures correction function if duplicate keys are being imported
|
||||
func TestImport_DuplicateKeys(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := accounts.CreateWalletWithKeymanager(cliCtx.Context, &accounts.CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a key and then copy it to create a duplicate
|
||||
_, keystorePath := createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
input, err := os.ReadFile(keystorePath)
|
||||
require.NoError(t, err)
|
||||
keystorePath2 := filepath.Join(keysDir, "copyOfKeystore.json")
|
||||
err = os.WriteFile(keystorePath2, input, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
_, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
// There should only be 1 account as the duplicate keystore was ignored
|
||||
assert.Equal(t, 1, len(keys))
|
||||
}
|
||||
|
||||
func TestImport_Noninteractive_RandomName(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := accounts.CreateWalletWithKeymanager(cliCtx.Context, &accounts.CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
keymanager, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accounts, err := keymanager.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(accounts), 0)
|
||||
|
||||
// Create 2 keys.
|
||||
createRandomNameKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
createRandomNameKeystore(t, keysDir)
|
||||
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
w, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, len(keys))
|
||||
}
|
||||
|
||||
// Returns the fullPath to the newly created keystore file.
|
||||
func createRandomNameKeystore(t *testing.T, path string) (*keymanager.Keystore, string) {
|
||||
validatingKey, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
encryptor := keystorev4.New()
|
||||
cryptoFields, err := encryptor.Encrypt(validatingKey.Marshal(), password)
|
||||
require.NoError(t, err)
|
||||
id, err := uuid.NewRandom()
|
||||
require.NoError(t, err)
|
||||
keystoreFile := &keymanager.Keystore{
|
||||
Crypto: cryptoFields,
|
||||
ID: id.String(),
|
||||
Pubkey: fmt.Sprintf("%x", validatingKey.PublicKey().Marshal()),
|
||||
Version: encryptor.Version(),
|
||||
Name: encryptor.Name(),
|
||||
}
|
||||
encoded, err := json.MarshalIndent(keystoreFile, "", "\t")
|
||||
require.NoError(t, err)
|
||||
// Write the encoded keystore to disk with the timestamp appended
|
||||
random, err := rand.Int(rand.Reader, big.NewInt(1000000))
|
||||
require.NoError(t, err)
|
||||
fullPath := filepath.Join(path, fmt.Sprintf("test-%d-keystore", random.Int64()))
|
||||
require.NoError(t, os.WriteFile(fullPath, encoded, os.ModePerm))
|
||||
return keystoreFile, fullPath
|
||||
}
|
||||
|
||||
func TestImport_Noninteractive_Filepath(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
_, keystorePath := createKeystore(t, keysDir)
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keystorePath,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := accounts.CreateWalletWithKeymanager(cliCtx.Context, &accounts.CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
keymanager, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accounts, err := keymanager.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(accounts), 0)
|
||||
|
||||
require.NoError(t, accountsImport(cliCtx))
|
||||
|
||||
w, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 1, len(keys))
|
||||
}
|
||||
@@ -14,17 +14,13 @@ import (
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/io/file"
|
||||
"github.com/prysmaticlabs/prysm/io/prompt"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/proto/eth/service"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/iface"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/userprompt"
|
||||
"github.com/prysmaticlabs/prysm/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
"github.com/urfave/cli/v2"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
)
|
||||
|
||||
@@ -81,93 +77,31 @@ type ImportAccountsConfig struct {
|
||||
// ImportAccountsCli can import external, EIP-2335 compliant keystore.json files as
|
||||
// new accounts into the Prysm validator wallet. This uses the CLI to extract
|
||||
// values necessary to run the function.
|
||||
func ImportAccountsCli(cliCtx *cli.Context) error {
|
||||
w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
walletDir, err := userprompt.InputDirectory(cliCtx, userprompt.WalletDirPromptText, flags.WalletDirFlag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
exists, err := wallet.Exists(walletDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, wallet.CheckExistsErrMsg)
|
||||
}
|
||||
if exists {
|
||||
isValid, err := wallet.IsValid(walletDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, wallet.CheckValidityErrMsg)
|
||||
}
|
||||
if !isValid {
|
||||
return nil, errors.New(wallet.InvalidWalletErrMsg)
|
||||
}
|
||||
walletPassword, err := wallet.InputPassword(
|
||||
cliCtx,
|
||||
flags.WalletPasswordFileFlag,
|
||||
wallet.PasswordPromptText,
|
||||
false, /* Do not confirm password */
|
||||
wallet.ValidateExistingPass,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: walletPassword,
|
||||
})
|
||||
}
|
||||
|
||||
cfg, err := extractWalletCreationConfigFromCli(cliCtx, keymanager.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
w := wallet.New(&wallet.Config{
|
||||
KeymanagerKind: cfg.WalletCfg.KeymanagerKind,
|
||||
WalletDir: cfg.WalletCfg.WalletDir,
|
||||
WalletPassword: cfg.WalletCfg.WalletPassword,
|
||||
})
|
||||
if err = createLocalKeymanagerWallet(cliCtx.Context, w); err != nil {
|
||||
return nil, errors.Wrap(err, "could not create keymanager")
|
||||
}
|
||||
log.WithField("wallet-path", cfg.WalletCfg.WalletDir).Info(
|
||||
"Successfully created new wallet",
|
||||
)
|
||||
return w, nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not initialize wallet")
|
||||
}
|
||||
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
k, ok := km.(keymanager.Importer)
|
||||
func (acm *AccountsCLIManager) Import(ctx context.Context) error {
|
||||
k, ok := acm.keymanager.(keymanager.Importer)
|
||||
if !ok {
|
||||
return errors.New("keymanager cannot import keystores")
|
||||
}
|
||||
|
||||
// Check if the user wishes to import a one-off, private key directly
|
||||
// as an account into the Prysm validator.
|
||||
if cliCtx.IsSet(flags.ImportPrivateKeyFileFlag.Name) {
|
||||
return importPrivateKeyAsAccount(cliCtx, w, k)
|
||||
if acm.importPrivateKeys {
|
||||
return importPrivateKeyAsAccount(ctx, acm.wallet, k, acm.privateKeyFile)
|
||||
}
|
||||
|
||||
keysDir, err := userprompt.InputDirectory(cliCtx, userprompt.ImportKeysDirPromptText, flags.KeysDirFlag)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not parse keys directory")
|
||||
}
|
||||
// Consider that the keysDir might be a path to a specific file and handle accordingly.
|
||||
isDir, err := file.HasDir(keysDir)
|
||||
isDir, err := file.HasDir(acm.keysDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not determine if path is a directory")
|
||||
}
|
||||
keystoresImported := make([]*keymanager.Keystore, 0)
|
||||
if isDir {
|
||||
files, err := os.ReadDir(keysDir)
|
||||
files, err := os.ReadDir(acm.keysDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not read dir")
|
||||
}
|
||||
if len(files) == 0 {
|
||||
return fmt.Errorf("directory %s has no files, cannot import from it", keysDir)
|
||||
return fmt.Errorf("directory %s has no files, cannot import from it", acm.keysDir)
|
||||
}
|
||||
filesInDir := make([]string, 0)
|
||||
for i := 0; i < len(files); i++ {
|
||||
@@ -180,7 +114,7 @@ func ImportAccountsCli(cliCtx *cli.Context) error {
|
||||
// specify this value in their filename.
|
||||
sort.Sort(byDerivationPath(filesInDir))
|
||||
for _, name := range filesInDir {
|
||||
keystore, err := readKeystoreFile(cliCtx.Context, filepath.Join(keysDir, name))
|
||||
keystore, err := readKeystoreFile(ctx, filepath.Join(acm.keysDir, name))
|
||||
if err != nil && strings.Contains(err.Error(), "could not decode keystore json") {
|
||||
continue
|
||||
} else if err != nil {
|
||||
@@ -189,7 +123,7 @@ func ImportAccountsCli(cliCtx *cli.Context) error {
|
||||
keystoresImported = append(keystoresImported, keystore)
|
||||
}
|
||||
} else {
|
||||
keystore, err := readKeystoreFile(cliCtx.Context, keysDir)
|
||||
keystore, err := readKeystoreFile(ctx, acm.keysDir)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not import keystore")
|
||||
}
|
||||
@@ -197,9 +131,8 @@ func ImportAccountsCli(cliCtx *cli.Context) error {
|
||||
}
|
||||
|
||||
var accountsPassword string
|
||||
if cliCtx.IsSet(flags.AccountPasswordFileFlag.Name) {
|
||||
passwordFilePath := cliCtx.String(flags.AccountPasswordFileFlag.Name)
|
||||
data, err := os.ReadFile(passwordFilePath) // #nosec G304
|
||||
if acm.readPasswordFile {
|
||||
data, err := os.ReadFile(acm.passwordFilePath) // #nosec G304
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -213,7 +146,7 @@ func ImportAccountsCli(cliCtx *cli.Context) error {
|
||||
}
|
||||
}
|
||||
fmt.Println("Importing accounts, this may take a while...")
|
||||
statuses, err := ImportAccounts(cliCtx.Context, &ImportAccountsConfig{
|
||||
statuses, err := ImportAccounts(ctx, &ImportAccountsConfig{
|
||||
Importer: k,
|
||||
Keystores: keystoresImported,
|
||||
AccountPassword: accountsPassword,
|
||||
@@ -265,8 +198,7 @@ func ImportAccounts(ctx context.Context, cfg *ImportAccountsConfig) ([]*ethpbser
|
||||
|
||||
// Imports a one-off file containing a private key as a hex string into
|
||||
// the Prysm validator's accounts.
|
||||
func importPrivateKeyAsAccount(cliCtx *cli.Context, wallet *wallet.Wallet, importer keymanager.Importer) error {
|
||||
privKeyFile := cliCtx.String(flags.ImportPrivateKeyFileFlag.Name)
|
||||
func importPrivateKeyAsAccount(ctx context.Context, wallet *wallet.Wallet, importer keymanager.Importer, privKeyFile string) error {
|
||||
fullPath, err := file.ExpandPath(privKeyFile)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "could not expand file path for %s", privKeyFile)
|
||||
@@ -297,7 +229,7 @@ func importPrivateKeyAsAccount(cliCtx *cli.Context, wallet *wallet.Wallet, impor
|
||||
return errors.Wrap(err, "could not encrypt private key into a keystore file")
|
||||
}
|
||||
statuses, err := ImportAccounts(
|
||||
cliCtx.Context,
|
||||
ctx,
|
||||
&ImportAccountsConfig{
|
||||
Importer: importer,
|
||||
AccountPassword: wallet.Password(),
|
||||
|
||||
@@ -2,15 +2,12 @@ package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
@@ -27,111 +24,6 @@ import (
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
)
|
||||
|
||||
func TestImport_Noninteractive(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
keymanager, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accounts, err := keymanager.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(accounts), 0)
|
||||
|
||||
// Create 2 keys.
|
||||
createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
createKeystore(t, keysDir)
|
||||
|
||||
require.NoError(t, ImportAccountsCli(cliCtx))
|
||||
|
||||
w, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, len(keys))
|
||||
}
|
||||
|
||||
// TestImport_DuplicateKeys is a regression test that ensures correction function if duplicate keys are being imported
|
||||
func TestImport_DuplicateKeys(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a key and then copy it to create a duplicate
|
||||
_, keystorePath := createKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
input, err := os.ReadFile(keystorePath)
|
||||
require.NoError(t, err)
|
||||
keystorePath2 := filepath.Join(keysDir, "copyOfKeystore.json")
|
||||
err = os.WriteFile(keystorePath2, input, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.NoError(t, ImportAccountsCli(cliCtx))
|
||||
|
||||
_, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
// There should only be 1 account as the duplicate keystore was ignored
|
||||
assert.Equal(t, 1, len(keys))
|
||||
}
|
||||
|
||||
func TestImportAccounts_NoPassword(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
@@ -166,115 +58,6 @@ func TestImportAccounts_NoPassword(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(resp))
|
||||
require.Equal(t, resp[0].Status, ethpbservice.ImportedKeystoreStatus_ERROR)
|
||||
|
||||
}
|
||||
|
||||
func TestImport_Noninteractive_RandomName(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keysDir,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
keymanager, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accounts, err := keymanager.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(accounts), 0)
|
||||
|
||||
// Create 2 keys.
|
||||
createRandomNameKeystore(t, keysDir)
|
||||
time.Sleep(time.Second)
|
||||
createRandomNameKeystore(t, keysDir)
|
||||
|
||||
require.NoError(t, ImportAccountsCli(cliCtx))
|
||||
|
||||
w, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 2, len(keys))
|
||||
}
|
||||
|
||||
func TestImport_Noninteractive_Filepath(t *testing.T) {
|
||||
local.ResetCaches()
|
||||
walletDir, passwordsDir, passwordFilePath := setupWalletAndPasswordsDir(t)
|
||||
keysDir := filepath.Join(t.TempDir(), "keysDir")
|
||||
require.NoError(t, os.MkdirAll(keysDir, os.ModePerm))
|
||||
|
||||
_, keystorePath := createKeystore(t, keysDir)
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
passwordsDir: passwordsDir,
|
||||
keysDir: keystorePath,
|
||||
keymanagerKind: keymanager.Local,
|
||||
walletPasswordFile: passwordFilePath,
|
||||
accountPasswordFile: passwordFilePath,
|
||||
})
|
||||
w, err := CreateWalletWithKeymanager(cliCtx.Context, &CreateWalletConfig{
|
||||
WalletCfg: &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
KeymanagerKind: keymanager.Local,
|
||||
WalletPassword: password,
|
||||
},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
keymanager, err := local.NewKeymanager(
|
||||
cliCtx.Context,
|
||||
&local.SetupConfig{
|
||||
Wallet: w,
|
||||
ListenForChanges: false,
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Make sure there are no accounts at the start.
|
||||
accounts, err := keymanager.ValidatingAccountNames()
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, len(accounts), 0)
|
||||
|
||||
require.NoError(t, ImportAccountsCli(cliCtx))
|
||||
|
||||
w, err = wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
WalletPassword: password,
|
||||
})
|
||||
require.NoError(t, err)
|
||||
km, err := w.InitializeKeymanager(cliCtx.Context, iface.InitKeymanagerConfig{ListenForChanges: false})
|
||||
require.NoError(t, err)
|
||||
keys, err := km.FetchValidatingPublicKeys(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, 1, len(keys))
|
||||
}
|
||||
|
||||
func TestImport_SortByDerivationPath(t *testing.T) {
|
||||
@@ -378,7 +161,7 @@ func Test_importPrivateKeyAsAccount(t *testing.T) {
|
||||
},
|
||||
)
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, importPrivateKeyAsAccount(cliCtx, wallet, keymanager))
|
||||
assert.NoError(t, importPrivateKeyAsAccount(cliCtx.Context, wallet, keymanager, privKeyFileName))
|
||||
|
||||
// We re-instantiate the keymanager and check we now have 1 public key.
|
||||
keymanager, err = local.NewKeymanager(
|
||||
@@ -419,29 +202,3 @@ func createKeystore(t *testing.T, path string) (*keymanager.Keystore, string) {
|
||||
require.NoError(t, os.WriteFile(fullPath, encoded, os.ModePerm))
|
||||
return keystoreFile, fullPath
|
||||
}
|
||||
|
||||
// Returns the fullPath to the newly created keystore file.
|
||||
func createRandomNameKeystore(t *testing.T, path string) (*keymanager.Keystore, string) {
|
||||
validatingKey, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
encryptor := keystorev4.New()
|
||||
cryptoFields, err := encryptor.Encrypt(validatingKey.Marshal(), password)
|
||||
require.NoError(t, err)
|
||||
id, err := uuid.NewRandom()
|
||||
require.NoError(t, err)
|
||||
keystoreFile := &keymanager.Keystore{
|
||||
Crypto: cryptoFields,
|
||||
ID: id.String(),
|
||||
Pubkey: fmt.Sprintf("%x", validatingKey.PublicKey().Marshal()),
|
||||
Version: encryptor.Version(),
|
||||
Name: encryptor.Name(),
|
||||
}
|
||||
encoded, err := json.MarshalIndent(keystoreFile, "", "\t")
|
||||
require.NoError(t, err)
|
||||
// Write the encoded keystore to disk with the timestamp appended
|
||||
random, err := rand.Int(rand.Reader, big.NewInt(1000000))
|
||||
require.NoError(t, err)
|
||||
fullPath := filepath.Join(path, fmt.Sprintf("test-%d-keystore", random.Int64()))
|
||||
require.NoError(t, os.WriteFile(fullPath, encoded, os.ModePerm))
|
||||
return keystoreFile, fullPath
|
||||
}
|
||||
|
||||
@@ -32,10 +32,15 @@ type AccountsCLIManager struct {
|
||||
showPrivateKeys bool
|
||||
listValidatorIndices bool
|
||||
deletePublicKeys bool
|
||||
importPrivateKeys bool
|
||||
readPasswordFile bool
|
||||
dialOpts []grpc.DialOption
|
||||
grpcHeaders []string
|
||||
beaconRPCProvider string
|
||||
walletKeyCount int
|
||||
privateKeyFile string
|
||||
passwordFilePath string
|
||||
keysDir string
|
||||
backupsDir string
|
||||
backupsPassword string
|
||||
filteredPubKeys []bls.PublicKey
|
||||
|
||||
@@ -90,6 +90,46 @@ func WithDeletePublicKeys(deletePublicKeys bool) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithReadPasswordFile indicates whether to read the password from a file.
|
||||
func WithReadPasswordFile(readPasswordFile bool) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
acc.readPasswordFile = readPasswordFile
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithImportPrivateKeys indicates whether to import private keys as accounts.
|
||||
func WithImportPrivateKeys(importPrivateKeys bool) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
acc.importPrivateKeys = importPrivateKeys
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPrivateKeyFile specifies the private key path.
|
||||
func WithPrivateKeyFile(privateKeyFile string) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
acc.privateKeyFile = privateKeyFile
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithKeysDir specifies the directory keys are read from.
|
||||
func WithKeysDir(keysDir string) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
acc.keysDir = keysDir
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithPasswordFilePath specifies where the password is stored.
|
||||
func WithPasswordFilePath(passwordFilePath string) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
acc.passwordFilePath = passwordFilePath
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithBackupDir specifies the directory backups are written to.
|
||||
func WithBackupsDir(backupsDir string) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
|
||||
@@ -40,7 +40,7 @@ func CreateAndSaveWalletCli(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
createWalletConfig, err := extractWalletCreationConfigFromCli(cliCtx, keymanagerKind)
|
||||
createWalletConfig, err := ExtractWalletCreationConfigFromCli(cliCtx, keymanagerKind)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -72,7 +72,7 @@ func CreateWalletWithKeymanager(ctx context.Context, cfg *CreateWalletConfig) (*
|
||||
var err error
|
||||
switch w.KeymanagerKind() {
|
||||
case keymanager.Local:
|
||||
if err = createLocalKeymanagerWallet(ctx, w); err != nil {
|
||||
if err = CreateLocalKeymanagerWallet(ctx, w); err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialize wallet")
|
||||
}
|
||||
// TODO(#9883) - Remove this when we have a better way to handle this. should be safe to use for now.
|
||||
@@ -131,7 +131,8 @@ func extractKeymanagerKindFromCli(cliCtx *cli.Context) (keymanager.Kind, error)
|
||||
return inputKeymanagerKind(cliCtx)
|
||||
}
|
||||
|
||||
func extractWalletCreationConfigFromCli(cliCtx *cli.Context, keymanagerKind keymanager.Kind) (*CreateWalletConfig, error) {
|
||||
// ExtractWalletCreationConfigFromCli prompts the user for wallet creation input.
|
||||
func ExtractWalletCreationConfigFromCli(cliCtx *cli.Context, keymanagerKind keymanager.Kind) (*CreateWalletConfig, error) {
|
||||
walletDir, err := userprompt.InputDirectory(cliCtx, userprompt.WalletDirPromptText, flags.WalletDirFlag)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -204,7 +205,7 @@ func extractWalletCreationConfigFromCli(cliCtx *cli.Context, keymanagerKind keym
|
||||
return createWalletConfig, nil
|
||||
}
|
||||
|
||||
func createLocalKeymanagerWallet(_ context.Context, wallet *wallet.Wallet) error {
|
||||
func CreateLocalKeymanagerWallet(_ context.Context, wallet *wallet.Wallet) error {
|
||||
if wallet == nil {
|
||||
return errors.New("nil wallet")
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ func TestCreateOrOpenWallet(t *testing.T) {
|
||||
walletPasswordFile: walletPasswordFile,
|
||||
})
|
||||
createLocalWallet := func(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
cfg, err := extractWalletCreationConfigFromCli(cliCtx, keymanager.Local)
|
||||
cfg, err := ExtractWalletCreationConfigFromCli(cliCtx, keymanager.Local)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -128,7 +128,7 @@ func TestCreateOrOpenWallet(t *testing.T) {
|
||||
WalletDir: cfg.WalletCfg.WalletDir,
|
||||
WalletPassword: cfg.WalletCfg.WalletPassword,
|
||||
})
|
||||
if err = createLocalKeymanagerWallet(cliCtx.Context, w); err != nil {
|
||||
if err = CreateLocalKeymanagerWallet(cliCtx.Context, w); err != nil {
|
||||
return nil, errors.Wrap(err, "could not create keymanager")
|
||||
}
|
||||
log.WithField("wallet-path", cfg.WalletCfg.WalletDir).Info(
|
||||
|
||||
Reference in New Issue
Block a user