From e3fb4e86ec851643b747d04e77720d0be7ed0eec Mon Sep 17 00:00:00 2001 From: james-prysm <90280386+james-prysm@users.noreply.github.com> Date: Fri, 28 Mar 2025 09:03:42 -0500 Subject: [PATCH] validator client initialization cleanup (#15080) * cleanup * fixing optimal sort order for struct * reverting clictx change based on kasey's feedback * adding in fix for old trace file flag * more cleanup for clarity * optimizing if statement check and fixing wallet open on web enable * optimizing if statement check and fixing wallet open on web enable * some more cleanup and bug fix on open wallet * reverting debug.go changes will handle in a separate PR * removing useless comment * changing useWeb to enableAPI * fixing tests and linting * manu feedback and one optimization removing auth token check * gaz --- ...cleanup-validator-client-initialization.md | 3 + validator/accounts/wallet/wallet.go | 5 + validator/client/registration_test.go | 8 +- validator/client/service.go | 8 +- validator/client/validator.go | 47 ++-- validator/client/validator_test.go | 28 +-- validator/node/BUILD.bazel | 1 - validator/node/node.go | 235 +++++++----------- validator/rpc/auth_token.go | 29 +-- validator/rpc/server.go | 56 +++-- 10 files changed, 192 insertions(+), 228 deletions(-) create mode 100644 changelog/james-prysm_cleanup-validator-client-initialization.md diff --git a/changelog/james-prysm_cleanup-validator-client-initialization.md b/changelog/james-prysm_cleanup-validator-client-initialization.md new file mode 100644 index 0000000000..12c22bf294 --- /dev/null +++ b/changelog/james-prysm_cleanup-validator-client-initialization.md @@ -0,0 +1,3 @@ +### Fixed + +- The `--rpc` flag will now properly enable the keymanager APIs without web. The `--web` will enable both validator api endpoints and web. \ No newline at end of file diff --git a/validator/accounts/wallet/wallet.go b/validator/accounts/wallet/wallet.go index 8dd3f853cb..04857d0625 100644 --- a/validator/accounts/wallet/wallet.go +++ b/validator/accounts/wallet/wallet.go @@ -186,6 +186,7 @@ func OpenWalletOrElseCli(cliCtx *cli.Context, otherwise func(cliCtx *cli.Context if err != nil { return nil, err } + return OpenWallet(cliCtx.Context, &Config{ WalletDir: walletDir, WalletPassword: walletPassword, @@ -291,6 +292,10 @@ func OpenWallet(_ context.Context, cfg *Config) (*Wallet, error) { return nil, errors.Wrap(err, "could not read keymanager kind for wallet") } accountsPath := filepath.Join(cfg.WalletDir, keymanagerKind.String()) + log.WithFields(logrus.Fields{ + "wallet": accountsPath, + "keymanagerKind": keymanagerKind.String(), + }).Info("Opened validator wallet") return &Wallet{ walletDir: cfg.WalletDir, accountsPath: accountsPath, diff --git a/validator/client/registration_test.go b/validator/client/registration_test.go index bd954317d2..fbfd036e78 100644 --- a/validator/client/registration_test.go +++ b/validator/client/registration_test.go @@ -173,7 +173,7 @@ func TestValidator_SignValidatorRegistrationRequest(t *testing.T) { v := validator{ pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, genesisTime: 0, } v.signedValidatorRegistrations[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())] = ðpb.SignedValidatorRegistrationV1{ @@ -201,7 +201,7 @@ func TestValidator_SignValidatorRegistrationRequest(t *testing.T) { v := validator{ pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, genesisTime: 0, } v.signedValidatorRegistrations[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())] = ðpb.SignedValidatorRegistrationV1{ @@ -229,7 +229,7 @@ func TestValidator_SignValidatorRegistrationRequest(t *testing.T) { v := validator{ pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, genesisTime: 0, } v.signedValidatorRegistrations[bytesutil.ToBytes48(validatorKey.PublicKey().Marshal())] = ðpb.SignedValidatorRegistrationV1{ @@ -257,7 +257,7 @@ func TestValidator_SignValidatorRegistrationRequest(t *testing.T) { v := validator{ pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, genesisTime: 0, } return &v diff --git a/validator/client/service.go b/validator/client/service.go index f9a1ce3ecd..58bdbca07d 100644 --- a/validator/client/service.go +++ b/validator/client/service.go @@ -54,7 +54,7 @@ type ValidatorService struct { web3SignerConfig *remoteweb3signer.SetupConfig proposerSettings *proposer.Settings validatorsRegBatchSize int - useWeb bool + enableAPI bool emitAccountMetrics bool logValidatorPerformance bool distributed bool @@ -80,7 +80,7 @@ type Config struct { Web3SignerConfig *remoteweb3signer.SetupConfig ProposerSettings *proposer.Settings ValidatorsRegBatchSize int - UseWeb bool + EnableAPI bool LogValidatorPerformance bool EmitAccountMetrics bool Distributed bool @@ -103,7 +103,7 @@ func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, e web3SignerConfig: cfg.Web3SignerConfig, proposerSettings: cfg.ProposerSettings, validatorsRegBatchSize: cfg.ValidatorsRegBatchSize, - useWeb: cfg.UseWeb, + enableAPI: cfg.EnableAPI, emitAccountMetrics: cfg.EmitAccountMetrics, logValidatorPerformance: cfg.LogValidatorPerformance, distributed: cfg.Distributed, @@ -215,7 +215,7 @@ func (v *ValidatorService) Start() { submittedAggregates: make(map[submittedAttKey]*submittedAtt), logValidatorPerformance: v.logValidatorPerformance, emitAccountMetrics: v.emitAccountMetrics, - useWeb: v.useWeb, + enableAPI: v.enableAPI, distributed: v.distributed, } diff --git a/validator/client/validator.go b/validator/client/validator.go index f6cad923b3..142ca8cf37 100644 --- a/validator/client/validator.go +++ b/validator/client/validator.go @@ -102,7 +102,7 @@ type validator struct { submittedAggregates map[submittedAttKey]*submittedAtt logValidatorPerformance bool emitAccountMetrics bool - useWeb bool + enableAPI bool distributed bool domainDataLock sync.RWMutex attLogsLock sync.Mutex @@ -140,33 +140,33 @@ func (v *validator) WaitForKeymanagerInitialization(ctx context.Context) error { return errors.Wrap(err, "unable to retrieve valid genesis validators root while initializing key manager") } - if v.useWeb && v.wallet == nil { - log.Info("Waiting for keymanager to initialize validator client with web UI") - // if wallet is not set, wait for it to be set through the UI + switch { + case v.wallet != nil: + if v.web3SignerConfig != nil { + v.web3SignerConfig.GenesisValidatorsRoot = genesisRoot + } + keyManager, err := v.wallet.InitializeKeymanager(ctx, accountsiface.InitKeymanagerConfig{ListenForChanges: true, Web3SignerConfig: v.web3SignerConfig}) + if err != nil { + return errors.Wrap(err, "could not initialize key manager") + } + v.km = keyManager + case v.interopKeysConfig != nil: + keyManager, err := local.NewInteropKeymanager(ctx, v.interopKeysConfig.Offset, v.interopKeysConfig.NumValidatorKeys) + if err != nil { + return errors.Wrap(err, "could not generate interop keys for key manager") + } + v.km = keyManager + case v.enableAPI: km, err := waitForWebWalletInitialization(ctx, v.walletInitializedFeed, v.walletInitializedChan) if err != nil { return err } v.km = km - } else { - if v.interopKeysConfig != nil { - keyManager, err := local.NewInteropKeymanager(ctx, v.interopKeysConfig.Offset, v.interopKeysConfig.NumValidatorKeys) - if err != nil { - return errors.Wrap(err, "could not generate interop keys for key manager") - } - v.km = keyManager - } else if v.wallet == nil { - return errors.New("wallet not set") - } else { - if v.web3SignerConfig != nil { - v.web3SignerConfig.GenesisValidatorsRoot = genesisRoot - } - keyManager, err := v.wallet.InitializeKeymanager(ctx, accountsiface.InitKeymanagerConfig{ListenForChanges: true, Web3SignerConfig: v.web3SignerConfig}) - if err != nil { - return errors.Wrap(err, "could not initialize key manager") - } - v.km = keyManager - } + default: + return wallet.ErrNoWalletFound + } + if v.km == nil { + return errors.New("key manager not set") } recheckKeys(ctx, v.db, v.km) return nil @@ -181,6 +181,7 @@ func waitForWebWalletInitialization( ctx, span := trace.StartSpan(ctx, "validator.waitForWebWalletInitialization") defer span.End() + log.Info("Waiting for keymanager to initialize validator client with web UI or /v2/validator/wallet/create REST api") sub := walletInitializedEvent.Subscribe(walletChan) defer sub.Unsubscribe() for { diff --git a/validator/client/validator_test.go b/validator/client/validator_test.go index a3adc64221..46211c1376 100644 --- a/validator/client/validator_test.go +++ b/validator/client/validator_test.go @@ -1311,9 +1311,9 @@ func TestValidator_WaitForKeymanagerInitialization_web3Signer(t *testing.T) { set.String(flags.WalletDirFlag.Name, newDir, "") w := wallet.NewWalletForWeb3Signer(cli.NewContext(&app, set, nil)) v := validator{ - db: db, - useWeb: false, - wallet: w, + db: db, + enableAPI: false, + wallet: w, web3SignerConfig: &remoteweb3signer.SetupConfig{ BaseEndpoint: "http://localhost:8545", ProvidedPublicKeys: []string{"0xa2b5aaad9c6efefe7bb9b1243a043404f3362937cfb6b31833929833173f476630ea2cfeb0d9ddf15f97ca8685948820"}, @@ -1340,7 +1340,7 @@ func TestValidator_WaitForKeymanagerInitialization_Web(t *testing.T) { walletChan := make(chan *wallet.Wallet, 1) v := validator{ db: db, - useWeb: true, + enableAPI: true, walletInitializedFeed: &event.Feed{}, walletInitializedChan: walletChan, } @@ -1372,8 +1372,8 @@ func TestValidator_WaitForKeymanagerInitialization_Interop(t *testing.T) { err := db.SaveGenesisValidatorsRoot(ctx, root) require.NoError(t, err) v := validator{ - db: db, - useWeb: false, + db: db, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 2, Offset: 1, @@ -1460,7 +1460,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 2, Offset: 1, @@ -1551,7 +1551,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 2, Offset: 1, @@ -1637,7 +1637,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 2, Offset: 1, @@ -1707,7 +1707,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 1, Offset: 1, @@ -1780,7 +1780,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 1, Offset: 1, @@ -1849,7 +1849,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 1, Offset: 1, @@ -1906,7 +1906,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 1, Offset: 1, @@ -1953,7 +1953,7 @@ func TestValidator_PushSettings(t *testing.T) { db: db, pubkeyToStatus: make(map[[fieldparams.BLSPubkeyLength]byte]*validatorStatus), signedValidatorRegistrations: make(map[[fieldparams.BLSPubkeyLength]byte]*ethpb.SignedValidatorRegistrationV1), - useWeb: false, + enableAPI: false, interopKeysConfig: &local.InteropKeymanagerConfig{ NumValidatorKeys: 1, Offset: 1, diff --git a/validator/node/BUILD.bazel b/validator/node/BUILD.bazel index af4c9fa675..d5702728d3 100644 --- a/validator/node/BUILD.bazel +++ b/validator/node/BUILD.bazel @@ -33,7 +33,6 @@ go_library( "//validator:__subpackages__", ], deps = [ - "//api:go_default_library", "//api/server/middleware:go_default_library", "//async/event:go_default_library", "//cmd:go_default_library", diff --git a/validator/node/node.go b/validator/node/node.go index f7ad9bf56c..95592843bf 100644 --- a/validator/node/node.go +++ b/validator/node/node.go @@ -18,7 +18,6 @@ import ( "time" "github.com/pkg/errors" - "github.com/prysmaticlabs/prysm/v5/api" "github.com/prysmaticlabs/prysm/v5/api/server/middleware" "github.com/prysmaticlabs/prysm/v5/async/event" "github.com/prysmaticlabs/prysm/v5/cmd" @@ -86,17 +85,6 @@ func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) { // Warn if user's platform is not supported prereqs.WarnIfPlatformNotSupported(cliCtx.Context) - registry := runtime.NewServiceRegistry() - ctx, cancel := context.WithCancel(cliCtx.Context) - validatorClient := &ValidatorClient{ - cliCtx: cliCtx, - ctx: ctx, - cancel: cancel, - services: registry, - walletInitializedFeed: new(event.Feed), - stop: make(chan struct{}), - } - if err := features.ConfigureValidator(cliCtx); err != nil { return nil, err } @@ -111,23 +99,28 @@ func NewValidatorClient(cliCtx *cli.Context) (*ValidatorClient, error) { } } - // initialize router used for endpoints - router := http.NewServeMux() - // If the --web flag is enabled to administer the validator - // client via a web portal, we start the validator client in a different way. - // Change Web flag name to enable keymanager API, look at merging initializeFromCLI and initializeForWeb maybe after WebUI DEPRECATED. - if cliCtx.IsSet(flags.EnableWebFlag.Name) { - if cliCtx.IsSet(flags.Web3SignerURLFlag.Name) || cliCtx.IsSet(flags.Web3SignerPublicValidatorKeysFlag.Name) { - log.Warn("Remote Keymanager API enabled. Prysm web does not properly support web3signer at this time") - } - log.Info("Enabling web portal to manage the validator client") - if err := validatorClient.initializeForWeb(cliCtx, router); err != nil { - return nil, err - } - return validatorClient, nil + w, err := getWallet(cliCtx) + if err != nil { + return nil, err } - if err := validatorClient.initializeFromCLI(cliCtx, router); err != nil { + registry := runtime.NewServiceRegistry() + ctx, cancel := context.WithCancel(cliCtx.Context) + validatorClient := &ValidatorClient{ + cliCtx: cliCtx, + ctx: ctx, + cancel: cancel, + services: registry, + wallet: w, + walletInitializedFeed: new(event.Feed), + stop: make(chan struct{}), + } + + if err := validatorClient.initializeDB(cliCtx); err != nil { + return nil, errors.Wrapf(err, "could not initialize database") + } + + if err := validatorClient.registerServices(cliCtx); err != nil { return nil, err } @@ -228,93 +221,40 @@ func (c *ValidatorClient) getLegacyDatabaseLocation( return dataDir, dataFile, nil } -func (c *ValidatorClient) initializeFromCLI(cliCtx *cli.Context, router *http.ServeMux) error { - isInteropNumValidatorsSet := cliCtx.IsSet(flags.InteropNumValidators.Name) - isWeb3SignerURLFlagSet := cliCtx.IsSet(flags.Web3SignerURLFlag.Name) - - if !isInteropNumValidatorsSet { - // Custom Check For Web3Signer - if isWeb3SignerURLFlagSet { - c.wallet = wallet.NewWalletForWeb3Signer(cliCtx) - } else { - w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { - return nil, wallet.ErrNoWalletFound - }) - if err != nil { - return errors.Wrap(err, "could not open wallet") - } - c.wallet = w - // TODO(#9883) - Remove this when we have a better way to handle this. - log.WithFields(logrus.Fields{ - "wallet": w.AccountsDir(), - "keymanagerKind": w.KeymanagerKind().String(), - }).Info("Opened validator wallet") - } +func getWallet(cliCtx *cli.Context) (*wallet.Wallet, error) { + if cliCtx.IsSet(flags.InteropNumValidators.Name) { + log.Info("no wallet required for interop validation") + return nil, nil } - - if err := c.initializeDB(cliCtx); err != nil { - return errors.Wrapf(err, "could not initialize database") + if cliCtx.IsSet(flags.Web3SignerURLFlag.Name) { + return wallet.NewWalletForWeb3Signer(cliCtx), nil } - - if !cliCtx.Bool(cmd.DisableMonitoringFlag.Name) { - if err := c.registerPrometheusService(cliCtx); err != nil { - return err - } + if err := setWalletPasswordFilePath(cliCtx); err != nil { + return nil, errors.Wrap(err, "could not read wallet password file") } - if err := c.registerValidatorService(cliCtx); err != nil { - return err + w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { + // handle nil wallet in key manager initialization, give a chance for user to create a wallet + return nil, nil + }) + if err != nil { + return nil, errors.Wrap(err, "could not open wallet") } - if cliCtx.Bool(flags.EnableRPCFlag.Name) { - if err := c.registerRPCService(router); err != nil { - return err - } - } - return nil + return w, nil } -func (c *ValidatorClient) initializeForWeb(cliCtx *cli.Context, router *http.ServeMux) error { - if cliCtx.IsSet(flags.Web3SignerURLFlag.Name) { - // Custom Check For Web3Signer - c.wallet = wallet.NewWalletForWeb3Signer(cliCtx) - } else { - // Read the wallet password file from the cli context. - if err := setWalletPasswordFilePath(cliCtx); err != nil { - return errors.Wrap(err, "could not read wallet password file") - } - - // Read the wallet from the specified path. - w, err := wallet.OpenWalletOrElseCli(cliCtx, func(cliCtx *cli.Context) (*wallet.Wallet, error) { - return nil, nil - }) - if err != nil { - return errors.Wrap(err, "could not open wallet") - } - c.wallet = w +func (c *ValidatorClient) registerServices(cliCtx *cli.Context) error { + if err := c.registerPrometheusService(cliCtx); err != nil { + return errors.Wrapf(err, "could not register prometheus service") } - if err := c.initializeDB(cliCtx); err != nil { - return errors.Wrapf(err, "could not initialize database") - } - - if !cliCtx.Bool(cmd.DisableMonitoringFlag.Name) { - if err := c.registerPrometheusService(cliCtx); err != nil { - return err - } - } if err := c.registerValidatorService(cliCtx); err != nil { - return err + return errors.Wrapf(err, "could not register validator service") } - if err := c.registerRPCService(router); err != nil { - return err + if err := c.registerRPCService(cliCtx); err != nil { + return errors.Wrapf(err, "could not register RPC service") } - host := cliCtx.String(flags.HTTPServerHost.Name) - port := cliCtx.Int(flags.HTTPServerPort.Name) - webAddress := fmt.Sprintf("http://%s:%d", host, port) - log.WithField("address", webAddress).Info( - "Starting Prysm web UI on address, open in browser to access", - ) return nil } @@ -432,6 +372,10 @@ func (c *ValidatorClient) initializeDB(cliCtx *cli.Context) error { } func (c *ValidatorClient) registerPrometheusService(cliCtx *cli.Context) error { + if cliCtx.Bool(cmd.DisableMonitoringFlag.Name) { + log.Info("Prometheus service disabled") + return nil + } var additionalHandlers []prometheus.Handler if cliCtx.IsSet(cmd.EnableBackupWebhookFlag.Name) { additionalHandlers = append( @@ -443,7 +387,7 @@ func (c *ValidatorClient) registerPrometheusService(cliCtx *cli.Context) error { ) } service := prometheus.NewService( - fmt.Sprintf("%s:%d", c.cliCtx.String(cmd.MonitoringHostFlag.Name), c.cliCtx.Int(flags.MonitoringPortFlag.Name)), + fmt.Sprintf("%s:%d", cliCtx.String(cmd.MonitoringHostFlag.Name), cliCtx.Int(flags.MonitoringPortFlag.Name)), c.services, additionalHandlers..., ) @@ -458,7 +402,7 @@ func (c *ValidatorClient) registerValidatorService(cliCtx *cli.Context) error { ) // Configure interop. - if c.cliCtx.IsSet(flags.InteropNumValidators.Name) { + if cliCtx.IsSet(flags.InteropNumValidators.Name) { interopKmConfig = &local.InteropKeymanagerConfig{ Offset: cliCtx.Uint64(flags.InteropStartIndex.Name), NumValidatorKeys: cliCtx.Uint64(flags.InteropNumValidators.Name), @@ -467,8 +411,8 @@ func (c *ValidatorClient) registerValidatorService(cliCtx *cli.Context) error { // Configure graffiti. graffitiStruct := &g.Graffiti{} - if c.cliCtx.IsSet(flags.GraffitiFileFlag.Name) { - graffitiFilePath := c.cliCtx.String(flags.GraffitiFileFlag.Name) + if cliCtx.IsSet(flags.GraffitiFileFlag.Name) { + graffitiFilePath := cliCtx.String(flags.GraffitiFileFlag.Name) graffitiStruct, err = g.ParseGraffitiFile(graffitiFilePath) if err != nil { @@ -476,38 +420,38 @@ func (c *ValidatorClient) registerValidatorService(cliCtx *cli.Context) error { } } - web3signerConfig, err := Web3SignerConfig(c.cliCtx) + web3signerConfig, err := Web3SignerConfig(cliCtx) if err != nil { return err } - ps, err := proposerSettings(c.cliCtx, c.db) + ps, err := proposerSettings(cliCtx, c.db) if err != nil { return err } - validatorService, err := client.NewValidatorService(c.cliCtx.Context, &client.Config{ + validatorService, err := client.NewValidatorService(cliCtx.Context, &client.Config{ DB: c.db, Wallet: c.wallet, WalletInitializedFeed: c.walletInitializedFeed, - GRPCMaxCallRecvMsgSize: c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name), - GRPCRetries: c.cliCtx.Uint(flags.GRPCRetriesFlag.Name), - GRPCRetryDelay: c.cliCtx.Duration(flags.GRPCRetryDelayFlag.Name), - GRPCHeaders: strings.Split(c.cliCtx.String(flags.GRPCHeadersFlag.Name), ","), - BeaconNodeGRPCEndpoint: c.cliCtx.String(flags.BeaconRPCProviderFlag.Name), - BeaconNodeCert: c.cliCtx.String(flags.CertFlag.Name), - BeaconApiEndpoint: c.cliCtx.String(flags.BeaconRESTApiProviderFlag.Name), + GRPCMaxCallRecvMsgSize: cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name), + GRPCRetries: cliCtx.Uint(flags.GRPCRetriesFlag.Name), + GRPCRetryDelay: cliCtx.Duration(flags.GRPCRetryDelayFlag.Name), + GRPCHeaders: strings.Split(cliCtx.String(flags.GRPCHeadersFlag.Name), ","), + BeaconNodeGRPCEndpoint: cliCtx.String(flags.BeaconRPCProviderFlag.Name), + BeaconNodeCert: cliCtx.String(flags.CertFlag.Name), + BeaconApiEndpoint: cliCtx.String(flags.BeaconRESTApiProviderFlag.Name), BeaconApiTimeout: time.Second * 30, - Graffiti: g.ParseHexGraffiti(c.cliCtx.String(flags.GraffitiFlag.Name)), + Graffiti: g.ParseHexGraffiti(cliCtx.String(flags.GraffitiFlag.Name)), GraffitiStruct: graffitiStruct, InteropKmConfig: interopKmConfig, Web3SignerConfig: web3signerConfig, ProposerSettings: ps, - ValidatorsRegBatchSize: c.cliCtx.Int(flags.ValidatorsRegistrationBatchSizeFlag.Name), - UseWeb: c.cliCtx.Bool(flags.EnableWebFlag.Name), - LogValidatorPerformance: !c.cliCtx.Bool(flags.DisablePenaltyRewardLogFlag.Name), - EmitAccountMetrics: !c.cliCtx.Bool(flags.DisableAccountMetricsFlag.Name), - Distributed: c.cliCtx.Bool(flags.EnableDistributed.Name), + ValidatorsRegBatchSize: cliCtx.Int(flags.ValidatorsRegistrationBatchSizeFlag.Name), + EnableAPI: cliCtx.Bool(flags.EnableWebFlag.Name) || cliCtx.Bool(flags.EnableRPCFlag.Name), + LogValidatorPerformance: !cliCtx.Bool(flags.DisablePenaltyRewardLogFlag.Name), + EmitAccountMetrics: !cliCtx.Bool(flags.DisableAccountMetricsFlag.Name), + Distributed: cliCtx.Bool(flags.EnableDistributed.Name), }) if err != nil { return errors.Wrap(err, "could not initialize validator service") @@ -567,32 +511,36 @@ func proposerSettings(cliCtx *cli.Context, db iface.ValidatorDB) (*proposer.Sett return l.Load(cliCtx) } -func (c *ValidatorClient) registerRPCService(router *http.ServeMux) error { +func (c *ValidatorClient) registerRPCService(cliCtx *cli.Context) error { + serveWebUI := cliCtx.IsSet(flags.EnableWebFlag.Name) + if !cliCtx.IsSet(flags.EnableRPCFlag.Name) && !serveWebUI { + return nil + } + host := cliCtx.String(flags.HTTPServerHost.Name) + port := cliCtx.Int(flags.HTTPServerPort.Name) + authTokenPath := cliCtx.String(flags.AuthTokenPathFlag.Name) + walletDir := cliCtx.String(flags.WalletDirFlag.Name) + var vs *client.ValidatorService if err := c.services.FetchService(&vs); err != nil { return err } - authTokenPath := c.cliCtx.String(flags.AuthTokenPathFlag.Name) - walletDir := c.cliCtx.String(flags.WalletDirFlag.Name) - // if no auth token path flag was passed try to set a default value - if authTokenPath == "" { - authTokenPath = flags.AuthTokenPathFlag.Value - // if a wallet dir is passed without an auth token then override the default with the wallet dir - if walletDir != "" { - authTokenPath = filepath.Join(walletDir, api.AuthTokenFileName) + + if serveWebUI { + if cliCtx.IsSet(flags.Web3SignerURLFlag.Name) || cliCtx.IsSet(flags.Web3SignerPublicValidatorKeysFlag.Name) { + log.Warn("Remote Keymanager API enabled. Prysm web does not properly support web3signer at this time") } } - host := c.cliCtx.String(flags.HTTPServerHost.Name) + if host != flags.DefaultHTTPServerHost { log.WithField("webHost", host).Warn( "You are using a non-default web host. Web traffic is served by HTTP, so be wary of " + "changing this parameter if you are exposing this host to the Internet!", ) } - port := c.cliCtx.Int(flags.HTTPServerPort.Name) var allowedOrigins []string - if c.cliCtx.IsSet(flags.HTTPServerCorsDomain.Name) { - allowedOrigins = strings.Split(c.cliCtx.String(flags.HTTPServerCorsDomain.Name), ",") + if cliCtx.IsSet(flags.HTTPServerCorsDomain.Name) { + allowedOrigins = strings.Split(cliCtx.String(flags.HTTPServerCorsDomain.Name), ",") } else { allowedOrigins = strings.Split(flags.HTTPServerCorsDomain.Value, ",") } @@ -601,17 +549,17 @@ func (c *ValidatorClient) registerRPCService(router *http.ServeMux) error { middleware.NormalizeQueryValuesHandler, middleware.CorsHandler(allowedOrigins), } - s := rpc.NewServer(c.cliCtx.Context, &rpc.Config{ + s := rpc.NewServer(cliCtx.Context, &rpc.Config{ HTTPHost: host, HTTPPort: port, - GRPCMaxCallRecvMsgSize: c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name), - GRPCRetries: c.cliCtx.Uint(flags.GRPCRetriesFlag.Name), - GRPCRetryDelay: c.cliCtx.Duration(flags.GRPCRetryDelayFlag.Name), - GRPCHeaders: strings.Split(c.cliCtx.String(flags.GRPCHeadersFlag.Name), ","), - BeaconNodeGRPCEndpoint: c.cliCtx.String(flags.BeaconRPCProviderFlag.Name), - BeaconApiEndpoint: c.cliCtx.String(flags.BeaconRESTApiProviderFlag.Name), + GRPCMaxCallRecvMsgSize: cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name), + GRPCRetries: cliCtx.Uint(flags.GRPCRetriesFlag.Name), + GRPCRetryDelay: cliCtx.Duration(flags.GRPCRetryDelayFlag.Name), + GRPCHeaders: strings.Split(cliCtx.String(flags.GRPCHeadersFlag.Name), ","), + BeaconNodeGRPCEndpoint: cliCtx.String(flags.BeaconRPCProviderFlag.Name), + BeaconApiEndpoint: cliCtx.String(flags.BeaconRESTApiProviderFlag.Name), BeaconApiTimeout: time.Second * 30, - BeaconNodeCert: c.cliCtx.String(flags.CertFlag.Name), + BeaconNodeCert: cliCtx.String(flags.CertFlag.Name), DB: c.db, Wallet: c.wallet, WalletDir: walletDir, @@ -619,7 +567,8 @@ func (c *ValidatorClient) registerRPCService(router *http.ServeMux) error { ValidatorService: vs, AuthTokenPath: authTokenPath, Middlewares: middlewares, - Router: router, + Router: http.NewServeMux(), + ServeWebUI: serveWebUI, }) return c.services.RegisterService(s) } diff --git a/validator/rpc/auth_token.go b/validator/rpc/auth_token.go index df67fae079..a0357afaf7 100644 --- a/validator/rpc/auth_token.go +++ b/validator/rpc/auth_token.go @@ -32,7 +32,7 @@ func CreateAuthToken(authPath, validatorWebAddr string) error { if err := saveAuthToken(authPath, token); err != nil { return err } - logValidatorWebAuth(validatorWebAddr, token, authPath) + logValidatorWebAuth(true, validatorWebAddr, token, authPath) return nil } @@ -105,7 +105,7 @@ func (s *Server) refreshAuthTokenFromFileChanges(ctx context.Context, authTokenP continue } validatorWebAddr := fmt.Sprintf("%s:%d", s.httpHost, s.httpPort) - logValidatorWebAuth(validatorWebAddr, s.authToken, authTokenPath) + logValidatorWebAuth(s.serveWebUI, validatorWebAddr, s.authToken, authTokenPath) case err := <-watcher.Errors: log.WithError(err).Errorf("Could not watch for file changes for: %s", authTokenPath) case <-ctx.Done(): @@ -114,18 +114,19 @@ func (s *Server) refreshAuthTokenFromFileChanges(ctx context.Context, authTokenP } } -func logValidatorWebAuth(validatorWebAddr, token, tokenPath string) { - webAuthURLTemplate := "http://%s/initialize?token=%s" - webAuthURL := fmt.Sprintf( - webAuthURLTemplate, - validatorWebAddr, - url.QueryEscape(token), - ) - log.Infof( - "Once your validator process is running, navigate to the link below to authenticate with " + - "the Prysm web interface", - ) - log.Info(webAuthURL) +func logValidatorWebAuth(useWeb bool, validatorWebAddr, token, tokenPath string) { + if useWeb { + webAuthURLTemplate := "http://%s/initialize?token=%s" + webAuthURL := fmt.Sprintf( + webAuthURLTemplate, + validatorWebAddr, + url.QueryEscape(token), + ) + log.Infof( + "Starting Prysm WebUI, once your validator process is running, navigate to the link below to authenticate", + ) + log.Info(webAuthURL) + } log.Infof("Validator Client auth token for gRPC and REST authentication set at %s", tokenPath) } diff --git a/validator/rpc/server.go b/validator/rpc/server.go index f623faf06f..b760f6117a 100644 --- a/validator/rpc/server.go +++ b/validator/rpc/server.go @@ -43,40 +43,42 @@ type Config struct { AuthTokenPath string Middlewares []middleware.Middleware Router *http.ServeMux + ServeWebUI bool } // Server defining a HTTP server for the remote signer API and registering clients type Server struct { - ctx context.Context - cancel context.CancelFunc - httpHost string - httpPort int - server *httprest.Server + serveWebUI bool + walletInitialized bool + logStreamerBufferSize int grpcMaxCallRecvMsgSize int + walletInitializedFeed *event.Feed + beaconApiTimeout time.Duration + wallet *wallet.Wallet + validatorService *client.ValidatorService + httpPort int + cancel context.CancelFunc grpcRetries uint grpcRetryDelay time.Duration - grpcHeaders []string - beaconNodeValidatorClient iface.ValidatorClient - chainClient iface.ChainClient - nodeClient iface.NodeClient - healthClient ethpb.HealthClient - beaconNodeEndpoint string - beaconApiEndpoint string - beaconApiTimeout time.Duration - beaconNodeCert string - jwtSecret []byte + server *httprest.Server + router *http.ServeMux authTokenPath string + beaconNodeCert string + beaconApiEndpoint string + beaconNodeEndpoint string + healthClient ethpb.HealthClient + nodeClient iface.NodeClient + chainClient iface.ChainClient + beaconNodeValidatorClient iface.ValidatorClient + httpHost string authToken string db db.Database - walletDir string - wallet *wallet.Wallet - walletInitializedFeed *event.Feed - walletInitialized bool - validatorService *client.ValidatorService - router *http.ServeMux logStreamer logs.Streamer - logStreamerBufferSize int startFailure error + ctx context.Context + walletDir string + jwtSecret []byte + grpcHeaders []string } // NewServer instantiates a new HTTP server. @@ -104,9 +106,11 @@ func NewServer(ctx context.Context, cfg *Config) *Server { beaconApiEndpoint: cfg.BeaconApiEndpoint, beaconNodeEndpoint: cfg.BeaconNodeGRPCEndpoint, router: cfg.Router, + serveWebUI: cfg.ServeWebUI, } if server.authTokenPath == "" && server.walletDir != "" { + // if a wallet dir is passed without an auth token then override the default with the wallet dir server.authTokenPath = filepath.Join(server.walletDir, api.AuthTokenFileName) } @@ -115,9 +119,10 @@ func NewServer(ctx context.Context, cfg *Config) *Server { log.WithError(err).Error("Could not initialize web auth token") } validatorWebAddr := fmt.Sprintf("%s:%d", server.httpHost, server.httpPort) - logValidatorWebAuth(validatorWebAddr, server.authToken, server.authTokenPath) + logValidatorWebAuth(server.serveWebUI, validatorWebAddr, server.authToken, server.authTokenPath) go server.refreshAuthTokenFromFileChanges(server.ctx, server.authTokenPath) } + // Register a gRPC or HTTP client to the beacon node. // Used for proxy calls to beacon node from validator REST handlers if err := server.registerBeaconClient(); err != nil { @@ -159,8 +164,9 @@ func (s *Server) InitializeRoutesWithWebHandler() error { if strings.HasPrefix(r.URL.Path, "/api") { r.URL.Path = strings.Replace(r.URL.Path, "/api", "", 1) // used to redirect apis to standard rest APIs s.router.ServeHTTP(w, r) - } else { - // Finally, we handle with the web server. + return + } + if s.serveWebUI { web.Handler(w, r) } })