mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Prysm V4: Remove Prysm Remote Signer (#11895)
* removing all prysm remote signer code * fixing unit tests * resolving more build issues * resolving deepsource complaint * fixing lint * trying to fix bazel library * trying testonly true * removing assert and require from non test settings * fixing bazel and tests * removing more unused files related to remote signer * fixing linting * reverting some changes * reverting a change that broke some code * removing typo * fixing unit test * fixing mnemonic information
This commit is contained in:
parent
525d3b05a6
commit
753e285fb6
@ -252,18 +252,7 @@ var (
|
||||
Name: "keys-dir",
|
||||
Usage: "Path to a directory where keystores to be imported are stored",
|
||||
}
|
||||
// GrpcRemoteAddressFlag defines the host:port address for a remote keymanager to connect to.
|
||||
GrpcRemoteAddressFlag = &cli.StringFlag{
|
||||
Name: "grpc-remote-address",
|
||||
Usage: "Host:port of a gRPC server for a remote keymanager",
|
||||
Value: "",
|
||||
}
|
||||
// DisableRemoteSignerTlsFlag disables TLS when connecting to a remote signer.
|
||||
DisableRemoteSignerTlsFlag = &cli.BoolFlag{
|
||||
Name: "disable-remote-signer-tls",
|
||||
Usage: "Disables TLS when connecting to a remote signer. (WARNING! This will result in insecure requests!)",
|
||||
Value: false,
|
||||
}
|
||||
|
||||
// RemoteSignerCertPathFlag defines the path to a client.crt file for a wallet to connect to
|
||||
// a secure signer via TLS and gRPC.
|
||||
RemoteSignerCertPathFlag = &cli.StringFlag{
|
||||
|
@ -4,7 +4,6 @@ go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"create.go",
|
||||
"edit.go",
|
||||
"recover.go",
|
||||
"wallet.go",
|
||||
],
|
||||
@ -20,7 +19,6 @@ go_library(
|
||||
"//validator/accounts/userprompt:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"@com_github_manifoldco_promptui//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
@ -32,9 +30,9 @@ go_library(
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
testonly = True,
|
||||
srcs = [
|
||||
"create_test.go",
|
||||
"edit_test.go",
|
||||
"recover_test.go",
|
||||
],
|
||||
embed = [":go_default_library"],
|
||||
@ -50,7 +48,6 @@ go_test(
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote: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",
|
||||
|
@ -117,13 +117,6 @@ func ConstructCLIManagerOpts(cliCtx *cli.Context, keymanagerKind keymanager.Kind
|
||||
cliOpts = append(cliOpts, accounts.WithMnemonic25thWord(mnemonicPassphrase))
|
||||
}
|
||||
}
|
||||
if keymanagerKind == keymanager.Remote {
|
||||
opts, err := userprompt.InputRemoteKeymanagerConfig(cliCtx)
|
||||
if err != nil {
|
||||
return []accounts.Option{}, errors.Wrap(err, "could not input remote keymanager config")
|
||||
}
|
||||
cliOpts = append(cliOpts, accounts.WithKeymanagerOpts(opts))
|
||||
}
|
||||
if keymanagerKind == keymanager.Web3Signer {
|
||||
return []accounts.Option{}, errors.New("web3signer keymanager does not require persistent wallets.")
|
||||
}
|
||||
@ -139,7 +132,6 @@ func inputKeymanagerKind(cliCtx *cli.Context) (keymanager.Kind, error) {
|
||||
Items: []string{
|
||||
wallet.KeymanagerKindSelections[keymanager.Local],
|
||||
wallet.KeymanagerKindSelections[keymanager.Derived],
|
||||
wallet.KeymanagerKindSelections[keymanager.Remote],
|
||||
wallet.KeymanagerKindSelections[keymanager.Web3Signer],
|
||||
},
|
||||
}
|
||||
|
@ -1,26 +1,108 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
cmdacc "github.com/prysmaticlabs/prysm/v3/cmd/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/local"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"github.com/sirupsen/logrus"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
passwordFileName = "password.txt"
|
||||
password = "OhWOWthisisatest42!$"
|
||||
)
|
||||
|
||||
// `cmd/validator/accounts/delete_test.go`. https://pastebin.com/2n2VB7Ez is
|
||||
// the error I couldn't get around.
|
||||
func setupWalletAndPasswordsDir(t testing.TB) (string, string, string) {
|
||||
walletDir := filepath.Join(t.TempDir(), "wallet")
|
||||
passwordsDir := filepath.Join(t.TempDir(), "passwords")
|
||||
passwordFileDir := filepath.Join(t.TempDir(), "passwordFile")
|
||||
require.NoError(t, os.MkdirAll(passwordFileDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
|
||||
passwordFilePath := filepath.Join(passwordFileDir, passwordFileName)
|
||||
require.NoError(t, os.WriteFile(passwordFilePath, []byte(password), os.ModePerm))
|
||||
return walletDir, passwordsDir, passwordFilePath
|
||||
}
|
||||
|
||||
type testWalletConfig struct {
|
||||
exitAll bool
|
||||
skipDepositConfirm bool
|
||||
keymanagerKind keymanager.Kind
|
||||
numAccounts int64
|
||||
grpcHeaders string
|
||||
privateKeyFile string
|
||||
accountPasswordFile string
|
||||
walletPasswordFile string
|
||||
backupPasswordFile string
|
||||
backupPublicKeys string
|
||||
voluntaryExitPublicKeys string
|
||||
deletePublicKeys string
|
||||
keysDir string
|
||||
backupDir string
|
||||
walletDir string
|
||||
passwordsDir string
|
||||
}
|
||||
|
||||
func setupWalletCtx(
|
||||
tb testing.TB,
|
||||
cfg *testWalletConfig,
|
||||
) *cli.Context {
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.WalletDirFlag.Name, cfg.walletDir, "")
|
||||
set.String(flags.KeysDirFlag.Name, cfg.keysDir, "")
|
||||
set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "")
|
||||
set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "")
|
||||
set.String(flags.VoluntaryExitPublicKeysFlag.Name, cfg.voluntaryExitPublicKeys, "")
|
||||
set.String(flags.BackupDirFlag.Name, cfg.backupDir, "")
|
||||
set.String(flags.BackupPasswordFile.Name, cfg.backupPasswordFile, "")
|
||||
set.String(flags.BackupPublicKeysFlag.Name, cfg.backupPublicKeys, "")
|
||||
set.String(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile, "")
|
||||
set.String(flags.AccountPasswordFileFlag.Name, cfg.accountPasswordFile, "")
|
||||
set.Int64(flags.NumAccountsFlag.Name, cfg.numAccounts, "")
|
||||
set.Bool(flags.SkipDepositConfirmationFlag.Name, cfg.skipDepositConfirm, "")
|
||||
set.Bool(flags.SkipMnemonic25thWordCheckFlag.Name, true, "")
|
||||
set.Bool(flags.ExitAllFlag.Name, cfg.exitAll, "")
|
||||
set.String(flags.GrpcHeadersFlag.Name, cfg.grpcHeaders, "")
|
||||
|
||||
if cfg.privateKeyFile != "" {
|
||||
set.String(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile, "")
|
||||
assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile))
|
||||
}
|
||||
assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir))
|
||||
assert.NoError(tb, set.Set(flags.SkipMnemonic25thWordCheckFlag.Name, "true"))
|
||||
assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir))
|
||||
assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String()))
|
||||
assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys))
|
||||
assert.NoError(tb, set.Set(flags.VoluntaryExitPublicKeysFlag.Name, cfg.voluntaryExitPublicKeys))
|
||||
assert.NoError(tb, set.Set(flags.BackupDirFlag.Name, cfg.backupDir))
|
||||
assert.NoError(tb, set.Set(flags.BackupPublicKeysFlag.Name, cfg.backupPublicKeys))
|
||||
assert.NoError(tb, set.Set(flags.BackupPasswordFile.Name, cfg.backupPasswordFile))
|
||||
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.NumAccountsFlag.Name, strconv.Itoa(int(cfg.numAccounts))))
|
||||
assert.NoError(tb, set.Set(flags.SkipDepositConfirmationFlag.Name, strconv.FormatBool(cfg.skipDepositConfirm)))
|
||||
assert.NoError(tb, set.Set(flags.ExitAllFlag.Name, strconv.FormatBool(cfg.exitAll)))
|
||||
assert.NoError(tb, set.Set(flags.GrpcHeadersFlag.Name, cfg.grpcHeaders))
|
||||
return cli.NewContext(&app, set, nil)
|
||||
}
|
||||
|
||||
func init() {
|
||||
logrus.SetLevel(logrus.DebugLevel)
|
||||
logrus.SetOutput(io.Discard)
|
||||
@ -137,57 +219,6 @@ func TestCreateWallet_WalletAlreadyExists(t *testing.T) {
|
||||
require.ErrorContains(t, "already exists", err)
|
||||
}
|
||||
|
||||
func TestCreateWallet_Remote(t *testing.T) {
|
||||
walletDir, _, walletPasswordFile := setupWalletAndPasswordsDir(t)
|
||||
wantCfg := &remote.KeymanagerOpts{
|
||||
RemoteCertificate: &remote.CertificateConfig{
|
||||
RequireTls: true,
|
||||
ClientCertPath: "/tmp/client.crt",
|
||||
ClientKeyPath: "/tmp/client.key",
|
||||
CACertPath: "/tmp/ca.crt",
|
||||
},
|
||||
RemoteAddr: "host.example.com:4000",
|
||||
}
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
keymanagerKind := "remote"
|
||||
set.String(flags.WalletDirFlag.Name, walletDir, "")
|
||||
set.String(flags.WalletPasswordFileFlag.Name, walletDir, "")
|
||||
set.String(flags.KeymanagerKindFlag.Name, keymanagerKind, "")
|
||||
set.String(flags.GrpcRemoteAddressFlag.Name, wantCfg.RemoteAddr, "")
|
||||
set.String(flags.RemoteSignerCertPathFlag.Name, wantCfg.RemoteCertificate.ClientCertPath, "")
|
||||
set.String(flags.RemoteSignerKeyPathFlag.Name, wantCfg.RemoteCertificate.ClientKeyPath, "")
|
||||
set.String(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath, "")
|
||||
assert.NoError(t, set.Set(flags.WalletDirFlag.Name, walletDir))
|
||||
assert.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, walletPasswordFile))
|
||||
assert.NoError(t, set.Set(flags.KeymanagerKindFlag.Name, keymanagerKind))
|
||||
assert.NoError(t, set.Set(flags.GrpcRemoteAddressFlag.Name, wantCfg.RemoteAddr))
|
||||
assert.NoError(t, set.Set(flags.RemoteSignerCertPathFlag.Name, wantCfg.RemoteCertificate.ClientCertPath))
|
||||
assert.NoError(t, set.Set(flags.RemoteSignerKeyPathFlag.Name, wantCfg.RemoteCertificate.ClientKeyPath))
|
||||
assert.NoError(t, set.Set(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath))
|
||||
cliCtx := cli.NewContext(&app, set, nil)
|
||||
|
||||
// We attempt to create the wallet.
|
||||
_, err := CreateAndSaveWalletCli(cliCtx)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We attempt to open the newly created wallet.
|
||||
ctx := context.Background()
|
||||
w, err := wallet.OpenWallet(cliCtx.Context, &wallet.Config{
|
||||
WalletDir: walletDir,
|
||||
})
|
||||
assert.NoError(t, err)
|
||||
|
||||
// We read the keymanager config for the newly created wallet.
|
||||
encoded, err := w.ReadKeymanagerConfigFromDisk(ctx)
|
||||
assert.NoError(t, err)
|
||||
cfg, err := remote.UnmarshalOptionsFile(encoded)
|
||||
assert.NoError(t, err)
|
||||
|
||||
// We assert the created configuration was as desired.
|
||||
assert.DeepEqual(t, wantCfg, cfg)
|
||||
}
|
||||
|
||||
func TestInputKeymanagerKind(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
@ -219,18 +250,6 @@ func TestInputKeymanagerKind(t *testing.T) {
|
||||
want: keymanager.Derived,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "remote returns remote kind",
|
||||
args: "remote",
|
||||
want: keymanager.Remote,
|
||||
wantErr: false,
|
||||
},
|
||||
{
|
||||
name: "REMOTE (capitalized) returns remote kind",
|
||||
args: "REMOTE",
|
||||
want: keymanager.Remote,
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
@ -1,54 +0,0 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/userprompt"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
func remoteWalletEdit(c *cli.Context) error {
|
||||
w, err := wallet.OpenWalletOrElseCli(c, func(cliCtx *cli.Context) (*wallet.Wallet, error) {
|
||||
return nil, wallet.ErrNoWalletFound
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not open wallet")
|
||||
}
|
||||
if w.KeymanagerKind() != keymanager.Remote {
|
||||
return errors.New(
|
||||
fmt.Sprintf("Keymanager type: %s doesn't support configuration editing",
|
||||
w.KeymanagerKind().String()))
|
||||
}
|
||||
|
||||
enc, err := w.ReadKeymanagerConfigFromDisk(c.Context)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not read config")
|
||||
}
|
||||
fileOpts, err := remote.UnmarshalOptionsFile(enc)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not unmarshal config")
|
||||
}
|
||||
log.Info("Current configuration")
|
||||
// Prints the current configuration to stdout.
|
||||
fmt.Println(fileOpts)
|
||||
newCfg, err := userprompt.InputRemoteKeymanagerConfig(c)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get keymanager config")
|
||||
}
|
||||
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWallet(w),
|
||||
accounts.WithKeymanagerOpts(newCfg),
|
||||
}
|
||||
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return acc.WalletEdit(c.Context)
|
||||
}
|
@ -1,164 +0,0 @@
|
||||
package wallet
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
const (
|
||||
passwordFileName = "password.txt"
|
||||
password = "OhWOWthisisatest42!$"
|
||||
)
|
||||
|
||||
// TODO(mikeneuder): Figure out how to shared these functions with
|
||||
// `cmd/validator/accounts/delete_test.go`. https://pastebin.com/2n2VB7Ez is
|
||||
// the error I couldn't get around.
|
||||
func setupWalletAndPasswordsDir(t testing.TB) (string, string, string) {
|
||||
walletDir := filepath.Join(t.TempDir(), "wallet")
|
||||
passwordsDir := filepath.Join(t.TempDir(), "passwords")
|
||||
passwordFileDir := filepath.Join(t.TempDir(), "passwordFile")
|
||||
require.NoError(t, os.MkdirAll(passwordFileDir, params.BeaconIoConfig().ReadWriteExecutePermissions))
|
||||
passwordFilePath := filepath.Join(passwordFileDir, passwordFileName)
|
||||
require.NoError(t, os.WriteFile(passwordFilePath, []byte(password), os.ModePerm))
|
||||
return walletDir, passwordsDir, passwordFilePath
|
||||
}
|
||||
|
||||
type testWalletConfig struct {
|
||||
exitAll bool
|
||||
skipDepositConfirm bool
|
||||
keymanagerKind keymanager.Kind
|
||||
numAccounts int64
|
||||
grpcHeaders string
|
||||
privateKeyFile string
|
||||
accountPasswordFile string
|
||||
walletPasswordFile string
|
||||
backupPasswordFile string
|
||||
backupPublicKeys string
|
||||
voluntaryExitPublicKeys string
|
||||
deletePublicKeys string
|
||||
keysDir string
|
||||
backupDir string
|
||||
walletDir string
|
||||
passwordsDir string
|
||||
mnemonicLanguage string
|
||||
}
|
||||
|
||||
func setupWalletCtx(
|
||||
tb testing.TB,
|
||||
cfg *testWalletConfig,
|
||||
) *cli.Context {
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.WalletDirFlag.Name, cfg.walletDir, "")
|
||||
set.String(flags.KeysDirFlag.Name, cfg.keysDir, "")
|
||||
set.String(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String(), "")
|
||||
set.String(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys, "")
|
||||
set.String(flags.VoluntaryExitPublicKeysFlag.Name, cfg.voluntaryExitPublicKeys, "")
|
||||
set.String(flags.BackupDirFlag.Name, cfg.backupDir, "")
|
||||
set.String(flags.BackupPasswordFile.Name, cfg.backupPasswordFile, "")
|
||||
set.String(flags.BackupPublicKeysFlag.Name, cfg.backupPublicKeys, "")
|
||||
set.String(flags.WalletPasswordFileFlag.Name, cfg.walletPasswordFile, "")
|
||||
set.String(flags.AccountPasswordFileFlag.Name, cfg.accountPasswordFile, "")
|
||||
set.Int64(flags.NumAccountsFlag.Name, cfg.numAccounts, "")
|
||||
set.Bool(flags.SkipDepositConfirmationFlag.Name, cfg.skipDepositConfirm, "")
|
||||
set.Bool(flags.SkipMnemonic25thWordCheckFlag.Name, true, "")
|
||||
set.Bool(flags.ExitAllFlag.Name, cfg.exitAll, "")
|
||||
set.String(flags.GrpcHeadersFlag.Name, cfg.grpcHeaders, "")
|
||||
|
||||
if cfg.privateKeyFile != "" {
|
||||
set.String(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile, "")
|
||||
assert.NoError(tb, set.Set(flags.ImportPrivateKeyFileFlag.Name, cfg.privateKeyFile))
|
||||
}
|
||||
assert.NoError(tb, set.Set(flags.WalletDirFlag.Name, cfg.walletDir))
|
||||
assert.NoError(tb, set.Set(flags.SkipMnemonic25thWordCheckFlag.Name, "true"))
|
||||
assert.NoError(tb, set.Set(flags.KeysDirFlag.Name, cfg.keysDir))
|
||||
assert.NoError(tb, set.Set(flags.KeymanagerKindFlag.Name, cfg.keymanagerKind.String()))
|
||||
assert.NoError(tb, set.Set(flags.DeletePublicKeysFlag.Name, cfg.deletePublicKeys))
|
||||
assert.NoError(tb, set.Set(flags.VoluntaryExitPublicKeysFlag.Name, cfg.voluntaryExitPublicKeys))
|
||||
assert.NoError(tb, set.Set(flags.BackupDirFlag.Name, cfg.backupDir))
|
||||
assert.NoError(tb, set.Set(flags.BackupPublicKeysFlag.Name, cfg.backupPublicKeys))
|
||||
assert.NoError(tb, set.Set(flags.BackupPasswordFile.Name, cfg.backupPasswordFile))
|
||||
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.NumAccountsFlag.Name, strconv.Itoa(int(cfg.numAccounts))))
|
||||
assert.NoError(tb, set.Set(flags.SkipDepositConfirmationFlag.Name, strconv.FormatBool(cfg.skipDepositConfirm)))
|
||||
assert.NoError(tb, set.Set(flags.ExitAllFlag.Name, strconv.FormatBool(cfg.exitAll)))
|
||||
assert.NoError(tb, set.Set(flags.GrpcHeadersFlag.Name, cfg.grpcHeaders))
|
||||
return cli.NewContext(&app, set, nil)
|
||||
}
|
||||
|
||||
func TestEditWalletConfiguration(t *testing.T) {
|
||||
walletDir, _, passwordFile := setupWalletAndPasswordsDir(t)
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
keymanagerKind: keymanager.Remote,
|
||||
})
|
||||
opts := []accounts.Option{
|
||||
accounts.WithWalletDir(walletDir),
|
||||
accounts.WithKeymanagerType(keymanager.Remote),
|
||||
accounts.WithWalletPassword("Passwordz0320$"),
|
||||
}
|
||||
acc, err := accounts.NewCLIManager(opts...)
|
||||
require.NoError(t, err)
|
||||
w, err := acc.WalletCreate(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
originalCfg := &remote.KeymanagerOpts{
|
||||
RemoteCertificate: &remote.CertificateConfig{
|
||||
RequireTls: true,
|
||||
ClientCertPath: "/tmp/a.crt",
|
||||
ClientKeyPath: "/tmp/b.key",
|
||||
CACertPath: "/tmp/c.crt",
|
||||
},
|
||||
RemoteAddr: "my.server.com:4000",
|
||||
}
|
||||
encodedCfg, err := remote.MarshalOptionsFile(cliCtx.Context, originalCfg)
|
||||
assert.NoError(t, err)
|
||||
assert.NoError(t, w.WriteKeymanagerConfigToDisk(cliCtx.Context, encodedCfg))
|
||||
|
||||
wantCfg := &remote.KeymanagerOpts{
|
||||
RemoteCertificate: &remote.CertificateConfig{
|
||||
RequireTls: true,
|
||||
ClientCertPath: "/tmp/client.crt",
|
||||
ClientKeyPath: "/tmp/client.key",
|
||||
CACertPath: "/tmp/ca.crt",
|
||||
},
|
||||
RemoteAddr: "host.example.com:4000",
|
||||
}
|
||||
app := cli.App{}
|
||||
set := flag.NewFlagSet("test", 0)
|
||||
set.String(flags.WalletDirFlag.Name, walletDir, "")
|
||||
set.String(flags.WalletPasswordFileFlag.Name, passwordFile, "")
|
||||
set.String(flags.GrpcRemoteAddressFlag.Name, wantCfg.RemoteAddr, "")
|
||||
set.String(flags.RemoteSignerCertPathFlag.Name, wantCfg.RemoteCertificate.ClientCertPath, "")
|
||||
set.String(flags.RemoteSignerKeyPathFlag.Name, wantCfg.RemoteCertificate.ClientKeyPath, "")
|
||||
set.String(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath, "")
|
||||
assert.NoError(t, set.Set(flags.WalletDirFlag.Name, walletDir))
|
||||
assert.NoError(t, set.Set(flags.WalletPasswordFileFlag.Name, passwordFile))
|
||||
assert.NoError(t, set.Set(flags.GrpcRemoteAddressFlag.Name, wantCfg.RemoteAddr))
|
||||
assert.NoError(t, set.Set(flags.RemoteSignerCertPathFlag.Name, wantCfg.RemoteCertificate.ClientCertPath))
|
||||
assert.NoError(t, set.Set(flags.RemoteSignerKeyPathFlag.Name, wantCfg.RemoteCertificate.ClientKeyPath))
|
||||
assert.NoError(t, set.Set(flags.RemoteSignerCACertPathFlag.Name, wantCfg.RemoteCertificate.CACertPath))
|
||||
cliCtx = cli.NewContext(&app, set, nil)
|
||||
|
||||
err = remoteWalletEdit(cliCtx)
|
||||
require.NoError(t, err)
|
||||
encoded, err := w.ReadKeymanagerConfigFromDisk(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg, err := remote.UnmarshalOptionsFile(encoded)
|
||||
assert.NoError(t, err)
|
||||
assert.DeepEqual(t, wantCfg, cfg)
|
||||
}
|
@ -24,8 +24,6 @@ var Commands = &cli.Command{
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.WalletDirFlag,
|
||||
flags.KeymanagerKindFlag,
|
||||
flags.GrpcRemoteAddressFlag,
|
||||
flags.DisableRemoteSignerTlsFlag,
|
||||
flags.RemoteSignerCertPathFlag,
|
||||
flags.RemoteSignerKeyPathFlag,
|
||||
flags.RemoteSignerCACertPathFlag,
|
||||
@ -53,38 +51,6 @@ var Commands = &cli.Command{
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "edit-config",
|
||||
Usage: "edits a wallet configuration options, such as gRPC connection credentials and TLS certificates",
|
||||
Flags: cmd.WrapFlags([]cli.Flag{
|
||||
flags.WalletDirFlag,
|
||||
flags.WalletPasswordFileFlag,
|
||||
flags.GrpcRemoteAddressFlag,
|
||||
flags.DisableRemoteSignerTlsFlag,
|
||||
flags.RemoteSignerCertPathFlag,
|
||||
flags.RemoteSignerKeyPathFlag,
|
||||
flags.RemoteSignerCACertPathFlag,
|
||||
features.Mainnet,
|
||||
features.PraterTestnet,
|
||||
features.SepoliaTestnet,
|
||||
cmd.AcceptTosFlag,
|
||||
}),
|
||||
Before: func(cliCtx *cli.Context) error {
|
||||
if err := cmd.LoadFlagsFromConfig(cliCtx, cliCtx.Command.Flags); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := tos.VerifyTosAcceptedOrPrompt(cliCtx); err != nil {
|
||||
return err
|
||||
}
|
||||
return features.ConfigureValidator(cliCtx)
|
||||
},
|
||||
Action: func(cliCtx *cli.Context) error {
|
||||
if err := remoteWalletEdit(cliCtx); err != nil {
|
||||
log.WithError(err).Fatal("Could not edit wallet configuration")
|
||||
}
|
||||
return nil
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "recover",
|
||||
Usage: "uses a derived wallet seed recovery phase to recreate an existing HD wallet",
|
||||
|
@ -15,7 +15,6 @@ go_library(
|
||||
"doc.go",
|
||||
"log.go",
|
||||
"wallet_create.go",
|
||||
"wallet_edit.go",
|
||||
"wallet_recover.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/validator/accounts",
|
||||
@ -47,7 +46,6 @@ go_library(
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
"@com_github_google_uuid//:go_default_library",
|
||||
"@com_github_logrusorgru_aurora//:go_default_library",
|
||||
@ -73,7 +71,6 @@ go_test(
|
||||
data = glob(["testdata/**"]),
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//async/event:go_default_library",
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
@ -82,17 +79,13 @@ go_test(
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/eth/service:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/mock:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//validator/accounts/iface:go_default_library",
|
||||
"//validator/accounts/petnames:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"//validator/testing:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
"@com_github_google_uuid//:go_default_library",
|
||||
|
@ -1,7 +1,6 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
@ -14,25 +13,17 @@ import (
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/google/uuid"
|
||||
"github.com/prysmaticlabs/prysm/v3/async/event"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/v3/proto/eth/service"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/mock"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/petnames"
|
||||
"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"
|
||||
constant "github.com/prysmaticlabs/prysm/v3/validator/testing"
|
||||
"github.com/urfave/cli/v2"
|
||||
keystorev4 "github.com/wealdtech/go-eth2-wallet-encryptor-keystorev4"
|
||||
@ -116,37 +107,6 @@ func setupWalletAndPasswordsDir(t testing.TB) (string, string, string) {
|
||||
return walletDir, passwordsDir, passwordFilePath
|
||||
}
|
||||
|
||||
type mockRemoteKeymanager struct {
|
||||
publicKeys [][fieldparams.BLSPubkeyLength]byte
|
||||
opts *remote.KeymanagerOpts
|
||||
}
|
||||
|
||||
func (m *mockRemoteKeymanager) FetchValidatingPublicKeys(_ context.Context) ([][fieldparams.BLSPubkeyLength]byte, error) {
|
||||
return m.publicKeys, nil
|
||||
}
|
||||
|
||||
func (*mockRemoteKeymanager) Sign(context.Context, *validatorpb.SignRequest) (bls.Signature, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (*mockRemoteKeymanager) SubscribeAccountChanges(_ chan [][fieldparams.BLSPubkeyLength]byte) event.Subscription {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*mockRemoteKeymanager) ExtractKeystores(
|
||||
_ context.Context, _ []bls.PublicKey, _ string,
|
||||
) ([]*keymanager.Keystore, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (km *mockRemoteKeymanager) ListKeymanagerAccounts(ctx context.Context, cfg keymanager.ListKeymanagerAccountConfig) error {
|
||||
return remote.ListKeymanagerAccountsImpl(ctx, cfg, km, km.opts)
|
||||
}
|
||||
|
||||
func (*mockRemoteKeymanager) DeleteKeystores(context.Context, [][]byte) ([]*ethpbservice.DeletedKeystoreStatus, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func createRandomKeystore(t testing.TB, password string) *keymanager.Keystore {
|
||||
encryptor := keystorev4.New()
|
||||
id, err := uuid.NewRandom()
|
||||
@ -319,6 +279,44 @@ func TestListAccounts_LocalKeymanager(t *testing.T) {
|
||||
keyFound := strings.Contains(lines[lineNumber], keyString)
|
||||
assert.Equal(t, true, keyFound, "Private Key %s not found on line number %d", keyString, lineNumber)
|
||||
}
|
||||
|
||||
rescueStdout = os.Stdout
|
||||
r, writer, err = os.Pipe()
|
||||
require.NoError(t, err)
|
||||
os.Stdout = writer
|
||||
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
m := mock.NewMockValidatorClient(ctrl)
|
||||
var pks [][]byte
|
||||
for i := range pubKeys {
|
||||
pks = append(pks, pubKeys[i][:])
|
||||
}
|
||||
req := ðpb.MultipleValidatorStatusRequest{PublicKeys: pks}
|
||||
resp := ðpb.MultipleValidatorStatusResponse{Indices: []types.ValidatorIndex{1, math.MaxUint64, 2}}
|
||||
|
||||
m.
|
||||
EXPECT().
|
||||
MultipleValidatorStatus(gomock.Any(), gomock.Eq(req)).
|
||||
Return(resp, nil)
|
||||
|
||||
require.NoError(
|
||||
t,
|
||||
listValidatorIndices(
|
||||
cliCtx.Context,
|
||||
km,
|
||||
m,
|
||||
),
|
||||
)
|
||||
require.NoError(t, writer.Close())
|
||||
out, err = io.ReadAll(r)
|
||||
require.NoError(t, err)
|
||||
os.Stdout = rescueStdout
|
||||
|
||||
expectedStdout := au.BrightGreen("Validator indices:").Bold().String() +
|
||||
fmt.Sprintf("\n%#x: %d", pubKeys[0][0:4], 1) +
|
||||
fmt.Sprintf("\n%#x: %d\n", pubKeys[2][0:4], 2)
|
||||
require.Equal(t, expectedStdout, string(out))
|
||||
}
|
||||
|
||||
func TestListAccounts_DerivedKeymanager(t *testing.T) {
|
||||
@ -462,176 +460,3 @@ func TestListAccounts_DerivedKeymanager(t *testing.T) {
|
||||
assert.Equal(t, true, keyFound, "Validating Private Key %s not found on line number %d", keyString, lineNumber)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAccounts_RemoteKeymanager(t *testing.T) {
|
||||
walletDir, _, _ := setupWalletAndPasswordsDir(t)
|
||||
cliCtx := setupWalletCtx(t, &testWalletConfig{
|
||||
walletDir: walletDir,
|
||||
keymanagerKind: keymanager.Remote,
|
||||
})
|
||||
opts := []Option{
|
||||
WithWalletDir(walletDir),
|
||||
WithKeymanagerType(keymanager.Remote),
|
||||
WithWalletPassword(password),
|
||||
}
|
||||
acc, err := NewCLIManager(opts...)
|
||||
require.NoError(t, err)
|
||||
w, err := acc.WalletCreate(cliCtx.Context)
|
||||
require.NoError(t, err)
|
||||
|
||||
rescueStdout := os.Stdout
|
||||
r, writer, err := os.Pipe()
|
||||
require.NoError(t, err)
|
||||
os.Stdout = writer
|
||||
|
||||
numAccounts := 3
|
||||
pubKeys := make([][fieldparams.BLSPubkeyLength]byte, numAccounts)
|
||||
for i := 0; i < numAccounts; i++ {
|
||||
key := make([]byte, 48)
|
||||
copy(key, strconv.Itoa(i))
|
||||
pubKeys[i] = bytesutil.ToBytes48(key)
|
||||
}
|
||||
km := &mockRemoteKeymanager{
|
||||
publicKeys: pubKeys,
|
||||
opts: &remote.KeymanagerOpts{
|
||||
RemoteCertificate: &remote.CertificateConfig{
|
||||
RequireTls: true,
|
||||
ClientCertPath: "/tmp/client.crt",
|
||||
ClientKeyPath: "/tmp/client.key",
|
||||
CACertPath: "/tmp/ca.crt",
|
||||
},
|
||||
RemoteAddr: "localhost:4000",
|
||||
},
|
||||
}
|
||||
// We call the list remote keymanager accounts function.
|
||||
require.NoError(t,
|
||||
km.ListKeymanagerAccounts(context.Background(),
|
||||
keymanager.ListKeymanagerAccountConfig{
|
||||
KeymanagerConfigFileName: wallet.KeymanagerConfigFileName,
|
||||
}))
|
||||
|
||||
require.NoError(t, writer.Close())
|
||||
out, err := io.ReadAll(r)
|
||||
require.NoError(t, err)
|
||||
os.Stdout = rescueStdout
|
||||
|
||||
// Get stdout content and split to lines
|
||||
newLine := fmt.Sprintln()
|
||||
lines := strings.Split(string(out), newLine)
|
||||
|
||||
// Expected output example:
|
||||
/*
|
||||
(keymanager kind) remote signer
|
||||
(configuration file path) /tmp/79336/wallet/remote/keymanageropts.json
|
||||
|
||||
Configuration options
|
||||
Remote gRPC address: localhost:4000
|
||||
Require TLS: true
|
||||
Client cert path: /tmp/client.crt
|
||||
Client key path: /tmp/client.key
|
||||
CA cert path: /tmp/ca.crt
|
||||
|
||||
Showing 3 validator accounts
|
||||
|
||||
equally-primary-foal
|
||||
[validating public key] 0x300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
|
||||
rationally-charmed-werewolf
|
||||
[validating public key] 0x310000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// Expected output format definition
|
||||
const prologLength = 11
|
||||
const configOffset = 4
|
||||
const configLength = 5
|
||||
const accountLength = 4
|
||||
const nameOffset = 1
|
||||
const keyOffset = 2
|
||||
const epilogLength = 1
|
||||
|
||||
// Require the output has correct number of lines
|
||||
lineCount := prologLength + accountLength*numAccounts + epilogLength
|
||||
require.Equal(t, lineCount, len(lines))
|
||||
|
||||
// Assert the keymanager kind is printed on the first line.
|
||||
kindString := w.KeymanagerKind().String()
|
||||
kindFound := strings.Contains(lines[0], kindString)
|
||||
assert.Equal(t, true, kindFound, "Keymanager Kind %s not found on the first line", kindString)
|
||||
|
||||
// Assert that Configuration is printed in the right position
|
||||
configLines := lines[configOffset:(configOffset + configLength)]
|
||||
configExpected := km.opts.String()
|
||||
configActual := fmt.Sprintln(strings.Join(configLines, newLine))
|
||||
assert.Equal(t, configExpected, configActual, "Configuration not found at the expected position")
|
||||
|
||||
// Assert that account names are printed on the correct lines
|
||||
for i := 0; i < numAccounts; i++ {
|
||||
lineNumber := prologLength + accountLength*i + nameOffset
|
||||
accountName := petnames.DeterministicName(pubKeys[i][:], "-")
|
||||
accountNameFound := strings.Contains(lines[lineNumber], accountName)
|
||||
assert.Equal(t, true, accountNameFound, "Account Name %s not found on line number %d", accountName, lineNumber)
|
||||
}
|
||||
|
||||
// Assert that public keys are printed on the correct lines
|
||||
for i, key := range pubKeys {
|
||||
lineNumber := prologLength + accountLength*i + keyOffset
|
||||
keyString := fmt.Sprintf("%#x", key)
|
||||
keyFound := strings.Contains(lines[lineNumber], keyString)
|
||||
assert.Equal(t, true, keyFound, "Public Key %s not found on line number %d", keyString, lineNumber)
|
||||
}
|
||||
}
|
||||
|
||||
func TestListAccounts_ListValidatorIndices(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
numAccounts := 3
|
||||
pubKeys := make([][fieldparams.BLSPubkeyLength]byte, numAccounts)
|
||||
pks := make([][]byte, numAccounts)
|
||||
|
||||
for i := 0; i < numAccounts; i++ {
|
||||
key := make([]byte, 48)
|
||||
copy(key, strconv.Itoa(i))
|
||||
pubKeys[i] = bytesutil.ToBytes48(key)
|
||||
pks[i] = key
|
||||
}
|
||||
|
||||
km := &mockRemoteKeymanager{
|
||||
publicKeys: pubKeys,
|
||||
}
|
||||
|
||||
rescueStdout := os.Stdout
|
||||
r, writer, err := os.Pipe()
|
||||
require.NoError(t, err)
|
||||
os.Stdout = writer
|
||||
|
||||
m := mock.NewMockValidatorClient(ctrl)
|
||||
|
||||
req := ðpb.MultipleValidatorStatusRequest{PublicKeys: pks}
|
||||
resp := ðpb.MultipleValidatorStatusResponse{Indices: []primitives.ValidatorIndex{1, math.MaxUint64, 2}}
|
||||
|
||||
m.
|
||||
EXPECT().
|
||||
MultipleValidatorStatus(gomock.Eq(context.Background()), gomock.Eq(req)).
|
||||
Return(resp, nil)
|
||||
|
||||
require.NoError(
|
||||
t,
|
||||
listValidatorIndices(
|
||||
context.Background(),
|
||||
km,
|
||||
m,
|
||||
),
|
||||
)
|
||||
|
||||
require.NoError(t, writer.Close())
|
||||
out, err := io.ReadAll(r)
|
||||
require.NoError(t, err)
|
||||
os.Stdout = rescueStdout
|
||||
|
||||
expectedStdout := au.BrightGreen("Validator indices:").Bold().String() + "\n0x30000000: 1\n0x32000000: 2\n"
|
||||
require.Equal(t, expectedStdout, string(out))
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ import (
|
||||
validatorHelpers "github.com/prysmaticlabs/prysm/v3/validator/helpers"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/derived"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@ -37,7 +36,6 @@ type AccountsCLIManager struct {
|
||||
wallet *wallet.Wallet
|
||||
keymanager keymanager.IKeymanager
|
||||
keymanagerKind keymanager.Kind
|
||||
keymanagerOpts *remote.KeymanagerOpts
|
||||
showDepositData bool
|
||||
showPrivateKeys bool
|
||||
listValidatorIndices bool
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/wallet"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"google.golang.org/grpc"
|
||||
)
|
||||
|
||||
@ -37,14 +36,6 @@ func WithKeymanagerType(k keymanager.Kind) Option {
|
||||
}
|
||||
}
|
||||
|
||||
// WithKeymanagerOpts provides a keymanager configuration to the accounts cli manager.
|
||||
func WithKeymanagerOpts(kmo *remote.KeymanagerOpts) Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
acc.keymanagerOpts = kmo
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
// WithShowDepositData enables displaying deposit data in the accounts cli manager.
|
||||
func WithShowDepositData() Option {
|
||||
return func(acc *AccountsCLIManager) error {
|
||||
|
@ -15,7 +15,6 @@ go_library(
|
||||
"//cmd/validator/flags:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"//io/prompt:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"@com_github_logrusorgru_aurora//:go_default_library",
|
||||
"@com_github_manifoldco_promptui//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
@ -1,17 +1,12 @@
|
||||
package userprompt
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/manifoldco/promptui"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
"github.com/prysmaticlabs/prysm/v3/io/file"
|
||||
"github.com/prysmaticlabs/prysm/v3/io/prompt"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"github.com/urfave/cli/v2"
|
||||
)
|
||||
|
||||
@ -62,98 +57,6 @@ func InputDirectory(cliCtx *cli.Context, promptText string, flag *cli.StringFlag
|
||||
return file.ExpandPath(inputtedDir)
|
||||
}
|
||||
|
||||
// InputRemoteKeymanagerConfig via the cli.
|
||||
func InputRemoteKeymanagerConfig(cliCtx *cli.Context) (*remote.KeymanagerOpts, error) {
|
||||
addr := cliCtx.String(flags.GrpcRemoteAddressFlag.Name)
|
||||
requireTls := !cliCtx.Bool(flags.DisableRemoteSignerTlsFlag.Name)
|
||||
crt := cliCtx.String(flags.RemoteSignerCertPathFlag.Name)
|
||||
key := cliCtx.String(flags.RemoteSignerKeyPathFlag.Name)
|
||||
ca := cliCtx.String(flags.RemoteSignerCACertPathFlag.Name)
|
||||
log.Info("Input desired configuration")
|
||||
var err error
|
||||
if addr == "" {
|
||||
addr, err = prompt.ValidatePrompt(
|
||||
os.Stdin,
|
||||
"Remote gRPC address (such as host.example.com:4000)",
|
||||
prompt.NotEmpty)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if requireTls && crt == "" {
|
||||
crt, err = prompt.ValidatePrompt(
|
||||
os.Stdin,
|
||||
"Path to TLS crt (such as /path/to/client.crt)",
|
||||
validateCertPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if requireTls && key == "" {
|
||||
key, err = prompt.ValidatePrompt(
|
||||
os.Stdin,
|
||||
"Path to TLS key (such as /path/to/client.key)",
|
||||
validateCertPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if requireTls && ca == "" {
|
||||
ca, err = prompt.ValidatePrompt(
|
||||
os.Stdin,
|
||||
"Path to certificate authority (CA) crt (such as /path/to/ca.crt)",
|
||||
validateCertPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
crtPath, keyPath, caPath := "", "", ""
|
||||
if crt != "" {
|
||||
crtPath, err = file.ExpandPath(strings.TrimRight(crt, "\r\n"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not determine absolute path for %s", crt)
|
||||
}
|
||||
}
|
||||
if key != "" {
|
||||
keyPath, err = file.ExpandPath(strings.TrimRight(key, "\r\n"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not determine absolute path for %s", crt)
|
||||
}
|
||||
}
|
||||
if ca != "" {
|
||||
caPath, err = file.ExpandPath(strings.TrimRight(ca, "\r\n"))
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "could not determine absolute path for %s", crt)
|
||||
}
|
||||
}
|
||||
|
||||
newCfg := &remote.KeymanagerOpts{
|
||||
RemoteCertificate: &remote.CertificateConfig{
|
||||
RequireTls: requireTls,
|
||||
ClientCertPath: crtPath,
|
||||
ClientKeyPath: keyPath,
|
||||
CACertPath: caPath,
|
||||
},
|
||||
RemoteAddr: addr,
|
||||
}
|
||||
fmt.Printf("%s\n", newCfg)
|
||||
return newCfg, nil
|
||||
}
|
||||
|
||||
func validateCertPath(input string) error {
|
||||
if input == "" {
|
||||
return errors.New("crt path cannot be empty")
|
||||
}
|
||||
if !prompt.IsValidUnicode(input) {
|
||||
return errors.New("not valid unicode")
|
||||
}
|
||||
if !file.FileExists(input) {
|
||||
return fmt.Errorf("no crt found at path: %s", input)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// FormatPromptError for the user.
|
||||
func FormatPromptError(err error) error {
|
||||
switch err {
|
||||
|
@ -22,7 +22,6 @@ go_library(
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
|
@ -18,7 +18,6 @@ import (
|
||||
"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"
|
||||
remoteweb3signer "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-web3signer"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -55,7 +54,6 @@ var (
|
||||
KeymanagerKindSelections = map[keymanager.Kind]string{
|
||||
keymanager.Local: "Imported Wallet (Recommended)",
|
||||
keymanager.Derived: "HD Wallet",
|
||||
keymanager.Remote: "Remote Signing Wallet (Advanced)",
|
||||
keymanager.Web3Signer: "Consensys Web3Signer (Advanced)",
|
||||
}
|
||||
// ValidateExistingPass checks that an input cannot be empty.
|
||||
@ -145,7 +143,7 @@ func IsValid(walletDir string) (bool, error) {
|
||||
// Count how many wallet types we have in the directory
|
||||
numWalletTypes := 0
|
||||
for _, name := range names {
|
||||
// Nil error means input name is `derived`, `remote` or `imported`
|
||||
// Nil error means input name is `derived` or `imported`
|
||||
_, err = keymanager.ParseKind(name)
|
||||
if err == nil {
|
||||
numWalletTypes++
|
||||
@ -287,22 +285,6 @@ func (w *Wallet) InitializeKeymanager(ctx context.Context, cfg iface.InitKeymana
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialize derived keymanager")
|
||||
}
|
||||
case keymanager.Remote:
|
||||
configFile, err := w.ReadKeymanagerConfigFromDisk(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read keymanager config")
|
||||
}
|
||||
opts, err := remote.UnmarshalOptionsFile(configFile)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not unmarshal keymanager config file")
|
||||
}
|
||||
km, err = remote.NewKeymanager(ctx, &remote.SetupConfig{
|
||||
Opts: opts,
|
||||
MaxMessageSize: 100000000,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not initialize remote keymanager")
|
||||
}
|
||||
case keymanager.Web3Signer:
|
||||
config := cfg.Web3SignerConfig
|
||||
if config == nil {
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"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.
|
||||
@ -64,13 +63,6 @@ func (acm *AccountsCLIManager) WalletCreate(ctx context.Context) (*wallet.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:
|
||||
@ -119,17 +111,3 @@ func createDerivedKeymanagerWallet(
|
||||
}
|
||||
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
|
||||
}
|
||||
|
@ -1,21 +0,0 @@
|
||||
package accounts
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
)
|
||||
|
||||
// WalletEdit changes a user's on-disk wallet configuration: remote gRPC
|
||||
// credentials for remote signing, derivation paths for HD wallets, etc.
|
||||
func (acm *AccountsCLIManager) WalletEdit(ctx context.Context) error {
|
||||
encodedCfg, err := remote.MarshalOptionsFile(ctx, acm.keymanagerOpts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not marshal config file")
|
||||
}
|
||||
if err := acm.wallet.WriteKeymanagerConfigToDisk(ctx, encodedCfg); err != nil {
|
||||
return errors.Wrap(err, "could not write config to disk")
|
||||
}
|
||||
return nil
|
||||
}
|
@ -62,7 +62,6 @@ go_library(
|
||||
"//validator/helpers:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
@ -140,7 +139,6 @@ go_test(
|
||||
"//testing/util:go_default_library",
|
||||
"//time:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"//time/slots/testing:go_default_library",
|
||||
"//validator/accounts/testing:go_default_library",
|
||||
"//validator/accounts/wallet:go_default_library",
|
||||
"//validator/client/iface:go_default_library",
|
||||
@ -151,7 +149,6 @@ go_test(
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer:go_default_library",
|
||||
"//validator/keymanager/remote/mock:go_default_library",
|
||||
"//validator/slashing-protection-history:go_default_library",
|
||||
"//validator/testing:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common:go_default_library",
|
||||
|
@ -10,12 +10,10 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/cmd/validator/flags"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/iface"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
@ -103,7 +101,6 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
}
|
||||
case slot := <-v.NextSlot():
|
||||
span.AddAttributes(trace.Int64Attribute("slot", int64(slot))) // lint:ignore uintcast -- This conversion is OK for tracing.
|
||||
reloadRemoteKeys(ctx, km)
|
||||
allExited, err := v.AllValidatorsAreExited(ctx)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Could not check if validators are exited")
|
||||
@ -155,21 +152,11 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
}
|
||||
}
|
||||
|
||||
func reloadRemoteKeys(ctx context.Context, km keymanager.IKeymanager) {
|
||||
remoteKm, ok := km.(remote.RemoteKeymanager)
|
||||
if ok {
|
||||
_, err := remoteKm.ReloadPublicKeys(ctx)
|
||||
if err != nil {
|
||||
log.WithError(err).Error(msgCouldNotFetchKeys)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func initializeValidatorAndGetHeadSlot(ctx context.Context, v iface.Validator) (primitives.Slot, error) {
|
||||
func initializeValidatorAndGetHeadSlot(ctx context.Context, v iface.Validator) (types.Slot, error) {
|
||||
ticker := time.NewTicker(backOffPeriod)
|
||||
defer ticker.Stop()
|
||||
|
||||
var headSlot primitives.Slot
|
||||
var headSlot types.Slot
|
||||
firstTime := true
|
||||
for {
|
||||
if !firstTime {
|
||||
@ -231,7 +218,7 @@ func initializeValidatorAndGetHeadSlot(ctx context.Context, v iface.Validator) (
|
||||
return headSlot, nil
|
||||
}
|
||||
|
||||
func performRoles(slotCtx context.Context, allRoles map[[48]byte][]iface.ValidatorRole, v iface.Validator, slot primitives.Slot, wg *sync.WaitGroup, span *trace.Span) {
|
||||
func performRoles(slotCtx context.Context, allRoles map[[48]byte][]iface.ValidatorRole, v iface.Validator, slot types.Slot, wg *sync.WaitGroup, span *trace.Span) {
|
||||
for pubKey, roles := range allRoles {
|
||||
wg.Add(len(roles))
|
||||
for _, role := range roles {
|
||||
@ -281,7 +268,7 @@ func isConnectionError(err error) bool {
|
||||
return err != nil && errors.Is(err, iface.ErrConnectionIssue)
|
||||
}
|
||||
|
||||
func handleAssignmentError(err error, slot primitives.Slot) {
|
||||
func handleAssignmentError(err error, slot types.Slot) {
|
||||
if errCode, ok := status.FromError(err); ok && errCode.Code() == codes.NotFound {
|
||||
log.WithField(
|
||||
"epoch", slot/params.BeaconConfig().SlotsPerEpoch,
|
||||
|
@ -11,12 +11,11 @@ import (
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
validatorserviceconfig "github.com/prysmaticlabs/prysm/v3/config/validator/service"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/iface"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/testutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote/mock"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
@ -69,8 +68,8 @@ func TestUpdateDuties_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- slot
|
||||
@ -89,8 +88,8 @@ func TestUpdateDuties_HandlesError(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- slot
|
||||
@ -108,8 +107,8 @@ func TestRoleAt_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- slot
|
||||
@ -127,8 +126,8 @@ func TestAttests_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
v.RolesAtRet = []iface.ValidatorRole{iface.RoleAttester}
|
||||
go func() {
|
||||
@ -147,8 +146,8 @@ func TestProposes_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
v.RolesAtRet = []iface.ValidatorRole{iface.RoleProposer}
|
||||
go func() {
|
||||
@ -167,8 +166,8 @@ func TestBothProposesAndAttests_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
v.RolesAtRet = []iface.ValidatorRole{iface.RoleAttester, iface.RoleProposer}
|
||||
go func() {
|
||||
@ -190,8 +189,8 @@ func TestAllValidatorsAreExited_NextSlot(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.WithValue(context.Background(), testutil.AllValidatorsAreExitedCtxKey, true))
|
||||
hook := logTest.NewGlobal()
|
||||
|
||||
slot := primitives.Slot(55)
|
||||
ticker := make(chan primitives.Slot)
|
||||
slot := types.Slot(55)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- slot
|
||||
@ -232,23 +231,6 @@ func TestKeyReload_NoActiveKey(t *testing.T) {
|
||||
assert.Equal(t, 2, v.WaitForActivationCalled)
|
||||
}
|
||||
|
||||
func TestKeyReload_RemoteKeymanager(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
km := mock.NewMock()
|
||||
v := &testutil.FakeValidator{Km: &km}
|
||||
|
||||
ticker := make(chan primitives.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- primitives.Slot(55)
|
||||
|
||||
cancel()
|
||||
}()
|
||||
run(ctx, v)
|
||||
assert.Equal(t, true, km.ReloadPublicKeysCalled)
|
||||
}
|
||||
|
||||
func TestUpdateProposerSettingsAt_EpochStart(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Km: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
v.SetProposerSettings(&validatorserviceconfig.ProposerSettings{
|
||||
@ -261,7 +243,7 @@ func TestUpdateProposerSettingsAt_EpochStart(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
hook := logTest.NewGlobal()
|
||||
slot := params.BeaconConfig().SlotsPerEpoch
|
||||
ticker := make(chan primitives.Slot)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- slot
|
||||
@ -289,7 +271,7 @@ func TestUpdateProposerSettings_ContinuesAfterValidatorRegistrationFails(t *test
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
hook := logTest.NewGlobal()
|
||||
slot := params.BeaconConfig().SlotsPerEpoch
|
||||
ticker := make(chan primitives.Slot)
|
||||
ticker := make(chan types.Slot)
|
||||
v.NextSlotRet = ticker
|
||||
go func() {
|
||||
ticker <- slot
|
||||
|
@ -13,7 +13,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/monitoring/tracing"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote"
|
||||
"go.opencensus.io/trace"
|
||||
)
|
||||
|
||||
@ -38,17 +37,17 @@ func (v *validator) WaitForActivation(ctx context.Context, accountsChangedChan c
|
||||
}()
|
||||
}
|
||||
|
||||
return v.waitForActivation(ctx, accountsChangedChan)
|
||||
return v.internalWaitForActivation(ctx, accountsChangedChan)
|
||||
}
|
||||
|
||||
// waitForActivation performs the following:
|
||||
// internalWaitForActivation performs the following:
|
||||
// 1) While the key manager is empty, poll the key manager until some validator keys exist.
|
||||
// 2) Open a server side stream for activation events against the given keys.
|
||||
// 3) In another go routine, the key manager is monitored for updates and emits an update event on
|
||||
// the accountsChangedChan. When an event signal is received, restart the waitForActivation routine.
|
||||
// the accountsChangedChan. When an event signal is received, restart the internalWaitForActivation routine.
|
||||
// 4) If the stream is reset in error, restart the routine.
|
||||
// 5) If the stream returns a response indicating one or more validators are active, exit the routine.
|
||||
func (v *validator) waitForActivation(ctx context.Context, accountsChangedChan <-chan [][fieldparams.BLSPubkeyLength]byte) error {
|
||||
func (v *validator) internalWaitForActivation(ctx context.Context, accountsChangedChan <-chan [][fieldparams.BLSPubkeyLength]byte) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.WaitForActivation")
|
||||
defer span.End()
|
||||
|
||||
@ -91,80 +90,23 @@ func (v *validator) waitForActivation(ctx context.Context, accountsChangedChan <
|
||||
Error("Stream broken while waiting for activation. Reconnecting...")
|
||||
// Reconnection attempt backoff, up to 60s.
|
||||
time.Sleep(time.Second * time.Duration(math.Min(uint64(attempts), 60)))
|
||||
return v.waitForActivation(incrementRetries(ctx), accountsChangedChan)
|
||||
return v.internalWaitForActivation(incrementRetries(ctx), accountsChangedChan)
|
||||
}
|
||||
|
||||
remoteKm, ok := v.keyManager.(remote.RemoteKeymanager)
|
||||
if ok {
|
||||
if err = v.handleWithRemoteKeyManager(ctx, accountsChangedChan, &remoteKm); err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
if err = v.handleWithoutRemoteKeyManager(ctx, accountsChangedChan, &stream, span); err != nil {
|
||||
return err
|
||||
}
|
||||
if err = v.handleAccountsChanged(ctx, accountsChangedChan, &stream, span); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
v.ticker = slots.NewSlotTicker(time.Unix(int64(v.genesisTime), 0), params.BeaconConfig().SecondsPerSlot)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) handleWithRemoteKeyManager(ctx context.Context, accountsChangedChan <-chan [][fieldparams.BLSPubkeyLength]byte, remoteKm *remote.RemoteKeymanager) error {
|
||||
func (v *validator) handleAccountsChanged(ctx context.Context, accountsChangedChan <-chan [][fieldparams.BLSPubkeyLength]byte, stream *ethpb.BeaconNodeValidator_WaitForActivationClient, span *trace.Span) error {
|
||||
for {
|
||||
select {
|
||||
case <-accountsChangedChan:
|
||||
// Accounts (keys) changed, restart the process.
|
||||
return v.waitForActivation(ctx, accountsChangedChan)
|
||||
case <-v.NextSlot():
|
||||
if ctx.Err() == context.Canceled {
|
||||
return errors.Wrap(ctx.Err(), "context canceled, not waiting for activation anymore")
|
||||
}
|
||||
validatingKeys, err := (*remoteKm).ReloadPublicKeys(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, msgCouldNotFetchKeys)
|
||||
}
|
||||
statusRequestKeys := make([][]byte, len(validatingKeys))
|
||||
for i := range validatingKeys {
|
||||
statusRequestKeys[i] = validatingKeys[i][:]
|
||||
}
|
||||
resp, err := v.validatorClient.MultipleValidatorStatus(ctx, ðpb.MultipleValidatorStatusRequest{
|
||||
PublicKeys: statusRequestKeys,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
statuses := make([]*validatorStatus, len(resp.Statuses))
|
||||
for i, s := range resp.Statuses {
|
||||
statuses[i] = &validatorStatus{
|
||||
publicKey: resp.PublicKeys[i],
|
||||
status: s,
|
||||
index: resp.Indices[i],
|
||||
}
|
||||
}
|
||||
|
||||
vals, err := v.beaconClient.ListValidators(ctx, ðpb.ListValidatorsRequest{Active: true, PageSize: 0})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not get active validator count")
|
||||
}
|
||||
|
||||
valActivated := v.checkAndLogValidatorStatus(statuses, uint64(vals.TotalSize))
|
||||
if valActivated {
|
||||
logActiveValidatorStatus(statuses)
|
||||
} else {
|
||||
continue
|
||||
}
|
||||
}
|
||||
break
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) handleWithoutRemoteKeyManager(ctx context.Context, accountsChangedChan <-chan [][fieldparams.BLSPubkeyLength]byte, stream *ethpb.BeaconNodeValidator_WaitForActivationClient, span *trace.Span) error {
|
||||
for {
|
||||
select {
|
||||
case <-accountsChangedChan:
|
||||
// Accounts (keys) changed, restart the process.
|
||||
return v.waitForActivation(ctx, accountsChangedChan)
|
||||
return v.internalWaitForActivation(ctx, accountsChangedChan)
|
||||
default:
|
||||
res, err := (*stream).Recv()
|
||||
// If the stream is closed, we stop the loop.
|
||||
@ -182,7 +124,7 @@ func (v *validator) handleWithoutRemoteKeyManager(ctx context.Context, accountsC
|
||||
Error("Stream broken while waiting for activation. Reconnecting...")
|
||||
// Reconnection attempt backoff, up to 60s.
|
||||
time.Sleep(time.Second * time.Duration(math.Min(uint64(attempts), 60)))
|
||||
return v.waitForActivation(incrementRetries(ctx), accountsChangedChan)
|
||||
return v.internalWaitForActivation(incrementRetries(ctx), accountsChangedChan)
|
||||
}
|
||||
|
||||
statuses := make([]*validatorStatus, len(res.Statuses))
|
||||
|
@ -9,18 +9,13 @@ import (
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/pkg/errors"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/mock"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
slotutilmock "github.com/prysmaticlabs/prysm/v3/time/slots/testing"
|
||||
walletMock "github.com/prysmaticlabs/prysm/v3/validator/accounts/testing"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/client/testutil"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/derived"
|
||||
remotekeymanagermock "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote/mock"
|
||||
constant "github.com/prysmaticlabs/prysm/v3/validator/testing"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
"github.com/tyler-smith/go-bip39"
|
||||
@ -248,7 +243,7 @@ func TestWaitForActivation_RefetchKeys(t *testing.T) {
|
||||
clientStream.EXPECT().Recv().Return(
|
||||
resp,
|
||||
nil)
|
||||
assert.NoError(t, v.waitForActivation(context.Background(), make(chan [][fieldparams.BLSPubkeyLength]byte)), "Could not wait for activation")
|
||||
assert.NoError(t, v.internalWaitForActivation(context.Background(), make(chan [][fieldparams.BLSPubkeyLength]byte)), "Could not wait for activation")
|
||||
assert.LogsContain(t, hook, msgNoKeysFetched)
|
||||
assert.LogsContain(t, hook, "Validator activated")
|
||||
}
|
||||
@ -395,131 +390,7 @@ func TestWaitForActivation_AccountsChanged(t *testing.T) {
|
||||
channel <- [][fieldparams.BLSPubkeyLength]byte{}
|
||||
}()
|
||||
|
||||
assert.NoError(t, v.waitForActivation(context.Background(), channel))
|
||||
assert.LogsContain(t, hook, "Waiting for deposit to be observed by beacon node")
|
||||
assert.LogsContain(t, hook, "Validator activated")
|
||||
})
|
||||
}
|
||||
|
||||
func TestWaitForActivation_RemoteKeymanager(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
validatorClient := mock.NewMockValidatorClient(ctrl)
|
||||
beaconClient := mock.NewMockBeaconChainClient(ctrl)
|
||||
stream := mock.NewMockBeaconNodeValidator_WaitForActivationClient(ctrl)
|
||||
validatorClient.EXPECT().WaitForActivation(
|
||||
gomock.Any(),
|
||||
gomock.Any(),
|
||||
).Return(stream, nil /* err */).AnyTimes()
|
||||
beaconClient.EXPECT().ListValidators(gomock.Any(), gomock.Any()).Return(ðpb.Validators{}, nil).AnyTimes()
|
||||
|
||||
inactiveKey := bytesutil.ToBytes48([]byte("inactive"))
|
||||
activeKey := bytesutil.ToBytes48([]byte("active"))
|
||||
km := remotekeymanagermock.NewMock()
|
||||
km.PublicKeys = [][fieldparams.BLSPubkeyLength]byte{inactiveKey, activeKey}
|
||||
slot := primitives.Slot(0)
|
||||
|
||||
t.Run("activated", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
hook := logTest.NewGlobal()
|
||||
tickerChan := make(chan primitives.Slot)
|
||||
ticker := &slotutilmock.MockTicker{
|
||||
Channel: tickerChan,
|
||||
}
|
||||
v := validator{
|
||||
validatorClient: validatorClient,
|
||||
keyManager: &km,
|
||||
ticker: ticker,
|
||||
beaconClient: beaconClient,
|
||||
}
|
||||
go func() {
|
||||
tickerChan <- slot
|
||||
// Cancel after timeout to avoid waiting on channel forever in case test goes wrong.
|
||||
time.Sleep(time.Second)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
resp := testutil.GenerateMultipleValidatorStatusResponse([][]byte{inactiveKey[:], activeKey[:]})
|
||||
resp.Statuses[0].Status = ethpb.ValidatorStatus_UNKNOWN_STATUS
|
||||
resp.Statuses[1].Status = ethpb.ValidatorStatus_ACTIVE
|
||||
validatorClient.EXPECT().MultipleValidatorStatus(
|
||||
gomock.Any(),
|
||||
ðpb.MultipleValidatorStatusRequest{
|
||||
PublicKeys: [][]byte{inactiveKey[:], activeKey[:]},
|
||||
},
|
||||
).Return(resp, nil /* err */)
|
||||
err := v.waitForActivation(ctx, nil /* accountsChangedChan */)
|
||||
require.NoError(t, err)
|
||||
assert.LogsContain(t, hook, "Waiting for deposit to be observed by beacon node")
|
||||
assert.LogsContain(t, hook, "Validator activated")
|
||||
})
|
||||
|
||||
t.Run("cancelled", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
||||
tickerChan := make(chan primitives.Slot)
|
||||
ticker := &slotutilmock.MockTicker{
|
||||
Channel: tickerChan,
|
||||
}
|
||||
v := validator{
|
||||
validatorClient: validatorClient,
|
||||
keyManager: &km,
|
||||
ticker: ticker,
|
||||
}
|
||||
go func() {
|
||||
cancel()
|
||||
tickerChan <- slot
|
||||
}()
|
||||
|
||||
err := v.waitForActivation(ctx, nil /* accountsChangedChan */)
|
||||
assert.ErrorContains(t, "context canceled, not waiting for activation anymore", err)
|
||||
})
|
||||
t.Run("reloaded", func(t *testing.T) {
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
hook := logTest.NewGlobal()
|
||||
remoteKm := remotekeymanagermock.NewMock()
|
||||
remoteKm.PublicKeys = [][fieldparams.BLSPubkeyLength]byte{inactiveKey}
|
||||
tickerChan := make(chan primitives.Slot)
|
||||
ticker := &slotutilmock.MockTicker{
|
||||
Channel: tickerChan,
|
||||
}
|
||||
v := validator{
|
||||
validatorClient: validatorClient,
|
||||
keyManager: &remoteKm,
|
||||
ticker: ticker,
|
||||
beaconClient: beaconClient,
|
||||
}
|
||||
go func() {
|
||||
tickerChan <- slot
|
||||
time.Sleep(time.Second)
|
||||
remoteKm.PublicKeys = [][fieldparams.BLSPubkeyLength]byte{inactiveKey, activeKey}
|
||||
tickerChan <- slot
|
||||
// Cancel after timeout to avoid waiting on channel forever in case test goes wrong.
|
||||
time.Sleep(time.Second)
|
||||
cancel()
|
||||
}()
|
||||
|
||||
resp := testutil.GenerateMultipleValidatorStatusResponse([][]byte{inactiveKey[:]})
|
||||
resp.Statuses[0].Status = ethpb.ValidatorStatus_UNKNOWN_STATUS
|
||||
validatorClient.EXPECT().MultipleValidatorStatus(
|
||||
gomock.Any(),
|
||||
ðpb.MultipleValidatorStatusRequest{
|
||||
PublicKeys: [][]byte{inactiveKey[:]},
|
||||
},
|
||||
).Return(resp, nil /* err */)
|
||||
resp2 := testutil.GenerateMultipleValidatorStatusResponse([][]byte{inactiveKey[:], activeKey[:]})
|
||||
resp2.Statuses[0].Status = ethpb.ValidatorStatus_UNKNOWN_STATUS
|
||||
resp2.Statuses[1].Status = ethpb.ValidatorStatus_ACTIVE
|
||||
validatorClient.EXPECT().MultipleValidatorStatus(
|
||||
gomock.Any(),
|
||||
ðpb.MultipleValidatorStatusRequest{
|
||||
PublicKeys: [][]byte{inactiveKey[:], activeKey[:]},
|
||||
},
|
||||
).Return(resp2, nil /* err */)
|
||||
|
||||
err := v.waitForActivation(ctx, remoteKm.ReloadPublicKeysChan /* accountsChangedChan */)
|
||||
require.NoError(t, err)
|
||||
assert.NoError(t, v.internalWaitForActivation(context.Background(), channel))
|
||||
assert.LogsContain(t, hook, "Waiting for deposit to be observed by beacon node")
|
||||
assert.LogsContain(t, hook, "Validator activated")
|
||||
})
|
||||
|
@ -32,7 +32,6 @@ go_test(
|
||||
"//testing/require:go_default_library",
|
||||
"//validator/keymanager/derived:go_default_library",
|
||||
"//validator/keymanager/local:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer:go_default_library",
|
||||
],
|
||||
)
|
||||
|
@ -1,15 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = ["format.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-utils",
|
||||
visibility = [
|
||||
"//validator:__pkg__",
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//validator/accounts/petnames:go_default_library",
|
||||
"@com_github_logrusorgru_aurora//:go_default_library",
|
||||
],
|
||||
)
|
@ -1,22 +0,0 @@
|
||||
package remote_utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/petnames"
|
||||
)
|
||||
|
||||
// DisplayRemotePublicKeys prints remote public keys to stdout.
|
||||
func DisplayRemotePublicKeys(validatingPubKeys [][48]byte) {
|
||||
au := aurora.NewAurora(true)
|
||||
for i := 0; i < len(validatingPubKeys); i++ {
|
||||
fmt.Println("")
|
||||
fmt.Printf(
|
||||
"%s\n", au.BrightGreen(petnames.DeterministicName(validatingPubKeys[i][:], "-")).Bold(),
|
||||
)
|
||||
// Retrieve the validating key account metadata.
|
||||
fmt.Printf("%s %#x\n", au.BrightCyan("[validating public key]").Bold(), validatingPubKeys[i])
|
||||
fmt.Println(" ")
|
||||
}
|
||||
}
|
@ -18,8 +18,8 @@ go_library(
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/eth/service:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//validator/accounts/petnames:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/remote-utils:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer/internal:go_default_library",
|
||||
"//validator/keymanager/remote-web3signer/v1:go_default_library",
|
||||
"@com_github_ethereum_go_ethereum//common/hexutil:go_default_library",
|
||||
|
@ -17,8 +17,8 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/v3/proto/eth/service"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/accounts/petnames"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
remoteutils "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-utils"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-web3signer/internal"
|
||||
web3signerv1 "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-web3signer/v1"
|
||||
log "github.com/sirupsen/logrus"
|
||||
@ -313,10 +313,24 @@ func (km *Keymanager) ListKeymanagerAccounts(ctx context.Context, cfg keymanager
|
||||
} else {
|
||||
fmt.Printf("Showing %d validator accounts\n", len(validatingPubKeys))
|
||||
}
|
||||
remoteutils.DisplayRemotePublicKeys(validatingPubKeys)
|
||||
DisplayRemotePublicKeys(validatingPubKeys)
|
||||
return nil
|
||||
}
|
||||
|
||||
// DisplayRemotePublicKeys prints remote public keys to stdout.
|
||||
func DisplayRemotePublicKeys(validatingPubKeys [][48]byte) {
|
||||
au := aurora.NewAurora(true)
|
||||
for i := 0; i < len(validatingPubKeys); i++ {
|
||||
fmt.Println("")
|
||||
fmt.Printf(
|
||||
"%s\n", au.BrightGreen(petnames.DeterministicName(validatingPubKeys[i][:], "-")).Bold(),
|
||||
)
|
||||
// Retrieve the validating key account metadata.
|
||||
fmt.Printf("%s %#x\n", au.BrightCyan("[validating public key]").Bold(), validatingPubKeys[i])
|
||||
fmt.Println(" ")
|
||||
}
|
||||
}
|
||||
|
||||
// AddPublicKeys imports a list of public keys into the keymanager for web3signer use. Returns status with message.
|
||||
func (km *Keymanager) AddPublicKeys(ctx context.Context, pubKeys [][fieldparams.BLSPubkeyLength]byte) ([]*ethpbservice.ImportedRemoteKeysStatus, error) {
|
||||
if ctx == nil {
|
||||
|
@ -1,52 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library", "go_test")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
srcs = [
|
||||
"doc.go",
|
||||
"keymanager.go",
|
||||
"log.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote",
|
||||
visibility = [
|
||||
"//cmd/validator:__subpackages__",
|
||||
"//validator:__pkg__",
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//async/event:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/eth/service:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/remote-utils:go_default_library",
|
||||
"@com_github_logrusorgru_aurora//:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
"@com_github_sirupsen_logrus//:go_default_library",
|
||||
"@io_bazel_rules_go//proto/wkt:empty_go_proto",
|
||||
"@org_golang_google_grpc//:go_default_library",
|
||||
"@org_golang_google_grpc//credentials:go_default_library",
|
||||
],
|
||||
)
|
||||
|
||||
go_test(
|
||||
name = "go_default_test",
|
||||
srcs = ["keymanager_test.go"],
|
||||
embed = [":go_default_library"],
|
||||
deps = [
|
||||
"//async/event:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//config/params:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//testing/assert:go_default_library",
|
||||
"//testing/mock:go_default_library",
|
||||
"//testing/require:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
"@com_github_golang_mock//gomock:go_default_library",
|
||||
"@com_github_sirupsen_logrus//hooks/test:go_default_library",
|
||||
],
|
||||
)
|
@ -1,59 +0,0 @@
|
||||
/*
|
||||
Package remote defines an implementation of an on-disk, EIP-2335 keystore.json
|
||||
approach towards defining validator accounts in Prysm. A validating private key is
|
||||
encrypted using a passphrase and its resulting encrypted file is stored as a
|
||||
keystore.json file under a unique, human-readable, account namespace. This imported keymanager approach
|
||||
relies on storing account information on-disk, making it trivial to import, backup and
|
||||
list all associated accounts for a user.
|
||||
|
||||
Package remote defines a keymanager implementation which connects to a remote signer
|
||||
server via gRPC. The connection is established via TLS using supplied paths to
|
||||
certificates and key files and allows for submitting remote signing requests for
|
||||
Ethereum data structures as well as retrieving the available signing public keys from
|
||||
the remote server.
|
||||
|
||||
Remote sign requests are defined by the following protobuf schema:
|
||||
|
||||
// SignRequest is a message type used by a keymanager
|
||||
// as part of Prysm's accounts implementation.
|
||||
message SignRequest {
|
||||
// 48 byte public key corresponding to an associated private key
|
||||
// being requested to sign data.
|
||||
bytes public_key = 1;
|
||||
|
||||
// Raw bytes signing root the client is requesting to sign. The client is
|
||||
// expected to determine these raw bytes from the appropriate BLS
|
||||
// signing domain as well as the signing root of the data structure
|
||||
// the bytes represent.
|
||||
bytes signing_root = 2;
|
||||
}
|
||||
|
||||
Remote signing responses will contain a BLS12-381 signature along with the
|
||||
status of the signing response from the remote server, signifying the
|
||||
request either failed, was denied, or completed successfully.
|
||||
|
||||
message SignResponse {
|
||||
enum Status {
|
||||
UNKNOWN = 0;
|
||||
SUCCEEDED = 1;
|
||||
DENIED = 2;
|
||||
FAILED = 3;
|
||||
}
|
||||
|
||||
// BLS12-381 signature for the data specified in the request.
|
||||
bytes signature = 1;
|
||||
}
|
||||
|
||||
The remote keymanager can be customized via a keymanageropts.json file
|
||||
which requires the following schema:
|
||||
|
||||
{
|
||||
"remote_address": "remoteserver.com:4000", // Remote gRPC server address.
|
||||
"remote_cert": {
|
||||
"crt_path": "/home/eth2/certs/client.crt", // Client certificate path.
|
||||
"ca_crt_path": "/home/eth2/certs/ca.crt", // Certificate authority cert path.
|
||||
"key_path": "/home/eth2/certs/client.key", // Client key path.
|
||||
}
|
||||
}
|
||||
*/
|
||||
package remote
|
@ -1,314 +0,0 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"crypto/tls"
|
||||
"crypto/x509"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"github.com/golang/protobuf/ptypes/empty"
|
||||
"github.com/logrusorgru/aurora"
|
||||
"github.com/pkg/errors"
|
||||
"github.com/prysmaticlabs/prysm/v3/async/event"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/v3/proto/eth/service"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
remoteutils "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-utils"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
)
|
||||
|
||||
var (
|
||||
// ErrSigningFailed defines a failure from the remote server
|
||||
// when performing a signing operation.
|
||||
ErrSigningFailed = errors.New("signing failed in the remote server")
|
||||
// ErrSigningDenied defines a failure from the remote server when
|
||||
// performing a signing operation was denied by a remote server.
|
||||
ErrSigningDenied = errors.New("signing request was denied by remote server")
|
||||
)
|
||||
|
||||
// RemoteKeymanager defines the interface for remote Prysm wallets.
|
||||
type RemoteKeymanager interface {
|
||||
keymanager.IKeymanager
|
||||
ReloadPublicKeys(ctx context.Context) ([][fieldparams.BLSPubkeyLength]byte, error)
|
||||
}
|
||||
|
||||
// KeymanagerOpts for a remote keymanager.
|
||||
type KeymanagerOpts struct {
|
||||
RemoteCertificate *CertificateConfig `json:"remote_cert"`
|
||||
RemoteAddr string `json:"remote_address"`
|
||||
}
|
||||
|
||||
// CertificateConfig defines configuration options for
|
||||
// certificate authority certs, client certs, and client keys
|
||||
// for TLS gRPC connections.
|
||||
type CertificateConfig struct {
|
||||
RequireTls bool `json:"require_tls"`
|
||||
ClientCertPath string `json:"crt_path"`
|
||||
ClientKeyPath string `json:"key_path"`
|
||||
CACertPath string `json:"ca_crt_path"`
|
||||
}
|
||||
|
||||
// SetupConfig includes configuration values for initializing
|
||||
// a keymanager, such as passwords, the wallet, and more.
|
||||
type SetupConfig struct {
|
||||
Opts *KeymanagerOpts
|
||||
MaxMessageSize int
|
||||
}
|
||||
|
||||
// Keymanager implementation using remote signing keys via gRPC.
|
||||
type Keymanager struct {
|
||||
opts *KeymanagerOpts
|
||||
client validatorpb.RemoteSignerClient
|
||||
orderedPubKeys [][fieldparams.BLSPubkeyLength]byte
|
||||
accountsChangedFeed *event.Feed
|
||||
}
|
||||
|
||||
// NewKeymanager instantiates a new imported keymanager from configuration options.
|
||||
func NewKeymanager(_ context.Context, cfg *SetupConfig) (*Keymanager, error) {
|
||||
// Load the client certificates.
|
||||
if cfg.Opts.RemoteCertificate == nil {
|
||||
return nil, errors.New("certificate configuration is missing")
|
||||
}
|
||||
|
||||
var clientCreds credentials.TransportCredentials
|
||||
|
||||
if cfg.Opts.RemoteCertificate.RequireTls {
|
||||
if cfg.Opts.RemoteCertificate.ClientCertPath == "" {
|
||||
return nil, errors.New("client certificate is required")
|
||||
}
|
||||
if cfg.Opts.RemoteCertificate.ClientKeyPath == "" {
|
||||
return nil, errors.New("client key is required")
|
||||
}
|
||||
clientPair, err := tls.LoadX509KeyPair(cfg.Opts.RemoteCertificate.ClientCertPath, cfg.Opts.RemoteCertificate.ClientKeyPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain client's certificate and/or key")
|
||||
}
|
||||
|
||||
// Load the CA for the server certificate if present.
|
||||
cp := x509.NewCertPool()
|
||||
if cfg.Opts.RemoteCertificate.CACertPath != "" {
|
||||
serverCA, err := os.ReadFile(cfg.Opts.RemoteCertificate.CACertPath)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "failed to obtain server's CA certificate")
|
||||
}
|
||||
if !cp.AppendCertsFromPEM(serverCA) {
|
||||
return nil, errors.Wrap(err, "failed to add server's CA certificate to pool")
|
||||
}
|
||||
}
|
||||
|
||||
tlsCfg := &tls.Config{
|
||||
Certificates: []tls.Certificate{clientPair},
|
||||
RootCAs: cp,
|
||||
MinVersion: tls.VersionTLS13,
|
||||
}
|
||||
clientCreds = credentials.NewTLS(tlsCfg)
|
||||
}
|
||||
|
||||
grpcOpts := []grpc.DialOption{
|
||||
// Receive large messages without erroring.
|
||||
grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(cfg.MaxMessageSize)),
|
||||
}
|
||||
if cfg.Opts.RemoteCertificate.RequireTls {
|
||||
// Require TLS with client certificate.
|
||||
grpcOpts = append(grpcOpts, grpc.WithTransportCredentials(clientCreds))
|
||||
} else {
|
||||
grpcOpts = append(grpcOpts, grpc.WithInsecure())
|
||||
}
|
||||
|
||||
conn, err := grpc.Dial(cfg.Opts.RemoteAddr, grpcOpts...)
|
||||
if err != nil {
|
||||
return nil, errors.New("failed to connect to remote wallet")
|
||||
}
|
||||
client := validatorpb.NewRemoteSignerClient(conn)
|
||||
k := &Keymanager{
|
||||
opts: cfg.Opts,
|
||||
client: client,
|
||||
orderedPubKeys: make([][fieldparams.BLSPubkeyLength]byte, 0),
|
||||
accountsChangedFeed: new(event.Feed),
|
||||
}
|
||||
return k, nil
|
||||
}
|
||||
|
||||
// UnmarshalOptionsFile attempts to JSON unmarshal a keymanager
|
||||
// options file into a struct.
|
||||
func UnmarshalOptionsFile(r io.ReadCloser) (*KeymanagerOpts, error) {
|
||||
enc, err := io.ReadAll(r)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not read config")
|
||||
}
|
||||
defer func() {
|
||||
if err := r.Close(); err != nil {
|
||||
log.WithError(err).Error("Could not close keymanager config file")
|
||||
}
|
||||
}()
|
||||
opts := &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{RequireTls: true},
|
||||
}
|
||||
if err := json.Unmarshal(enc, opts); err != nil {
|
||||
return nil, errors.Wrap(err, "could not JSON unmarshal")
|
||||
}
|
||||
return opts, nil
|
||||
}
|
||||
|
||||
// MarshalOptionsFile for the keymanager.
|
||||
func MarshalOptionsFile(_ context.Context, cfg *KeymanagerOpts) ([]byte, error) {
|
||||
return json.MarshalIndent(cfg, "", "\t")
|
||||
}
|
||||
|
||||
// String pretty-print of a remote keymanager options.
|
||||
func (opts *KeymanagerOpts) String() string {
|
||||
au := aurora.NewAurora(true)
|
||||
var b strings.Builder
|
||||
strAddr := fmt.Sprintf("%s: %s\n", au.BrightMagenta("Remote gRPC address"), opts.RemoteAddr)
|
||||
if _, err := b.WriteString(strAddr); err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
strRequireTls := fmt.Sprintf(
|
||||
"%s: %t\n", au.BrightMagenta("Require TLS"), opts.RemoteCertificate.RequireTls,
|
||||
)
|
||||
if _, err := b.WriteString(strRequireTls); err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
strCrt := fmt.Sprintf(
|
||||
"%s: %s\n", au.BrightMagenta("Client cert path"), opts.RemoteCertificate.ClientCertPath,
|
||||
)
|
||||
if _, err := b.WriteString(strCrt); err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
strKey := fmt.Sprintf(
|
||||
"%s: %s\n", au.BrightMagenta("Client key path"), opts.RemoteCertificate.ClientKeyPath,
|
||||
)
|
||||
if _, err := b.WriteString(strKey); err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
strCa := fmt.Sprintf(
|
||||
"%s: %s\n", au.BrightMagenta("CA cert path"), opts.RemoteCertificate.CACertPath,
|
||||
)
|
||||
if _, err := b.WriteString(strCa); err != nil {
|
||||
log.Error(err)
|
||||
return ""
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
|
||||
// KeymanagerOpts for the remote keymanager.
|
||||
func (km *Keymanager) KeymanagerOpts() *KeymanagerOpts {
|
||||
return km.opts
|
||||
}
|
||||
|
||||
// ReloadPublicKeys reloads public keys.
|
||||
func (km *Keymanager) ReloadPublicKeys(ctx context.Context) ([][fieldparams.BLSPubkeyLength]byte, error) {
|
||||
pubKeys, err := km.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not reload public keys")
|
||||
}
|
||||
|
||||
sort.Slice(pubKeys, func(i, j int) bool { return bytes.Compare(pubKeys[i][:], pubKeys[j][:]) == -1 })
|
||||
if len(km.orderedPubKeys) != len(pubKeys) {
|
||||
log.Info(keymanager.KeysReloaded)
|
||||
km.accountsChangedFeed.Send(pubKeys)
|
||||
} else {
|
||||
for i := range km.orderedPubKeys {
|
||||
if !bytes.Equal(km.orderedPubKeys[i][:], pubKeys[i][:]) {
|
||||
log.Info(keymanager.KeysReloaded)
|
||||
km.accountsChangedFeed.Send(pubKeys)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
km.orderedPubKeys = pubKeys
|
||||
return km.orderedPubKeys, nil
|
||||
}
|
||||
|
||||
// FetchValidatingPublicKeys fetches the list of public keys that should be used to validate with.
|
||||
func (km *Keymanager) FetchValidatingPublicKeys(ctx context.Context) ([][fieldparams.BLSPubkeyLength]byte, error) {
|
||||
resp, err := km.client.ListValidatingPublicKeys(ctx, &empty.Empty{})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "could not list accounts from remote server")
|
||||
}
|
||||
pubKeys := make([][fieldparams.BLSPubkeyLength]byte, len(resp.ValidatingPublicKeys))
|
||||
for i := range resp.ValidatingPublicKeys {
|
||||
pubKeys[i] = bytesutil.ToBytes48(resp.ValidatingPublicKeys[i])
|
||||
}
|
||||
return pubKeys, nil
|
||||
}
|
||||
|
||||
// Sign signs a message for a validator key via a gRPC request.
|
||||
func (km *Keymanager) Sign(ctx context.Context, req *validatorpb.SignRequest) (bls.Signature, error) {
|
||||
resp, err := km.client.Sign(ctx, req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
switch resp.Status {
|
||||
case validatorpb.SignResponse_DENIED:
|
||||
return nil, ErrSigningDenied
|
||||
case validatorpb.SignResponse_FAILED:
|
||||
return nil, ErrSigningFailed
|
||||
}
|
||||
return bls.SignatureFromBytes(resp.Signature)
|
||||
}
|
||||
|
||||
// SubscribeAccountChanges creates an event subscription for a channel
|
||||
// to listen for public key changes at runtime, such as when new validator accounts
|
||||
// are imported into the keymanager while the validator process is running.
|
||||
func (km *Keymanager) SubscribeAccountChanges(pubKeysChan chan [][fieldparams.BLSPubkeyLength]byte) event.Subscription {
|
||||
return km.accountsChangedFeed.Subscribe(pubKeysChan)
|
||||
}
|
||||
|
||||
// ExtractKeystores is not supported for the remote keymanager type.
|
||||
func (*Keymanager) ExtractKeystores(
|
||||
_ context.Context, _ []bls.PublicKey, _ string,
|
||||
) ([]*keymanager.Keystore, error) {
|
||||
return nil, errors.New("extracting keys not supported for a remote keymanager")
|
||||
}
|
||||
|
||||
// DeleteKeystores is not supported for the remote keymanager type.
|
||||
func (*Keymanager) DeleteKeystores(context.Context, [][]byte) ([]*ethpbservice.DeletedKeystoreStatus, error) {
|
||||
return nil, errors.New("Wrong wallet type: web3-signer. Only Imported or Derived wallets can delete accounts")
|
||||
}
|
||||
|
||||
func (km *Keymanager) ListKeymanagerAccounts(ctx context.Context, cfg keymanager.ListKeymanagerAccountConfig) error {
|
||||
return ListKeymanagerAccountsImpl(ctx, cfg, km, km.KeymanagerOpts())
|
||||
}
|
||||
|
||||
func ListKeymanagerAccountsImpl(ctx context.Context, cfg keymanager.ListKeymanagerAccountConfig, km keymanager.IKeymanager, opts *KeymanagerOpts) error {
|
||||
au := aurora.NewAurora(true)
|
||||
fmt.Printf("(keymanager kind) %s\n", au.BrightGreen("remote signer").Bold())
|
||||
fmt.Printf(
|
||||
"(configuration file path) %s\n",
|
||||
au.BrightGreen(filepath.Join(cfg.WalletAccountsDir, cfg.KeymanagerConfigFileName)).Bold(),
|
||||
)
|
||||
fmt.Println(" ")
|
||||
fmt.Printf("%s\n", au.BrightGreen("Configuration options").Bold())
|
||||
fmt.Println(opts)
|
||||
validatingPubKeys, err := km.FetchValidatingPublicKeys(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not fetch validating public keys")
|
||||
}
|
||||
if len(validatingPubKeys) == 1 {
|
||||
fmt.Print("Showing 1 validator account\n")
|
||||
} else if len(validatingPubKeys) == 0 {
|
||||
fmt.Print("No accounts found\n")
|
||||
return nil
|
||||
} else {
|
||||
fmt.Printf("Showing %d validator accounts\n", len(validatingPubKeys))
|
||||
}
|
||||
remoteutils.DisplayRemotePublicKeys(validatingPubKeys)
|
||||
return nil
|
||||
}
|
@ -1,414 +0,0 @@
|
||||
package remote
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"strconv"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/prysmaticlabs/prysm/v3/async/event"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/config/params"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/mock"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
logTest "github.com/sirupsen/logrus/hooks/test"
|
||||
)
|
||||
|
||||
var validClientCert = `-----BEGIN CERTIFICATE-----
|
||||
MIIEITCCAgmgAwIBAgIQXUJWQZgVO4IX+zlWGI1/mTANBgkqhkiG9w0BAQsFADAU
|
||||
MRIwEAYDVQQDEwlBdHRlc3RhbnQwHhcNMjAwMzE3MDgwNjU3WhcNMjEwOTE3MDc1
|
||||
OTUyWjASMRAwDgYDVQQDEwdjbGllbnQxMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A
|
||||
MIIBCgKCAQEAsc977g16Tan2j7YuA+zQOlDntb4Bkfs4sDOznOEvnozHwRZOgfcP
|
||||
jVcA9AS5eZOGIRrsTssptrgVNDPoIHWoKk7LAKyyLM3dGp5PWeyMBoQA5cq+yPAT
|
||||
4JkJpDnBFfwxXB99osJH0z3jSTRa62CSVvPRBisK4B9AlLQfcleEQlKJugy9tOAj
|
||||
G7zodwEi+J4AYQHmOiwL38ZsKq9We5y4HMQ0E7de0FoU5QHrtuPNrTuwVwrq825l
|
||||
cEAAFey6Btngx+sziysPHWHYOq4xOZ1UPBApeaAFLguzusc/4VwM7kzRNr4VOD8a
|
||||
eC3CtKLhBBVVxHI5ZlaHS+YylNGYD4+FxQIDAQABo3EwbzAOBgNVHQ8BAf8EBAMC
|
||||
A7gwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMB0GA1UdDgQWBBQDGCE0
|
||||
3k4rHzB+Ycf3pt1MzeDPgzAfBgNVHSMEGDAWgBScIYZa4dQBIW/gVwR0ctGCuHhe
|
||||
9jANBgkqhkiG9w0BAQsFAAOCAgEAHG/EfvqIwbhYfci+zRCYC7aQPuvhivJblBwN
|
||||
mbXo2qsxvje1hcKm0ptJLOy/cjJzeLJYREhQlXDPRJC/xgELnbXRjgag82r35+pf
|
||||
wVJwP6Yw53VCM3o0QKsUrKyMm4sAijOBrJyqpB5untAieZsry5Bfj0S4YobbtdJa
|
||||
VsEioU07fVVczf5lYN0XrLgRnXq3LMkTiZ6drFiqLkwmXQZVxNujmcaFSm7yCALl
|
||||
EdhYNmaqedS5me5UOGxwPacrsZwWF9dvMsl3OswgTcaGdsUtx2/q+S2vbZUAM/Gw
|
||||
qaTanDfvVtVTF7KzVN9hiqKe4mO0HHHK2HWJYBLdRJjInOgRW+53hCmUhLxD+Dq+
|
||||
31jLKxn/Y4hyH9E+55b1sJHCFpsbEtVD53fojiH2C/uLbhq4Wr1PXgOoxzf2KeSQ
|
||||
B3ENu8C4b6AlNhqOnz5zeDcx8Ug0vMfVDAwf6RAYMG5b/MoWNKcLNXhk8H1nbVkt
|
||||
16ppjh6I27JqfNqfP2J/p3BF++ZugZuWfN9DRaJ6UPz+yyF7eW8fyDAQNl7LS0Kh
|
||||
8PlF5cYvyIIKVHe38Mn8ZAWboKUs0xNv2vhA9V/4Q1ZzAEkXjmbk8H26sjGvJnvg
|
||||
Lgm/+6LVWR4EnUlU8aEWASEpTWq2lSRF3ZOvNstHnufyiDfcwDcl/IKKQiVQQ3mX
|
||||
tw8Jf74=
|
||||
-----END CERTIFICATE-----`
|
||||
|
||||
// skipcq: SCT-1000
|
||||
var validClientKey = `-----BEGIN RSA PRIVATE KEY-----
|
||||
MIIEpAIBAAKCAQEAsc977g16Tan2j7YuA+zQOlDntb4Bkfs4sDOznOEvnozHwRZO
|
||||
gfcPjVcA9AS5eZOGIRrsTssptrgVNDPoIHWoKk7LAKyyLM3dGp5PWeyMBoQA5cq+
|
||||
yPAT4JkJpDnBFfwxXB99osJH0z3jSTRa62CSVvPRBisK4B9AlLQfcleEQlKJugy9
|
||||
tOAjG7zodwEi+J4AYQHmOiwL38ZsKq9We5y4HMQ0E7de0FoU5QHrtuPNrTuwVwrq
|
||||
825lcEAAFey6Btngx+sziysPHWHYOq4xOZ1UPBApeaAFLguzusc/4VwM7kzRNr4V
|
||||
OD8aeC3CtKLhBBVVxHI5ZlaHS+YylNGYD4+FxQIDAQABAoIBAQCjV2MVcDQmHDhw
|
||||
FH95A5bVu3TgM8flfs64rwYU25iPIexuqDs+kOMsh/xMLfrkgGz7BGyIhYGwZLK1
|
||||
3ekjyHHPS8qYuAyFtCelSEDE7tRDOAhLEFDq7gCUloGQ561EsQP3CMa1OZwZpgSh
|
||||
PwM2ruRAFIK0E95NvOfqsv0gYN0Svo7hYjNsvW6ok/ZGMyN2ikcRR04wGOFOGjfT
|
||||
xTmfURc9ejnOjHAOqLTpToPwM1/gWWR2iMQefC4njy4MO2BXqOPUmHxmmR4PYhu2
|
||||
8EcKbyRs+/fvL3GgD3VAlOe5vnkfBzssQhHmexgSk5lHZrcSxUGXYGrYKPAeV2mk
|
||||
5HRBWp0RAoGBAOUn5w+NCAugcTGP0hfNlyGXsXqUZvnMyFWvUcxgzgPlJyEyDnKn
|
||||
aIb1DFOF2HckCfLZdrHqqgaF6K3TDvW9BgSKIsvISpo1S95ZPD6DKUo6YQ10CQRW
|
||||
q/ZZVbxtFksVgFRGYpCVmPNULmx7CiXDT1b/suwNMAwCZwiNPTSvKQVLAoGBAMaj
|
||||
zDo1/eepRslqnz5s8hh7dGEjfG/ZJcLgAJAxCyAgnIP4Tls7QkNhCVp9LcN6i1bc
|
||||
CnT6AIuZRXSJWEdp4k2QnVFUmh9Q5MGgwrKYSY5M/1puTISlF1yQ8J6FX8BlDVmy
|
||||
4dyaSyC0RIvgBzF9/KBDxxmJcHgGQ0awLeeyl4cvAoGBAN83FS3itLmOmXQrofyp
|
||||
uNNyDeFXeU9OmL5OPqGUkljc+Favib9JLtp3DIC3WfoD0uUJy0LXULN18QaRFnts
|
||||
mtYFMIvMGE9KJxL5XWOPI8M4Rp1yL+5X9r3Km2cl45dT5GMzBIPOFOTBVU86MtJC
|
||||
A6C9Bi5FUk4AcRi1a69MB+stAoGAWNiwoyS9IV38dGCFQ4W1LzAg2MXnhZuJoUVR
|
||||
2yykfkU33Gs2mOXDeKGxblDpJDLumfYnkzSzA72VbE92NdLtTqYtR1Bg8zraZqTC
|
||||
EOG+nLBh0o/dF8ND1LpbdXvQXRyVwRYaofI9Qi5/LlUQwplIYmKObiSkMnsSok5w
|
||||
6d5emi8CgYBjtUihOFaAmgqkTHOn4j4eKS1O7/H8QQSVe5M0bocmAIbgJ4At3GnI
|
||||
E1JcIY2SZtSwAWs6aQPGE42gwsNCCsQWdJNtViO23JbCwlcPToC4aDfc0JJNaYqp
|
||||
oVV7C5jmJh9VRd2tXIXIZMMNOfThfNf2qDQuJ1S2t5KugozFiRsHUg==
|
||||
-----END RSA PRIVATE KEY-----`
|
||||
|
||||
func TestNewRemoteKeymanager(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
opts *KeymanagerOpts
|
||||
clientCert string
|
||||
clientKey string
|
||||
caCert string
|
||||
err string
|
||||
}{
|
||||
{
|
||||
name: "NoCertificates",
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: nil,
|
||||
},
|
||||
err: "certificate configuration is missing",
|
||||
},
|
||||
{
|
||||
name: "NoClientCertificate",
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: true,
|
||||
},
|
||||
},
|
||||
err: "client certificate is required",
|
||||
},
|
||||
{
|
||||
name: "NoClientKey",
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: true,
|
||||
ClientCertPath: "/foo/client.crt",
|
||||
ClientKeyPath: "",
|
||||
},
|
||||
},
|
||||
err: "client key is required",
|
||||
},
|
||||
{
|
||||
name: "MissingClientKey",
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: true,
|
||||
ClientCertPath: "/foo/client.crt",
|
||||
ClientKeyPath: "/foo/client.key",
|
||||
CACertPath: "",
|
||||
},
|
||||
},
|
||||
err: "failed to obtain client's certificate and/or key",
|
||||
},
|
||||
{
|
||||
name: "BadClientCert",
|
||||
clientCert: `bad`,
|
||||
clientKey: validClientKey,
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: true,
|
||||
},
|
||||
},
|
||||
err: "failed to obtain client's certificate and/or key: tls: failed to find any PEM data in certificate input",
|
||||
},
|
||||
{
|
||||
name: "BadClientKey",
|
||||
clientCert: validClientCert,
|
||||
clientKey: `bad`,
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: true,
|
||||
},
|
||||
},
|
||||
err: "failed to obtain client's certificate and/or key: tls: failed to find any PEM data in key input",
|
||||
},
|
||||
{
|
||||
name: "MissingCACert",
|
||||
clientCert: validClientCert,
|
||||
clientKey: validClientKey,
|
||||
opts: &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: true,
|
||||
CACertPath: `bad`,
|
||||
},
|
||||
},
|
||||
err: "failed to obtain server's CA certificate: open bad: no such file or directory",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
if test.caCert != "" || test.clientCert != "" || test.clientKey != "" {
|
||||
dir := fmt.Sprintf("%s/%s", t.TempDir(), test.name)
|
||||
require.NoError(t, os.MkdirAll(dir, 0777))
|
||||
if test.caCert != "" {
|
||||
caCertPath := fmt.Sprintf("%s/ca.crt", dir)
|
||||
err := os.WriteFile(caCertPath, []byte(test.caCert), params.BeaconIoConfig().ReadWritePermissions)
|
||||
require.NoError(t, err, "Failed to write CA certificate")
|
||||
test.opts.RemoteCertificate.CACertPath = caCertPath
|
||||
}
|
||||
if test.clientCert != "" {
|
||||
clientCertPath := fmt.Sprintf("%s/client.crt", dir)
|
||||
err := os.WriteFile(clientCertPath, []byte(test.clientCert), params.BeaconIoConfig().ReadWritePermissions)
|
||||
require.NoError(t, err, "Failed to write client certificate")
|
||||
test.opts.RemoteCertificate.ClientCertPath = clientCertPath
|
||||
}
|
||||
if test.clientKey != "" {
|
||||
clientKeyPath := fmt.Sprintf("%s/client.key", dir)
|
||||
err := os.WriteFile(clientKeyPath, []byte(test.clientKey), params.BeaconIoConfig().ReadWritePermissions)
|
||||
require.NoError(t, err, "Failed to write client key")
|
||||
test.opts.RemoteCertificate.ClientKeyPath = clientKeyPath
|
||||
}
|
||||
}
|
||||
_, err := NewKeymanager(context.Background(), &SetupConfig{Opts: test.opts, MaxMessageSize: 1})
|
||||
if test.err == "" {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.ErrorContains(t, test.err, err)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewRemoteKeymanager_TlsDisabled(t *testing.T) {
|
||||
opts := &KeymanagerOpts{
|
||||
RemoteCertificate: &CertificateConfig{
|
||||
RequireTls: false,
|
||||
},
|
||||
}
|
||||
_, err := NewKeymanager(context.Background(), &SetupConfig{Opts: opts, MaxMessageSize: 1})
|
||||
assert.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestRemoteKeymanager_Sign(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
m := mock.NewMockRemoteSignerClient(ctrl)
|
||||
k := &Keymanager{
|
||||
client: m,
|
||||
}
|
||||
|
||||
// Expect error handling to work.
|
||||
m.EXPECT().Sign(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(nil, errors.New("could not sign"))
|
||||
_, err := k.Sign(context.Background(), nil)
|
||||
require.ErrorContains(t, "could not sign", err)
|
||||
|
||||
// Expected proper error handling for signing response statuses.
|
||||
m.EXPECT().Sign(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.SignResponse{
|
||||
Status: validatorpb.SignResponse_FAILED,
|
||||
}, nil /*err*/)
|
||||
_, err = k.Sign(context.Background(), nil)
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err != ErrSigningFailed {
|
||||
t.Errorf("Expected %v, received %v", ErrSigningFailed, err)
|
||||
}
|
||||
m.EXPECT().Sign(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.SignResponse{
|
||||
Status: validatorpb.SignResponse_DENIED,
|
||||
}, nil /*err*/)
|
||||
_, err = k.Sign(context.Background(), nil)
|
||||
if err == nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err != ErrSigningDenied {
|
||||
t.Errorf("Expected %v, received %v", ErrSigningDenied, err)
|
||||
}
|
||||
|
||||
// Expected signing success.
|
||||
randKey, err := bls.RandKey()
|
||||
require.NoError(t, err)
|
||||
data := []byte("hello-world")
|
||||
sig := randKey.Sign(data)
|
||||
m.EXPECT().Sign(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.SignResponse{
|
||||
Status: validatorpb.SignResponse_SUCCEEDED,
|
||||
Signature: sig.Marshal(),
|
||||
}, nil /*err*/)
|
||||
resp, err := k.Sign(context.Background(), nil)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, sig.Marshal(), resp.Marshal())
|
||||
}
|
||||
|
||||
func TestRemoteKeymanager_FetchValidatingPublicKeys(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
m := mock.NewMockRemoteSignerClient(ctrl)
|
||||
k := &Keymanager{
|
||||
client: m,
|
||||
accountsChangedFeed: new(event.Feed),
|
||||
}
|
||||
|
||||
// Expect error handling to work.
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(nil, errors.New("could not fetch keys"))
|
||||
_, err := k.FetchValidatingPublicKeys(context.Background())
|
||||
require.ErrorContains(t, "could not fetch keys", err)
|
||||
|
||||
// Expect an empty response to return empty keys.
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.ListPublicKeysResponse{
|
||||
ValidatingPublicKeys: make([][]byte, 0),
|
||||
}, nil /*err*/)
|
||||
keys, err := k.FetchValidatingPublicKeys(context.Background())
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, 0, len(keys), "Expected empty response")
|
||||
|
||||
numKeys := 10
|
||||
pubKeys := make([][]byte, numKeys)
|
||||
for i := 0; i < numKeys; i++ {
|
||||
key := make([]byte, 48)
|
||||
copy(key, strconv.Itoa(i))
|
||||
pubKeys[i] = key
|
||||
}
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.ListPublicKeysResponse{
|
||||
ValidatingPublicKeys: pubKeys,
|
||||
}, nil /*err*/)
|
||||
keys, err = k.FetchValidatingPublicKeys(context.Background())
|
||||
require.NoError(t, err)
|
||||
rawKeys := make([][]byte, len(keys))
|
||||
for i := 0; i < len(rawKeys); i++ {
|
||||
rawKeys[i] = keys[i][:]
|
||||
}
|
||||
assert.DeepEqual(t, pubKeys, rawKeys)
|
||||
}
|
||||
|
||||
func TestUnmarshalOptionsFile_DefaultRequireTls(t *testing.T) {
|
||||
optsWithoutTls := struct {
|
||||
RemoteCertificate struct {
|
||||
ClientCertPath string
|
||||
ClientKeyPath string
|
||||
CACertPath string
|
||||
}
|
||||
}{}
|
||||
var buffer bytes.Buffer
|
||||
b, err := json.Marshal(optsWithoutTls)
|
||||
require.NoError(t, err)
|
||||
_, err = buffer.Write(b)
|
||||
require.NoError(t, err)
|
||||
r := io.NopCloser(&buffer)
|
||||
|
||||
opts, err := UnmarshalOptionsFile(r)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, true, opts.RemoteCertificate.RequireTls)
|
||||
}
|
||||
|
||||
func TestReloadPublicKeys(t *testing.T) {
|
||||
hook := logTest.NewGlobal()
|
||||
ctx := context.Background()
|
||||
ctrl := gomock.NewController(t)
|
||||
m := mock.NewMockRemoteSignerClient(ctrl)
|
||||
|
||||
k := &Keymanager{
|
||||
client: m,
|
||||
accountsChangedFeed: new(event.Feed),
|
||||
orderedPubKeys: [][fieldparams.BLSPubkeyLength]byte{bytesutil.ToBytes48([]byte("100"))},
|
||||
}
|
||||
|
||||
// Add key
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.ListPublicKeysResponse{
|
||||
// Return keys in reverse order to verify ordering
|
||||
ValidatingPublicKeys: [][]byte{[]byte("200"), []byte("100")},
|
||||
}, nil /* err */)
|
||||
|
||||
keys, err := k.ReloadPublicKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, [][fieldparams.BLSPubkeyLength]byte{bytesutil.ToBytes48([]byte("100")), bytesutil.ToBytes48([]byte("200"))}, k.orderedPubKeys)
|
||||
assert.DeepEqual(t, keys, k.orderedPubKeys)
|
||||
assert.LogsContain(t, hook, keymanager.KeysReloaded)
|
||||
|
||||
hook.Reset()
|
||||
|
||||
// Remove key
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.ListPublicKeysResponse{
|
||||
ValidatingPublicKeys: [][]byte{[]byte("200")},
|
||||
}, nil /* err */)
|
||||
|
||||
keys, err = k.ReloadPublicKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, [][fieldparams.BLSPubkeyLength]byte{bytesutil.ToBytes48([]byte("200"))}, k.orderedPubKeys)
|
||||
assert.DeepEqual(t, keys, k.orderedPubKeys)
|
||||
assert.LogsContain(t, hook, keymanager.KeysReloaded)
|
||||
|
||||
hook.Reset()
|
||||
|
||||
// Change key
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.ListPublicKeysResponse{
|
||||
ValidatingPublicKeys: [][]byte{[]byte("300")},
|
||||
}, nil /* err */)
|
||||
|
||||
keys, err = k.ReloadPublicKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, [][fieldparams.BLSPubkeyLength]byte{bytesutil.ToBytes48([]byte("300"))}, k.orderedPubKeys)
|
||||
assert.DeepEqual(t, keys, k.orderedPubKeys)
|
||||
assert.LogsContain(t, hook, keymanager.KeysReloaded)
|
||||
|
||||
hook.Reset()
|
||||
|
||||
// No change
|
||||
m.EXPECT().ListValidatingPublicKeys(
|
||||
gomock.Any(), // ctx
|
||||
gomock.Any(), // epoch
|
||||
).Return(&validatorpb.ListPublicKeysResponse{
|
||||
ValidatingPublicKeys: [][]byte{[]byte("300")},
|
||||
}, nil /* err */)
|
||||
|
||||
keys, err = k.ReloadPublicKeys(ctx)
|
||||
require.NoError(t, err)
|
||||
assert.DeepEqual(t, [][fieldparams.BLSPubkeyLength]byte{bytesutil.ToBytes48([]byte("300"))}, k.orderedPubKeys)
|
||||
assert.DeepEqual(t, keys, k.orderedPubKeys)
|
||||
assert.LogsDoNotContain(t, hook, keymanager.KeysReloaded)
|
||||
}
|
@ -1,5 +0,0 @@
|
||||
package remote
|
||||
|
||||
import "github.com/sirupsen/logrus"
|
||||
|
||||
var log = logrus.WithField("prefix", "remote-keymanager")
|
@ -1,21 +0,0 @@
|
||||
load("@prysm//tools/go:def.bzl", "go_library")
|
||||
|
||||
go_library(
|
||||
name = "go_default_library",
|
||||
testonly = True,
|
||||
srcs = ["mock_keymanager.go"],
|
||||
importpath = "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote/mock",
|
||||
visibility = ["//visibility:public"],
|
||||
deps = [
|
||||
"//async/event:go_default_library",
|
||||
"//beacon-chain/core/signing:go_default_library",
|
||||
"//config/fieldparams:go_default_library",
|
||||
"//crypto/bls:go_default_library",
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//proto/eth/service:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//testing/util:go_default_library",
|
||||
"//time/slots:go_default_library",
|
||||
"//validator/keymanager:go_default_library",
|
||||
],
|
||||
)
|
@ -1,82 +0,0 @@
|
||||
package mock
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/prysmaticlabs/prysm/v3/async/event"
|
||||
"github.com/prysmaticlabs/prysm/v3/beacon-chain/core/signing"
|
||||
fieldparams "github.com/prysmaticlabs/prysm/v3/config/fieldparams"
|
||||
"github.com/prysmaticlabs/prysm/v3/crypto/bls"
|
||||
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
|
||||
ethpbservice "github.com/prysmaticlabs/prysm/v3/proto/eth/service"
|
||||
validatorpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/v3/testing/util"
|
||||
"github.com/prysmaticlabs/prysm/v3/time/slots"
|
||||
"github.com/prysmaticlabs/prysm/v3/validator/keymanager"
|
||||
)
|
||||
|
||||
// MockKeymanager --
|
||||
type MockKeymanager struct {
|
||||
PublicKeys [][fieldparams.BLSPubkeyLength]byte
|
||||
ReloadPublicKeysChan chan [][fieldparams.BLSPubkeyLength]byte
|
||||
ReloadPublicKeysCalled bool
|
||||
accountsChangedFeed *event.Feed
|
||||
}
|
||||
|
||||
func NewMock() MockKeymanager {
|
||||
return MockKeymanager{
|
||||
accountsChangedFeed: new(event.Feed),
|
||||
ReloadPublicKeysChan: make(chan [][fieldparams.BLSPubkeyLength]byte, 1),
|
||||
}
|
||||
}
|
||||
|
||||
// FetchValidatingPublicKeys --
|
||||
func (m *MockKeymanager) FetchValidatingPublicKeys(context.Context) ([][fieldparams.BLSPubkeyLength]byte, error) {
|
||||
return m.PublicKeys, nil
|
||||
}
|
||||
|
||||
// Sign --
|
||||
func (*MockKeymanager) Sign(_ context.Context, s *validatorpb.SignRequest) (bls.Signature, error) {
|
||||
key, err := bls.RandKey()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
st, _ := util.DeterministicGenesisState(nil, 1)
|
||||
e := slots.ToEpoch(st.Slot())
|
||||
byteValue, err := signing.ComputeDomainAndSign(st, e, s.SigningSlot, bytesutil.ToBytes4(s.SignatureDomain), key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return bls.SignatureFromBytes(byteValue)
|
||||
}
|
||||
|
||||
// SubscribeAccountChanges --
|
||||
func (m *MockKeymanager) SubscribeAccountChanges(chan [][fieldparams.BLSPubkeyLength]byte) event.Subscription {
|
||||
return m.accountsChangedFeed.Subscribe(m.ReloadPublicKeysChan)
|
||||
}
|
||||
|
||||
// ReloadPublicKeys --
|
||||
func (m *MockKeymanager) ReloadPublicKeys(context.Context) ([][fieldparams.BLSPubkeyLength]byte, error) {
|
||||
m.ReloadPublicKeysCalled = true
|
||||
m.ReloadPublicKeysChan <- m.PublicKeys
|
||||
return m.PublicKeys, nil
|
||||
}
|
||||
|
||||
// ExtractKeystores --
|
||||
func (*MockKeymanager) ExtractKeystores(
|
||||
_ context.Context, _ []bls.PublicKey, _ string,
|
||||
) ([]*keymanager.Keystore, error) {
|
||||
return nil, errors.New("extracting keys not supported for a remote keymanager")
|
||||
}
|
||||
|
||||
// ListKeymanagerAccounts --
|
||||
func (*MockKeymanager) ListKeymanagerAccounts(
|
||||
context.Context, keymanager.ListKeymanagerAccountConfig) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (*MockKeymanager) DeleteKeystores(context.Context, [][]byte,
|
||||
) ([]*ethpbservice.DeletedKeystoreStatus, error) {
|
||||
return nil, nil
|
||||
}
|
@ -100,8 +100,6 @@ const (
|
||||
Local Kind = iota
|
||||
// Derived keymanager using a hierarchical-deterministic algorithm.
|
||||
Derived
|
||||
// Remote keymanager capable of remote-signing data.
|
||||
Remote
|
||||
// Web3Signer keymanager capable of signing data using a remote signer called Web3Signer.
|
||||
Web3Signer
|
||||
)
|
||||
@ -121,8 +119,6 @@ func (k Kind) String() string {
|
||||
// multiple directories will cause the isValid function to fail in wallet.go
|
||||
// and may result in using a unintended wallet.
|
||||
return "direct"
|
||||
case Remote:
|
||||
return "remote"
|
||||
case Web3Signer:
|
||||
return "web3signer"
|
||||
default:
|
||||
@ -137,8 +133,6 @@ func ParseKind(k string) (Kind, error) {
|
||||
return Derived, nil
|
||||
case "direct", "imported", "local":
|
||||
return Local, nil
|
||||
case "remote":
|
||||
return Remote, nil
|
||||
case "web3signer":
|
||||
return Web3Signer, nil
|
||||
default:
|
||||
|
@ -10,14 +10,12 @@ import (
|
||||
"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"
|
||||
remoteweb3signer "github.com/prysmaticlabs/prysm/v3/validator/keymanager/remote-web3signer"
|
||||
)
|
||||
|
||||
var (
|
||||
_ = keymanager.IKeymanager(&local.Keymanager{})
|
||||
_ = keymanager.IKeymanager(&derived.Keymanager{})
|
||||
_ = keymanager.IKeymanager(&remote.Keymanager{})
|
||||
|
||||
// More granular assertions.
|
||||
_ = keymanager.KeysFetcher(&local.Keymanager{})
|
||||
|
@ -50,8 +50,6 @@ func (s *Server) CreateWallet(ctx context.Context, req *pb.CreateWalletRequest)
|
||||
switch s.wallet.KeymanagerKind() {
|
||||
case keymanager.Derived:
|
||||
keymanagerKind = pb.KeymanagerKind_DERIVED
|
||||
case keymanager.Remote:
|
||||
keymanagerKind = pb.KeymanagerKind_REMOTE
|
||||
case keymanager.Web3Signer:
|
||||
keymanagerKind = pb.KeymanagerKind_WEB3SIGNER
|
||||
}
|
||||
@ -132,8 +130,6 @@ func (s *Server) WalletConfig(_ context.Context, _ *empty.Empty) (*pb.WalletResp
|
||||
keymanagerKind = pb.KeymanagerKind_DERIVED
|
||||
case keymanager.Local:
|
||||
keymanagerKind = pb.KeymanagerKind_IMPORTED
|
||||
case keymanager.Remote:
|
||||
keymanagerKind = pb.KeymanagerKind_REMOTE
|
||||
case keymanager.Web3Signer:
|
||||
keymanagerKind = pb.KeymanagerKind_WEB3SIGNER
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user