mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-09 15:37:56 -05:00
Integrate Accounts v2 Keymanager Into Validator Client (#6489)
* add in configs * ask for enable accounts v2 * begin integration of v2 keymanager * refactor wallet opening * include significant refactoring of how opening a wallet works, making it easy to include at runtime * ensure build with keymanager v2 * further improving runtime integration * default pass paths * finally running v2 at runtime * import spacing * Merge branch 'master' into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * confs * rem e2e val flag * Merge branch 'master' into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature * Merge refs/heads/master into v2-accounts-feature
This commit is contained in:
@@ -54,6 +54,7 @@ type Flags struct {
|
||||
NewStateMgmt bool // NewStateMgmt enables the new state mgmt service.
|
||||
WaitForSynced bool // WaitForSynced uses WaitForSynced in validator startup to ensure it can communicate with the beacon node as soon as possible.
|
||||
ReduceAttesterStateCopy bool // ReduceAttesterStateCopy reduces head state copies for attester rpc.
|
||||
EnableAccountsV2 bool // EnableAccountsV2 for Prysm validator clients.
|
||||
BatchBlockVerify bool // BatchBlockVerify performs batched verification of block batches that we receive when syncing.
|
||||
InitSyncVerbose bool // InitSyncVerbose logs every processed block during initial syncing.
|
||||
// DisableForkChoice disables using LMD-GHOST fork choice to update
|
||||
@@ -264,6 +265,10 @@ func ConfigureValidator(ctx *cli.Context) {
|
||||
log.Warn("Enabled validator slashing protection.")
|
||||
cfg.LocalProtection = true
|
||||
}
|
||||
if ctx.Bool(enableAccountsV2.Name) {
|
||||
log.Warn("Enabling v2 of Prysm validator accounts")
|
||||
cfg.EnableAccountsV2 = true
|
||||
}
|
||||
if ctx.Bool(enableExternalSlasherProtectionFlag.Name) {
|
||||
log.Warn("Enabled validator attestation and block slashing protection using an external slasher.")
|
||||
cfg.SlasherProtection = true
|
||||
|
||||
@@ -144,6 +144,10 @@ var (
|
||||
Name: "altona",
|
||||
Usage: "This defines the flag through which we can run on the Altona Multiclient Testnet",
|
||||
}
|
||||
enableAccountsV2 = &cli.BoolFlag{
|
||||
Name: "enable-accounts-v2",
|
||||
Usage: "Enables usage of v2 for Prysm validator accounts",
|
||||
}
|
||||
batchBlockVerify = &cli.BoolFlag{
|
||||
Name: "batch-block-verify",
|
||||
Usage: "When enabled we will perform full signature verification of blocks in batches instead of singularly.",
|
||||
@@ -562,6 +566,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{
|
||||
disableDomainDataCacheFlag,
|
||||
waitForSyncedFlag,
|
||||
altonaTestnet,
|
||||
enableAccountsV2,
|
||||
}...)
|
||||
|
||||
// SlasherFlags contains a list of all the feature flags that apply to the slasher client.
|
||||
|
||||
@@ -3,7 +3,6 @@ package v2
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"os"
|
||||
"path"
|
||||
"unicode"
|
||||
|
||||
@@ -12,7 +11,6 @@ import (
|
||||
"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/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
@@ -52,20 +50,12 @@ func NewAccount(cliCtx *cli.Context) error {
|
||||
// based on specified options.
|
||||
var wallet *Wallet
|
||||
var isNewWallet bool
|
||||
ok, err := hasWalletDir(walletDir)
|
||||
if err != nil {
|
||||
log.Fatalf("Could not check if wallet exists at %s: %v", walletDir, err)
|
||||
}
|
||||
if ok {
|
||||
// Read the wallet from the specified path.
|
||||
wallet, err = OpenWallet(ctx, &WalletConfig{
|
||||
PasswordsDir: passwordsDirPath,
|
||||
WalletDir: walletDir,
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatalf("Could not read wallet at specified path %s: %v", walletDir, err)
|
||||
}
|
||||
} else {
|
||||
// Read the wallet from the specified path.
|
||||
wallet, err = OpenWallet(ctx, &WalletConfig{
|
||||
PasswordsDir: passwordsDirPath,
|
||||
WalletDir: walletDir,
|
||||
})
|
||||
if err == ErrNoWalletFound {
|
||||
// Determine the desired keymanager kind for the wallet from user input.
|
||||
keymanagerKind, err := inputKeymanagerKind(cliCtx)
|
||||
if err != nil {
|
||||
@@ -82,14 +72,16 @@ func NewAccount(cliCtx *cli.Context) error {
|
||||
log.Fatalf("Could not create wallet at specified path %s: %v", walletDir, err)
|
||||
}
|
||||
isNewWallet = true
|
||||
} else if err != nil {
|
||||
log.Fatalf("Could not read wallet at specified path %s: %v", walletDir, err)
|
||||
}
|
||||
|
||||
// We initialize a new keymanager depending on the user's selected keymanager kind.
|
||||
var keymanager v2keymanager.IKeymanager
|
||||
if isNewWallet {
|
||||
keymanager, err = initializeNewKeymanager(ctx, wallet)
|
||||
keymanager, err = wallet.CreateKeymanager(ctx)
|
||||
} else {
|
||||
keymanager, err = initializeExistingKeymanager(ctx, wallet)
|
||||
keymanager, err = wallet.ExistingKeyManager(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Could not initialize keymanager: %v", err)
|
||||
@@ -108,77 +100,10 @@ func NewAccount(cliCtx *cli.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Initializes a keymanager. If a config file exists in the wallet, it
|
||||
// reads the config file and initializes the keymanager that way. Otherwise,
|
||||
// writes a new configuration file to the wallet and returns the initialized
|
||||
// keymanager for use.
|
||||
func initializeNewKeymanager(ctx context.Context, wallet *Wallet) (v2keymanager.IKeymanager, error) {
|
||||
var keymanager v2keymanager.IKeymanager
|
||||
var err error
|
||||
switch wallet.KeymanagerKind() {
|
||||
case v2keymanager.Direct:
|
||||
keymanager, err = direct.NewKeymanager(ctx, wallet, direct.DefaultConfig())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read keymanager")
|
||||
}
|
||||
case v2keymanager.Derived:
|
||||
return nil, errors.New("derived keymanager is unimplemented, work in progress")
|
||||
case v2keymanager.Remote:
|
||||
return nil, errors.New("remote keymanager is unimplemented, work in progress")
|
||||
default:
|
||||
return nil, errors.New("keymanager type must be specified")
|
||||
}
|
||||
keymanagerConfig, err := keymanager.MarshalConfigFile(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not marshal keymanager config file")
|
||||
}
|
||||
if err := wallet.WriteKeymanagerConfigToDisk(ctx, keymanagerConfig); err != nil {
|
||||
return nil, errors.Wrap(err, "could not write keymanager config file to disk")
|
||||
}
|
||||
return keymanager, nil
|
||||
}
|
||||
|
||||
func initializeExistingKeymanager(
|
||||
ctx context.Context, wallet *Wallet,
|
||||
) (v2keymanager.IKeymanager, error) {
|
||||
var keymanager v2keymanager.IKeymanager
|
||||
switch wallet.KeymanagerKind() {
|
||||
case v2keymanager.Direct:
|
||||
configFile, err := wallet.ReadKeymanagerConfigFromDisk(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read keymanager config")
|
||||
}
|
||||
cfg, err := direct.UnmarshalConfigFile(configFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal keymanager config file")
|
||||
}
|
||||
keymanager, err = direct.NewKeymanager(ctx, wallet, cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialize keymanager")
|
||||
}
|
||||
case v2keymanager.Derived:
|
||||
return nil, errors.New("derived keymanager is unimplemented, work in progress")
|
||||
case v2keymanager.Remote:
|
||||
return nil, errors.New("remote keymanager is unimplemented, work in progress")
|
||||
default:
|
||||
return nil, errors.New("keymanager kind must be specified")
|
||||
}
|
||||
return keymanager, nil
|
||||
}
|
||||
|
||||
// Check if a user has an existing wallet at the specified path.
|
||||
func hasWalletDir(walletPath string) (bool, error) {
|
||||
_, err := os.Stat(walletPath)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
}
|
||||
|
||||
func inputWalletDir(cliCtx *cli.Context) (string, error) {
|
||||
walletDir := cliCtx.String(flags.WalletDirFlag.Name)
|
||||
if walletDir == flags.DefaultValidatorDir() {
|
||||
walletDir = path.Join(walletDir, walletDefaultDirName)
|
||||
walletDir = path.Join(walletDir, WalletDefaultDirName)
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Enter a wallet directory",
|
||||
@@ -244,7 +169,7 @@ func inputAccountPassword(_ *cli.Context) (string, error) {
|
||||
func inputPasswordsDirectory(cliCtx *cli.Context) string {
|
||||
passwordsDir := cliCtx.String(flags.WalletPasswordsDirFlag.Name)
|
||||
if passwordsDir == flags.DefaultValidatorDir() {
|
||||
passwordsDir = path.Join(passwordsDir, walletDefaultDirName, passwordsDefaultDirName)
|
||||
passwordsDir = path.Join(passwordsDir, PasswordsDefaultDirName)
|
||||
}
|
||||
prompt := promptui.Prompt{
|
||||
Label: "Passwords directory",
|
||||
|
||||
@@ -11,19 +11,27 @@ import (
|
||||
petname "github.com/dustinkirkland/golang-petname"
|
||||
"github.com/pkg/errors"
|
||||
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager/v2/direct"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
const (
|
||||
// WalletDefaultDirName for accounts-v2.
|
||||
WalletDefaultDirName = ".prysm-wallet-v2"
|
||||
// PasswordsDefaultDirName where account passwords are stored.
|
||||
PasswordsDefaultDirName = ".prysm-wallet-v2-passwords"
|
||||
keymanagerConfigFileName = "keymanageropts.json"
|
||||
walletDefaultDirName = ".prysm-wallet-v2"
|
||||
passwordsDefaultDirName = ".passwords"
|
||||
passwordFileSuffix = ".pass"
|
||||
numAccountWords = 3 // Number of words in account human-readable names.
|
||||
accountFilePermissions = os.O_CREATE | os.O_RDWR
|
||||
directoryPermissions = os.ModePerm
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrNoWalletFound signifies there is no data at the given wallet path.
|
||||
ErrNoWalletFound = errors.New("no wallet found at path")
|
||||
)
|
||||
|
||||
// WalletConfig for a wallet struct, containing important information
|
||||
// such as the passwords directory, the wallet's directory, and keymanager.
|
||||
type WalletConfig struct {
|
||||
@@ -67,13 +75,46 @@ func CreateWallet(ctx context.Context, cfg *WalletConfig) (*Wallet, error) {
|
||||
return w, nil
|
||||
}
|
||||
|
||||
// OpenWallet instantiates a wallet from a specified path.
|
||||
// OpenWallet instantiates a wallet from a specified path. It checks the
|
||||
// type of keymanager associated with the wallet by reading files in the wallet
|
||||
// path, if applicable. If a wallet does not exist, returns an appropriate error.
|
||||
func OpenWallet(ctx context.Context, cfg *WalletConfig) (*Wallet, error) {
|
||||
ok, err := hasDir(cfg.WalletDir)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not check if wallet exists at %s", cfg.WalletDir)
|
||||
}
|
||||
if !ok {
|
||||
return nil, ErrNoWalletFound
|
||||
}
|
||||
walletPath := path.Join(cfg.WalletDir, cfg.KeymanagerKind.String())
|
||||
walletDir, err := os.Open(cfg.WalletDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer func() {
|
||||
if err := walletDir.Close(); err != nil {
|
||||
log.WithField(
|
||||
"path", walletPath,
|
||||
).Errorf("Could not close wallet directory: %v", err)
|
||||
}
|
||||
}()
|
||||
// Retrieve the type of keymanager the wallet uses by looking at
|
||||
// directories in its directory path.
|
||||
list, err := walletDir.Readdirnames(0) // 0 to read all files and folders.
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not read files in directory: %s", walletPath)
|
||||
}
|
||||
if len(list) != 1 {
|
||||
return nil, fmt.Errorf("expected a single directory in the wallet path: %s", walletPath)
|
||||
}
|
||||
keymanagerKind, err := v2keymanager.ParseKind(list[0])
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not parse keymanager kind from wallet path")
|
||||
}
|
||||
return &Wallet{
|
||||
accountsPath: walletPath,
|
||||
passwordsDir: cfg.PasswordsDir,
|
||||
keymanagerKind: cfg.KeymanagerKind,
|
||||
keymanagerKind: keymanagerKind,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -115,7 +156,77 @@ func (w *Wallet) AccountNames() ([]string, error) {
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not read files in directory: %s", w.accountsPath)
|
||||
}
|
||||
return list, err
|
||||
accountNames := make([]string, 0)
|
||||
for _, item := range list {
|
||||
ok, err := hasDir(path.Join(w.accountsPath, item))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not parse directory: %v", err)
|
||||
}
|
||||
if ok {
|
||||
accountNames = append(accountNames, item)
|
||||
}
|
||||
}
|
||||
return accountNames, err
|
||||
}
|
||||
|
||||
// ExistingKeyManager reads a keymanager config from disk at the wallet path,
|
||||
// unmarshals it based on the wallet's keymanager kind, and returns its value.
|
||||
func (w *Wallet) ExistingKeyManager(
|
||||
ctx context.Context,
|
||||
) (v2keymanager.IKeymanager, error) {
|
||||
var keymanager v2keymanager.IKeymanager
|
||||
switch w.KeymanagerKind() {
|
||||
case v2keymanager.Direct:
|
||||
configFile, err := w.ReadKeymanagerConfigFromDisk(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read keymanager config")
|
||||
}
|
||||
cfg, err := direct.UnmarshalConfigFile(configFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal keymanager config file")
|
||||
}
|
||||
keymanager, err = direct.NewKeymanager(ctx, w, cfg)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialize keymanager")
|
||||
}
|
||||
case v2keymanager.Derived:
|
||||
return nil, errors.New("derived keymanager is unimplemented, work in progress")
|
||||
case v2keymanager.Remote:
|
||||
return nil, errors.New("remote keymanager is unimplemented, work in progress")
|
||||
default:
|
||||
return nil, errors.New("keymanager kind must be specified")
|
||||
}
|
||||
return keymanager, nil
|
||||
}
|
||||
|
||||
// CreateKeymanager determines if a config file exists in the wallet, it
|
||||
// reads the config file and initializes the keymanager that way. Otherwise,
|
||||
// writes a new configuration file to the wallet and returns the initialized
|
||||
// keymanager for use.
|
||||
func (w *Wallet) CreateKeymanager(ctx context.Context) (v2keymanager.IKeymanager, error) {
|
||||
var keymanager v2keymanager.IKeymanager
|
||||
var err error
|
||||
switch w.KeymanagerKind() {
|
||||
case v2keymanager.Direct:
|
||||
keymanager, err = direct.NewKeymanager(ctx, w, direct.DefaultConfig())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read keymanager")
|
||||
}
|
||||
case v2keymanager.Derived:
|
||||
return nil, errors.New("derived keymanager is unimplemented, work in progress")
|
||||
case v2keymanager.Remote:
|
||||
return nil, errors.New("remote keymanager is unimplemented, work in progress")
|
||||
default:
|
||||
return nil, errors.New("keymanager type must be specified")
|
||||
}
|
||||
keymanagerConfig, err := keymanager.MarshalConfigFile(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not marshal keymanager config file")
|
||||
}
|
||||
if err := w.WriteKeymanagerConfigToDisk(ctx, keymanagerConfig); err != nil {
|
||||
return nil, errors.Wrap(err, "could not write keymanager config file to disk")
|
||||
}
|
||||
return keymanager, nil
|
||||
}
|
||||
|
||||
// WriteAccountToDisk creates an account directory under a unique namespace
|
||||
@@ -297,10 +408,11 @@ func fileExists(filename string) bool {
|
||||
return !info.IsDir()
|
||||
}
|
||||
|
||||
// Checks if a directory indeed exists at the specified path.
|
||||
func hasDir(dirPath string) (bool, error) {
|
||||
_, err := os.Stat(dirPath)
|
||||
info, err := os.Stat(dirPath)
|
||||
if os.IsNotExist(err) {
|
||||
return false, nil
|
||||
}
|
||||
return true, err
|
||||
return info.IsDir(), err
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ go_library(
|
||||
"//beacon-chain/core/helpers:go_default_library",
|
||||
"//beacon-chain/state/stateutil:go_default_library",
|
||||
"//proto/slashing:go_default_library",
|
||||
"//proto/validator/accounts/v2:go_default_library",
|
||||
"//shared/blockutil:go_default_library",
|
||||
"//shared/bls:go_default_library",
|
||||
"//shared/bytesutil:go_default_library",
|
||||
@@ -33,6 +34,7 @@ go_library(
|
||||
"//validator/db:go_default_library",
|
||||
"//validator/db/kv:go_default_library",
|
||||
"//validator/keymanager/v1:go_default_library",
|
||||
"//validator/keymanager/v2:go_default_library",
|
||||
"//validator/slashing-protection:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_gogo_protobuf//proto:go_default_library",
|
||||
|
||||
@@ -111,7 +111,7 @@ func (v *validator) signSlot(ctx context.Context, pubKey [48]byte, slot uint64)
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig, err := v.signObject(pubKey, slot, domain.SignatureDomain)
|
||||
sig, err := v.signObject(ctx, pubKey, slot, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "Failed to sign slot")
|
||||
}
|
||||
@@ -142,7 +142,7 @@ func (v *validator) aggregateAndProofSig(ctx context.Context, pubKey [48]byte, a
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
sig, err := v.signObject(pubKey, agg, d.SignatureDomain)
|
||||
sig, err := v.signObject(ctx, pubKey, agg, d.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -10,8 +10,10 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-bitfield"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/hashutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/shared/roughtime"
|
||||
@@ -175,10 +177,17 @@ func (v *validator) signAtt(ctx context.Context, pubKey [48]byte, data *ethpb.At
|
||||
}
|
||||
|
||||
var sig bls.Signature
|
||||
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
|
||||
sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data)
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
Data: root[:],
|
||||
})
|
||||
} else {
|
||||
sig, err = v.keyManager.Sign(pubKey, root)
|
||||
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
|
||||
sig, err = protectingKeymanager.SignAttestation(pubKey, bytesutil.ToBytes32(domain.SignatureDomain), data)
|
||||
} else {
|
||||
sig, err = v.keyManager.Sign(pubKey, root)
|
||||
}
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/prometheus/client_golang/prometheus/promauto"
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
@@ -140,7 +141,13 @@ func (v *validator) LogValidatorGainsAndLosses(ctx context.Context, slot uint64)
|
||||
return nil
|
||||
}
|
||||
|
||||
pks, err := v.keyManager.FetchValidatingKeys()
|
||||
var pks [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
pks, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
} else {
|
||||
pks, err = v.keyManager.FetchValidatingKeys()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,8 +9,10 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/state/stateutil"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
km "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
"github.com/sirupsen/logrus"
|
||||
@@ -124,7 +126,7 @@ func (v *validator) signRandaoReveal(ctx context.Context, pubKey [48]byte, epoch
|
||||
return nil, errors.Wrap(err, "could not get domain data")
|
||||
}
|
||||
|
||||
randaoReveal, err := v.signObject(pubKey, epoch, domain.SignatureDomain)
|
||||
randaoReveal, err := v.signObject(ctx, pubKey, epoch, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign reveal")
|
||||
}
|
||||
@@ -138,6 +140,21 @@ func (v *validator) signBlock(ctx context.Context, pubKey [48]byte, epoch uint64
|
||||
return nil, errors.Wrap(err, "could not get domain data")
|
||||
}
|
||||
var sig bls.Signature
|
||||
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
blockRoot, err := helpers.ComputeSigningRoot(b, domain.SignatureDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not get signing root")
|
||||
}
|
||||
sig, err = v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
Data: blockRoot[:],
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not sign block proposal")
|
||||
}
|
||||
return sig.Marshal(), nil
|
||||
}
|
||||
if protectingKeymanager, supported := v.keyManager.(km.ProtectingKeyManager); supported {
|
||||
bodyRoot, err := stateutil.BlockBodyRoot(b.Body)
|
||||
if err != nil {
|
||||
|
||||
@@ -14,12 +14,15 @@ import (
|
||||
ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1"
|
||||
"github.com/prysmaticlabs/go-ssz"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core/helpers"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/shared/bls"
|
||||
"github.com/prysmaticlabs/prysm/shared/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/shared/featureconfig"
|
||||
"github.com/prysmaticlabs/prysm/shared/grpcutils"
|
||||
"github.com/prysmaticlabs/prysm/shared/params"
|
||||
"github.com/prysmaticlabs/prysm/validator/db/kv"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/plugin/ocgrpc"
|
||||
@@ -42,9 +45,11 @@ type ValidatorService struct {
|
||||
withCert string
|
||||
dataDir string
|
||||
keyManager keymanager.KeyManager
|
||||
keyManagerV2 v2.IKeymanager
|
||||
logValidatorBalances bool
|
||||
emitAccountMetrics bool
|
||||
maxCallRecvMsgSize int
|
||||
validatingPubKeys [][48]byte
|
||||
grpcRetries uint
|
||||
grpcHeaders []string
|
||||
protector slashingprotection.Protector
|
||||
@@ -56,7 +61,9 @@ type Config struct {
|
||||
DataDir string
|
||||
CertFlag string
|
||||
GraffitiFlag string
|
||||
ValidatingPubKeys [][48]byte
|
||||
KeyManager keymanager.KeyManager
|
||||
KeyManagerV2 v2.IKeymanager
|
||||
LogValidatorBalances bool
|
||||
EmitAccountMetrics bool
|
||||
GrpcMaxCallRecvMsgSizeFlag int
|
||||
@@ -77,6 +84,8 @@ func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, e
|
||||
dataDir: cfg.DataDir,
|
||||
graffiti: []byte(cfg.GraffitiFlag),
|
||||
keyManager: cfg.KeyManager,
|
||||
keyManagerV2: cfg.KeyManagerV2,
|
||||
validatingPubKeys: cfg.ValidatingPubKeys,
|
||||
logValidatorBalances: cfg.LogValidatorBalances,
|
||||
emitAccountMetrics: cfg.EmitAccountMetrics,
|
||||
maxCallRecvMsgSize: cfg.GrpcMaxCallRecvMsgSizeFlag,
|
||||
@@ -113,13 +122,7 @@ func (v *ValidatorService) Start() {
|
||||
log.Info("Established secure gRPC connection")
|
||||
}
|
||||
|
||||
pubkeys, err := v.keyManager.FetchValidatingKeys()
|
||||
if err != nil {
|
||||
log.Errorf("Could not get validating keys: %v", err)
|
||||
return
|
||||
}
|
||||
|
||||
valDB, err := kv.NewKVStore(v.dataDir, pubkeys)
|
||||
valDB, err := kv.NewKVStore(v.dataDir, v.validatingPubKeys)
|
||||
if err != nil {
|
||||
log.Errorf("Could not initialize db: %v", err)
|
||||
return
|
||||
@@ -147,6 +150,7 @@ func (v *ValidatorService) Start() {
|
||||
beaconClient: ethpb.NewBeaconChainClient(v.conn),
|
||||
node: ethpb.NewNodeClient(v.conn),
|
||||
keyManager: v.keyManager,
|
||||
keyManagerV2: v.keyManagerV2,
|
||||
graffiti: v.graffiti,
|
||||
logValidatorBalances: v.logValidatorBalances,
|
||||
emitAccountMetrics: v.emitAccountMetrics,
|
||||
@@ -182,7 +186,22 @@ func (v *ValidatorService) Status() error {
|
||||
}
|
||||
|
||||
// signObject signs a generic object, with protection if available.
|
||||
func (v *validator) signObject(pubKey [48]byte, object interface{}, domain []byte) (bls.Signature, error) {
|
||||
func (v *validator) signObject(
|
||||
ctx context.Context,
|
||||
pubKey [48]byte,
|
||||
object interface{},
|
||||
domain []byte,
|
||||
) (bls.Signature, error) {
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
root, err := helpers.ComputeSigningRoot(object, domain)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return v.keyManagerV2.Sign(ctx, &validatorpb.SignRequest{
|
||||
PublicKey: pubKey[:],
|
||||
Data: root[:],
|
||||
})
|
||||
}
|
||||
if protectingKeymanager, supported := v.keyManager.(keymanager.ProtectingKeyManager); supported {
|
||||
root, err := ssz.HashTreeRoot(object)
|
||||
if err != nil {
|
||||
|
||||
@@ -28,6 +28,7 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/slotutil"
|
||||
vdb "github.com/prysmaticlabs/prysm/validator/db"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v2keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
@@ -52,6 +53,7 @@ type validator struct {
|
||||
graffiti []byte
|
||||
node ethpb.NodeClient
|
||||
keyManager keymanager.KeyManager
|
||||
keyManagerV2 v2keymanager.IKeymanager
|
||||
startBalances map[[48]byte]uint64
|
||||
prevBalance map[[48]byte]uint64
|
||||
voteStats voteStats
|
||||
@@ -180,7 +182,14 @@ func (v *validator) WaitForSynced(ctx context.Context) error {
|
||||
func (v *validator) WaitForActivation(ctx context.Context) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.WaitForActivation")
|
||||
defer span.End()
|
||||
validatingKeys, err := v.keyManager.FetchValidatingKeys()
|
||||
|
||||
var validatingKeys [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
} else {
|
||||
validatingKeys, err = v.keyManager.FetchValidatingKeys()
|
||||
}
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch validating keys")
|
||||
}
|
||||
@@ -314,7 +323,13 @@ func (v *validator) UpdateDuties(ctx context.Context, slot uint64) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.UpdateAssignments")
|
||||
defer span.End()
|
||||
|
||||
validatingKeys, err := v.keyManager.FetchValidatingKeys()
|
||||
var validatingKeys [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
validatingKeys, err = v.keyManagerV2.FetchValidatingPublicKeys(ctx)
|
||||
} else {
|
||||
validatingKeys, err = v.keyManager.FetchValidatingKeys()
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ func NewKeystore(input string) (KeyManager, string, error) {
|
||||
if opts.Path == "" {
|
||||
opts.Path = v1.DefaultValidatorDir()
|
||||
}
|
||||
log.WithField("keystorePath", opts.Path).Info("Checking validator keys")
|
||||
log.WithField("keystorePath", opts.Path).Debug("Checking validator keys")
|
||||
|
||||
exists, err := v1.Exists(opts.Path, true /* assertNonEmpty */)
|
||||
if err != nil {
|
||||
|
||||
@@ -46,3 +46,17 @@ func (k Kind) String() string {
|
||||
return fmt.Sprintf("%d", int(k))
|
||||
}
|
||||
}
|
||||
|
||||
// ParseKind from a raw string, returning a keymanager kind.
|
||||
func ParseKind(k string) (Kind, error) {
|
||||
switch k {
|
||||
case "direct":
|
||||
return Direct, nil
|
||||
case "derived":
|
||||
return Derived, nil
|
||||
case "remote":
|
||||
return Remote, nil
|
||||
default:
|
||||
return 0, fmt.Errorf("%s is not an allowed keymanager", k)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,6 +70,8 @@ var appFlags = []cli.Flag{
|
||||
flags.MonitoringPortFlag,
|
||||
flags.SlasherRPCProviderFlag,
|
||||
flags.SlasherCertFlag,
|
||||
flags.WalletPasswordsDirFlag,
|
||||
flags.WalletDirFlag,
|
||||
cmd.MinimalConfigFlag,
|
||||
cmd.E2EConfigFlag,
|
||||
cmd.VerbosityFlag,
|
||||
@@ -174,7 +176,10 @@ contract in order to activate the validator client`,
|
||||
var err error
|
||||
var pubKeys [][]byte
|
||||
if cliCtx.String(flags.KeyManager.Name) != "" {
|
||||
pubKeysBytes48, success := node.ExtractPublicKeysFromKeyManager(cliCtx)
|
||||
pubKeysBytes48, success := node.ExtractPublicKeysFromKeymanager(
|
||||
cliCtx,
|
||||
nil, /* nil v2 keymanager */
|
||||
)
|
||||
pubKeys, err = bytesutil.FromBytes48Array(pubKeysBytes48), success
|
||||
} else {
|
||||
keystorePath, passphrase, err := v1.HandleEmptyKeystoreFlags(cliCtx, false /*confirmPassword*/)
|
||||
|
||||
@@ -27,10 +27,12 @@ go_library(
|
||||
"//shared/prometheus:go_default_library",
|
||||
"//shared/tracing:go_default_library",
|
||||
"//shared/version:go_default_library",
|
||||
"//validator/accounts/v2:go_default_library",
|
||||
"//validator/client:go_default_library",
|
||||
"//validator/db/kv:go_default_library",
|
||||
"//validator/flags:go_default_library",
|
||||
"//validator/keymanager/v1:go_default_library",
|
||||
"//validator/keymanager/v2:go_default_library",
|
||||
"//validator/slashing-protection:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
||||
@@ -9,14 +9,12 @@ import (
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/signal"
|
||||
"path"
|
||||
"strings"
|
||||
"sync"
|
||||
"syscall"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/shared"
|
||||
"github.com/prysmaticlabs/prysm/shared/cmd"
|
||||
"github.com/prysmaticlabs/prysm/shared/debug"
|
||||
@@ -25,18 +23,21 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/shared/prometheus"
|
||||
"github.com/prysmaticlabs/prysm/shared/tracing"
|
||||
"github.com/prysmaticlabs/prysm/shared/version"
|
||||
accountsv2 "github.com/prysmaticlabs/prysm/validator/accounts/v2"
|
||||
"github.com/prysmaticlabs/prysm/validator/client"
|
||||
"github.com/prysmaticlabs/prysm/validator/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/validator/flags"
|
||||
keymanager "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v1 "github.com/prysmaticlabs/prysm/validator/keymanager/v1"
|
||||
v2 "github.com/prysmaticlabs/prysm/validator/keymanager/v2"
|
||||
slashing_protection "github.com/prysmaticlabs/prysm/validator/slashing-protection"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
var log = logrus.WithField("prefix", "node")
|
||||
|
||||
// ValidatorClient defines an instance of a sharding validator that manages
|
||||
// the entire lifecycle of services attached to it participating in
|
||||
// Ethereum Serenity.
|
||||
// ValidatorClient defines an instance of an eth2 validator that manages
|
||||
// the entire lifecycle of services attached to it participating in eth2.
|
||||
type ValidatorClient struct {
|
||||
cliCtx *cli.Context
|
||||
services *shared.ServiceRegistry // Lifecycle and service store.
|
||||
@@ -44,7 +45,7 @@ type ValidatorClient struct {
|
||||
stop chan struct{} // Channel to wait for termination notifications.
|
||||
}
|
||||
|
||||
// NewValidatorClient creates a new, Ethereum Serenity validator client.
|
||||
// NewValidatorClient creates a new, Prysm validator client.
|
||||
func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) {
|
||||
if err := tracing.Setup(
|
||||
"validator", // service name
|
||||
@@ -77,23 +78,48 @@ func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) {
|
||||
|
||||
cmd.ConfigureValidator(cliCtx)
|
||||
featureconfig.ConfigureValidator(cliCtx)
|
||||
|
||||
keyManager, err := selectKeyManager(cliCtx)
|
||||
keyManagerV1, err := selectV1Keymanager(cliCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
pubKeys, err := keyManager.FetchValidatingKeys()
|
||||
var keyManagerV2 v2.IKeymanager
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
walletDir := cliCtx.String(flags.WalletDirFlag.Name)
|
||||
if walletDir == flags.DefaultValidatorDir() {
|
||||
walletDir = path.Join(walletDir, accountsv2.WalletDefaultDirName)
|
||||
}
|
||||
passwordsDir := cliCtx.String(flags.WalletPasswordsDirFlag.Name)
|
||||
if passwordsDir == flags.DefaultValidatorDir() {
|
||||
passwordsDir = path.Join(passwordsDir, accountsv2.PasswordsDefaultDirName)
|
||||
}
|
||||
// Read the wallet from the specified path.
|
||||
wallet, err := accountsv2.OpenWallet(context.Background(), &accountsv2.WalletConfig{
|
||||
PasswordsDir: passwordsDir,
|
||||
WalletDir: walletDir,
|
||||
})
|
||||
if err == accountsv2.ErrNoWalletFound {
|
||||
log.Fatal("No wallet found at path, please create a new wallet using `validator accounts-v2 new`")
|
||||
}
|
||||
if err != nil {
|
||||
log.Fatalf("Could not open wallet: %v", err)
|
||||
}
|
||||
keyManagerV2, err = wallet.ExistingKeyManager(context.Background())
|
||||
if err != nil {
|
||||
log.Fatalf("Could not read existing keymanager for wallet: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
pubKeys, err := ExtractPublicKeysFromKeymanager(cliCtx, keyManagerV2)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to obtain public keys for validation")
|
||||
return nil, err
|
||||
}
|
||||
if len(pubKeys) == 0 {
|
||||
log.Warn("No keys found; nothing to validate")
|
||||
} else {
|
||||
if len(pubKeys) == 0 {
|
||||
log.Warn("No keys found; nothing to validate")
|
||||
} else {
|
||||
log.WithField("validators", len(pubKeys)).Debug("Found validator keys")
|
||||
for _, key := range pubKeys {
|
||||
log.WithField("pubKey", fmt.Sprintf("%#x", key)).Info("Validating for public key")
|
||||
}
|
||||
log.WithField("validators", len(pubKeys)).Debug("Found validator keys")
|
||||
for _, key := range pubKeys {
|
||||
log.WithField("pubKey", fmt.Sprintf("%#x", key)).Info("Validating for public key")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,10 +127,6 @@ func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) {
|
||||
forceClearFlag := cliCtx.Bool(cmd.ForceClearDB.Name)
|
||||
dataDir := cliCtx.String(cmd.DataDirFlag.Name)
|
||||
if clearFlag || forceClearFlag {
|
||||
pubkeys, err := keyManager.FetchValidatingKeys()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if dataDir == "" {
|
||||
dataDir = cmd.DefaultDataDir()
|
||||
if dataDir == "" {
|
||||
@@ -115,7 +137,7 @@ func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) {
|
||||
}
|
||||
|
||||
}
|
||||
if err := clearDB(dataDir, pubkeys, forceClearFlag); err != nil {
|
||||
if err := clearDB(dataDir, pubKeys, forceClearFlag); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
@@ -129,7 +151,7 @@ func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if err := ValidatorClient.registerClientService(keyManager); err != nil {
|
||||
if err := ValidatorClient.registerClientService(keyManagerV1, keyManagerV2, pubKeys); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -176,7 +198,7 @@ func (s *ValidatorClient) Close() {
|
||||
defer s.lock.Unlock()
|
||||
|
||||
s.services.StopAll()
|
||||
log.Info("Stopping sharding validator")
|
||||
log.Info("Stopping Prysm validator")
|
||||
|
||||
close(s.stop)
|
||||
}
|
||||
@@ -190,7 +212,11 @@ func (s *ValidatorClient) registerPrometheusService() error {
|
||||
return s.services.RegisterService(service)
|
||||
}
|
||||
|
||||
func (s *ValidatorClient) registerClientService(keyManager keymanager.KeyManager) error {
|
||||
func (s *ValidatorClient) registerClientService(
|
||||
keyManager v1.KeyManager,
|
||||
keyManagerV2 v2.IKeymanager,
|
||||
validatingPubKeys [][48]byte,
|
||||
) error {
|
||||
endpoint := s.cliCtx.String(flags.BeaconRPCProviderFlag.Name)
|
||||
dataDir := s.cliCtx.String(cmd.DataDirFlag.Name)
|
||||
logValidatorBalances := !s.cliCtx.Bool(flags.DisablePenaltyRewardLogFlag.Name)
|
||||
@@ -208,10 +234,12 @@ func (s *ValidatorClient) registerClientService(keyManager keymanager.KeyManager
|
||||
Endpoint: endpoint,
|
||||
DataDir: dataDir,
|
||||
KeyManager: keyManager,
|
||||
KeyManagerV2: keyManagerV2,
|
||||
LogValidatorBalances: logValidatorBalances,
|
||||
EmitAccountMetrics: emitAccountMetrics,
|
||||
CertFlag: cert,
|
||||
GraffitiFlag: graffiti,
|
||||
ValidatingPubKeys: validatingPubKeys,
|
||||
GrpcMaxCallRecvMsgSizeFlag: maxCallRecvMsgSize,
|
||||
GrpcRetriesFlag: grpcRetries,
|
||||
GrpcHeadersFlag: s.cliCtx.String(flags.GrpcHeadersFlag.Name),
|
||||
@@ -245,8 +273,8 @@ func (s *ValidatorClient) registerSlasherClientService() error {
|
||||
return s.services.RegisterService(sp)
|
||||
}
|
||||
|
||||
// selectKeyManager selects the key manager depending on the options provided by the user.
|
||||
func selectKeyManager(ctx *cli.Context) (keymanager.KeyManager, error) {
|
||||
// Selects the key manager depending on the options provided by the user.
|
||||
func selectV1Keymanager(ctx *cli.Context) (v1.KeyManager, error) {
|
||||
manager := strings.ToLower(ctx.String(flags.KeyManager.Name))
|
||||
opts := ctx.String(flags.KeyManagerOpts.Name)
|
||||
if opts == "" {
|
||||
@@ -286,20 +314,20 @@ func selectKeyManager(ctx *cli.Context) (keymanager.KeyManager, error) {
|
||||
}
|
||||
}
|
||||
|
||||
var km keymanager.KeyManager
|
||||
var km v1.KeyManager
|
||||
var help string
|
||||
var err error
|
||||
switch manager {
|
||||
case "interop":
|
||||
km, help, err = keymanager.NewInterop(opts)
|
||||
km, help, err = v1.NewInterop(opts)
|
||||
case "unencrypted":
|
||||
km, help, err = keymanager.NewUnencrypted(opts)
|
||||
km, help, err = v1.NewUnencrypted(opts)
|
||||
case "keystore":
|
||||
km, help, err = keymanager.NewKeystore(opts)
|
||||
km, help, err = v1.NewKeystore(opts)
|
||||
case "wallet":
|
||||
km, help, err = keymanager.NewWallet(opts)
|
||||
km, help, err = v1.NewWallet(opts)
|
||||
case "remote":
|
||||
km, help, err = keymanager.NewRemoteWallet(opts)
|
||||
km, help, err = v1.NewRemoteWallet(opts)
|
||||
default:
|
||||
return nil, fmt.Errorf("unknown keymanager %q", manager)
|
||||
}
|
||||
@@ -342,9 +370,18 @@ func clearDB(dataDir string, pubkeys [][48]byte, force bool) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExtractPublicKeysFromKeyManager extracts only the public keys from the specified key manager.
|
||||
func ExtractPublicKeysFromKeyManager(ctx *cli.Context) ([][48]byte, error) {
|
||||
km, err := selectKeyManager(ctx)
|
||||
// ExtractPublicKeysFromKeymanager extracts only the public keys from the specified key manager.
|
||||
func ExtractPublicKeysFromKeymanager(cliCtx *cli.Context, keyManagerV2 v2.IKeymanager) ([][48]byte, error) {
|
||||
var pubKeys [][48]byte
|
||||
var err error
|
||||
if featureconfig.Get().EnableAccountsV2 {
|
||||
pubKeys, err = keyManagerV2.FetchValidatingPublicKeys(context.Background())
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain public keys for validation")
|
||||
}
|
||||
return pubKeys, nil
|
||||
}
|
||||
km, err := selectV1Keymanager(cliCtx)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -94,6 +94,8 @@ var appHelpFlagGroups = []flagGroup{
|
||||
flags.SourceDirectory,
|
||||
flags.TargetDirectory,
|
||||
flags.DisableAccountMetricsFlag,
|
||||
flags.WalletDirFlag,
|
||||
flags.WalletPasswordsDirFlag,
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user