mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-08 23:18:15 -05: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:
@@ -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{})
|
||||
|
||||
Reference in New Issue
Block a user