github.com/prysmaticlabs/prysm@v1.4.4/validator/rpc/server.go (about) 1 package rpc 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "net" 8 "time" 9 10 middleware "github.com/grpc-ecosystem/go-grpc-middleware" 11 recovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" 12 grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" 13 grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" 14 healthpb "github.com/prysmaticlabs/prysm/proto/beacon/rpc/v1" 15 ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1" 16 pb "github.com/prysmaticlabs/prysm/proto/validator/accounts/v2" 17 "github.com/prysmaticlabs/prysm/shared/event" 18 "github.com/prysmaticlabs/prysm/shared/logutil" 19 "github.com/prysmaticlabs/prysm/shared/rand" 20 "github.com/prysmaticlabs/prysm/shared/traceutil" 21 "github.com/prysmaticlabs/prysm/validator/accounts/wallet" 22 "github.com/prysmaticlabs/prysm/validator/client" 23 "github.com/prysmaticlabs/prysm/validator/db" 24 "github.com/prysmaticlabs/prysm/validator/keymanager" 25 "github.com/sirupsen/logrus" 26 "go.opencensus.io/plugin/ocgrpc" 27 "google.golang.org/grpc" 28 "google.golang.org/grpc/credentials" 29 "google.golang.org/grpc/reflection" 30 ) 31 32 // Config options for the gRPC server. 33 type Config struct { 34 ValidatorGatewayHost string 35 ValidatorGatewayPort int 36 ValidatorMonitoringHost string 37 ValidatorMonitoringPort int 38 BeaconClientEndpoint string 39 ClientMaxCallRecvMsgSize int 40 ClientGrpcRetries uint 41 ClientGrpcRetryDelay time.Duration 42 ClientGrpcHeaders []string 43 ClientWithCert string 44 Host string 45 Port string 46 CertFlag string 47 KeyFlag string 48 ValDB db.Database 49 WalletDir string 50 ValidatorService *client.ValidatorService 51 SyncChecker client.SyncChecker 52 GenesisFetcher client.GenesisFetcher 53 WalletInitializedFeed *event.Feed 54 NodeGatewayEndpoint string 55 Wallet *wallet.Wallet 56 Keymanager keymanager.IKeymanager 57 } 58 59 // Server defining a gRPC server for the remote signer API. 60 type Server struct { 61 logsStreamer logutil.Streamer 62 streamLogsBufferSize int 63 beaconChainClient ethpb.BeaconChainClient 64 beaconNodeClient ethpb.NodeClient 65 beaconNodeValidatorClient ethpb.BeaconNodeValidatorClient 66 beaconNodeHealthClient healthpb.HealthClient 67 valDB db.Database 68 ctx context.Context 69 cancel context.CancelFunc 70 beaconClientEndpoint string 71 clientMaxCallRecvMsgSize int 72 clientGrpcRetries uint 73 clientGrpcRetryDelay time.Duration 74 clientGrpcHeaders []string 75 clientWithCert string 76 host string 77 port string 78 listener net.Listener 79 keymanager keymanager.IKeymanager 80 withCert string 81 withKey string 82 credentialError error 83 grpcServer *grpc.Server 84 jwtKey []byte 85 validatorService *client.ValidatorService 86 syncChecker client.SyncChecker 87 genesisFetcher client.GenesisFetcher 88 walletDir string 89 wallet *wallet.Wallet 90 walletInitializedFeed *event.Feed 91 walletInitialized bool 92 nodeGatewayEndpoint string 93 validatorMonitoringHost string 94 validatorMonitoringPort int 95 validatorGatewayHost string 96 validatorGatewayPort int 97 } 98 99 // NewServer instantiates a new gRPC server. 100 func NewServer(ctx context.Context, cfg *Config) *Server { 101 ctx, cancel := context.WithCancel(ctx) 102 return &Server{ 103 ctx: ctx, 104 cancel: cancel, 105 logsStreamer: logutil.NewStreamServer(), 106 streamLogsBufferSize: 1000, // Enough to handle most bursts of logs in the validator client. 107 host: cfg.Host, 108 port: cfg.Port, 109 withCert: cfg.CertFlag, 110 withKey: cfg.KeyFlag, 111 beaconClientEndpoint: cfg.BeaconClientEndpoint, 112 clientMaxCallRecvMsgSize: cfg.ClientMaxCallRecvMsgSize, 113 clientGrpcRetries: cfg.ClientGrpcRetries, 114 clientGrpcRetryDelay: cfg.ClientGrpcRetryDelay, 115 clientGrpcHeaders: cfg.ClientGrpcHeaders, 116 clientWithCert: cfg.ClientWithCert, 117 valDB: cfg.ValDB, 118 validatorService: cfg.ValidatorService, 119 syncChecker: cfg.SyncChecker, 120 genesisFetcher: cfg.GenesisFetcher, 121 walletDir: cfg.WalletDir, 122 walletInitializedFeed: cfg.WalletInitializedFeed, 123 walletInitialized: cfg.Wallet != nil, 124 wallet: cfg.Wallet, 125 keymanager: cfg.Keymanager, 126 nodeGatewayEndpoint: cfg.NodeGatewayEndpoint, 127 validatorMonitoringHost: cfg.ValidatorMonitoringHost, 128 validatorMonitoringPort: cfg.ValidatorMonitoringPort, 129 validatorGatewayHost: cfg.ValidatorGatewayHost, 130 validatorGatewayPort: cfg.ValidatorGatewayPort, 131 } 132 } 133 134 // Start the gRPC server. 135 func (s *Server) Start() { 136 // Setup the gRPC server options and TLS configuration. 137 address := fmt.Sprintf("%s:%s", s.host, s.port) 138 lis, err := net.Listen("tcp", address) 139 if err != nil { 140 log.Errorf("Could not listen to port in Start() %s: %v", address, err) 141 } 142 s.listener = lis 143 144 // Register interceptors for metrics gathering as well as our 145 // own, custom JWT unary interceptor. 146 opts := []grpc.ServerOption{ 147 grpc.StatsHandler(&ocgrpc.ServerHandler{}), 148 grpc.UnaryInterceptor(middleware.ChainUnaryServer( 149 recovery.UnaryServerInterceptor( 150 recovery.WithRecoveryHandlerContext(traceutil.RecoveryHandlerFunc), 151 ), 152 grpc_prometheus.UnaryServerInterceptor, 153 grpc_opentracing.UnaryServerInterceptor(), 154 s.JWTInterceptor(), 155 )), 156 } 157 grpc_prometheus.EnableHandlingTimeHistogram() 158 159 if s.withCert != "" && s.withKey != "" { 160 creds, err := credentials.NewServerTLSFromFile(s.withCert, s.withKey) 161 if err != nil { 162 log.WithError(err).Fatal("Could not load TLS keys") 163 } 164 opts = append(opts, grpc.Creds(creds)) 165 log.WithFields(logrus.Fields{ 166 "crt-path": s.withCert, 167 "key-path": s.withKey, 168 }).Info("Loaded TLS certificates") 169 } 170 s.grpcServer = grpc.NewServer(opts...) 171 172 // Register a gRPC client to the beacon node. 173 if err := s.registerBeaconClient(); err != nil { 174 log.WithError(err).Fatal("Could not register beacon chain gRPC client") 175 } 176 177 // We create a new, random JWT key upon validator startup. 178 jwtKey, err := createRandomJWTKey() 179 if err != nil { 180 log.WithError(err).Fatal("Could not initialize validator jwt key") 181 } 182 s.jwtKey = jwtKey 183 184 // Register services available for the gRPC server. 185 reflection.Register(s.grpcServer) 186 pb.RegisterAuthServer(s.grpcServer, s) 187 pb.RegisterWalletServer(s.grpcServer, s) 188 pb.RegisterHealthServer(s.grpcServer, s) 189 pb.RegisterBeaconServer(s.grpcServer, s) 190 pb.RegisterAccountsServer(s.grpcServer, s) 191 pb.RegisterSlashingProtectionServer(s.grpcServer, s) 192 193 go func() { 194 if s.listener != nil { 195 if err := s.grpcServer.Serve(s.listener); err != nil { 196 log.Errorf("Could not serve: %v", err) 197 } 198 } 199 }() 200 go s.checkUserSignup(s.ctx) 201 log.WithField("address", address).Info("gRPC server listening on address") 202 } 203 204 // Stop the gRPC server. 205 func (s *Server) Stop() error { 206 s.cancel() 207 if s.listener != nil { 208 s.grpcServer.GracefulStop() 209 log.Debug("Initiated graceful stop of server") 210 } 211 return nil 212 } 213 214 // Status returns nil or credentialError. 215 func (s *Server) Status() error { 216 return s.credentialError 217 } 218 219 func createRandomJWTKey() ([]byte, error) { 220 r := rand.NewGenerator() 221 jwtKey := make([]byte, 32) 222 n, err := r.Read(jwtKey) 223 if err != nil { 224 return nil, err 225 } 226 if n != len(jwtKey) { 227 return nil, errors.New("could not create appropriately sized random JWT key") 228 } 229 return jwtKey, nil 230 }