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
This commit is contained in:
james-prysm
2025-03-28 09:03:42 -05:00
committed by GitHub
parent 70aaad1904
commit e3fb4e86ec
10 changed files with 192 additions and 228 deletions

View File

@@ -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.

View File

@@ -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,

View File

@@ -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())] = &ethpb.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())] = &ethpb.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())] = &ethpb.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

View File

@@ -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,
}

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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",

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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)
}
})