prysm-pulse/validator/accounts/wallet_create.go
Sammy Rosso a15e0797e4
Support non english mnemonics for wallet creation (#11543)
* add option to log rejected gossip message

* add bip39 supported mnemonic languages

* Revert "add option to log rejected gossip message"

This reverts commit 9a3d4486f6c8a623d9eb6b3af1a5a89aa62ecf2f.

* Add mnemonic language flag

* Update go.mod

* Simplify language mapping

* Add test for setBip39Lang

* Update go.mod

* Improve language matching

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>

* Run gazelle + fix maligned struct

Co-authored-by: Preston Van Loon <preston@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2022-10-26 21:04:00 +00:00

136 lines
4.4 KiB
Go

package accounts
import (
"context"
"encoding/json"
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/validator/accounts/iface"
"github.com/prysmaticlabs/prysm/v3/validator/accounts/wallet"
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/derived"
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/local"
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
)
// WalletCreate creates wallet specified by configuration options.
func (acm *AccountsCLIManager) WalletCreate(ctx context.Context) (*wallet.Wallet, error) {
w := wallet.New(&wallet.Config{
WalletDir: acm.walletDir,
KeymanagerKind: acm.keymanagerKind,
WalletPassword: acm.walletPassword,
})
var err error
switch w.KeymanagerKind() {
case keymanager.Local:
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.
km, err := w.InitializeKeymanager(ctx, iface.InitKeymanagerConfig{ListenForChanges: false})
if err != nil {
return nil, errors.Wrap(err, ErrCouldNotInitializeKeymanager)
}
localKm, ok := km.(*local.Keymanager)
if !ok {
return nil, errors.Wrap(err, ErrCouldNotInitializeKeymanager)
}
accountsKeystore, err := localKm.CreateAccountsKeystore(ctx, make([][]byte, 0), make([][]byte, 0))
if err != nil {
return nil, err
}
encodedAccounts, err := json.MarshalIndent(accountsKeystore, "", "\t")
if err != nil {
return nil, err
}
if err = w.WriteFileAtPath(ctx, local.AccountsPath, local.AccountsKeystoreFileName, encodedAccounts); err != nil {
return nil, err
}
log.WithField("--wallet-dir", acm.walletDir).Info(
"Successfully created wallet with ability to import keystores",
)
case keymanager.Derived:
if err = createDerivedKeymanagerWallet(
ctx,
w,
acm.mnemonic25thWord,
acm.mnemonicLanguage,
acm.skipMnemonicConfirm,
acm.numAccounts,
); err != nil {
return nil, errors.Wrap(err, "could not initialize wallet")
}
log.WithField("--wallet-dir", acm.walletDir).Info(
"Successfully created HD wallet from mnemonic and regenerated accounts",
)
case keymanager.Remote:
if err = createRemoteKeymanagerWallet(ctx, w, acm.keymanagerOpts); err != nil {
return nil, errors.Wrap(err, "could not initialize wallet")
}
log.WithField("--wallet-dir", acm.walletDir).Info(
"Successfully created wallet with remote keymanager configuration",
)
case keymanager.Web3Signer:
return nil, errors.New("web3signer keymanager does not require persistent wallets.")
default:
return nil, errors.Wrapf(err, errKeymanagerNotSupported, w.KeymanagerKind())
}
return w, nil
}
func CreateLocalKeymanagerWallet(_ context.Context, wallet *wallet.Wallet) error {
if wallet == nil {
return errors.New("nil wallet")
}
if err := wallet.SaveWallet(); err != nil {
return errors.Wrap(err, "could not save wallet to disk")
}
return nil
}
func createDerivedKeymanagerWallet(
ctx context.Context,
wallet *wallet.Wallet,
mnemonicPassphrase string,
mnemonicLanguage string,
skipMnemonicConfirm bool,
numAccounts int,
) error {
if wallet == nil {
return errors.New("nil wallet")
}
if err := wallet.SaveWallet(); err != nil {
return errors.Wrap(err, "could not save wallet to disk")
}
km, err := derived.NewKeymanager(ctx, &derived.SetupConfig{
Wallet: wallet,
ListenForChanges: true,
})
if err != nil {
return errors.Wrap(err, "could not initialize HD keymanager")
}
mnemonic, err := derived.GenerateAndConfirmMnemonic(mnemonicLanguage, skipMnemonicConfirm)
if err != nil {
return errors.Wrap(err, "could not confirm mnemonic")
}
if err := km.RecoverAccountsFromMnemonic(ctx, mnemonic, mnemonicLanguage, mnemonicPassphrase, numAccounts); err != nil {
return errors.Wrap(err, "could not recover accounts from mnemonic")
}
return nil
}
func createRemoteKeymanagerWallet(ctx context.Context, wallet *wallet.Wallet, opts *remote.KeymanagerOpts) error {
keymanagerConfig, err := remote.MarshalOptionsFile(ctx, opts)
if err != nil {
return errors.Wrap(err, "could not marshal config file")
}
if err := wallet.SaveWallet(); err != nil {
return errors.Wrap(err, "could not save wallet to disk")
}
if err := wallet.WriteKeymanagerConfigToDisk(ctx, keymanagerConfig); err != nil {
return errors.Wrap(err, "could not write keymanager config to disk")
}
return nil
}