github.com/prysmaticlabs/prysm@v1.4.4/validator/slashing-protection/slasher_client.go (about) 1 package slashingprotection 2 3 import ( 4 "context" 5 "errors" 6 "fmt" 7 "strings" 8 "time" 9 10 middleware "github.com/grpc-ecosystem/go-grpc-middleware" 11 grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry" 12 grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing" 13 grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus" 14 ethsl "github.com/prysmaticlabs/prysm/proto/slashing" 15 "github.com/prysmaticlabs/prysm/shared/grpcutils" 16 "go.opencensus.io/plugin/ocgrpc" 17 "google.golang.org/grpc" 18 "google.golang.org/grpc/connectivity" 19 "google.golang.org/grpc/credentials" 20 ) 21 22 // Service represents a service to manage the validator 23 // slashing protection. 24 type Service struct { 25 cfg *Config 26 ctx context.Context 27 cancel context.CancelFunc 28 conn *grpc.ClientConn 29 grpcHeaders []string 30 slasherClient ethsl.SlasherClient 31 } 32 33 // Config for the validator service. 34 type Config struct { 35 Endpoint string 36 CertFlag string 37 GrpcMaxCallRecvMsgSizeFlag int 38 GrpcRetriesFlag uint 39 GrpcRetryDelay time.Duration 40 GrpcHeadersFlag string 41 } 42 43 // NewService creates a new validator service for the service 44 // registry. 45 func NewService(ctx context.Context, cfg *Config) (*Service, error) { 46 ctx, cancel := context.WithCancel(ctx) 47 return &Service{ 48 cfg: cfg, 49 ctx: ctx, 50 cancel: cancel, 51 grpcHeaders: strings.Split(cfg.GrpcHeadersFlag, ","), 52 }, nil 53 } 54 55 // Start the slasher protection service and grpc client. 56 func (s *Service) Start() { 57 if s.cfg.Endpoint != "" { 58 s.slasherClient = s.startSlasherClient() 59 } 60 } 61 62 func (s *Service) startSlasherClient() ethsl.SlasherClient { 63 var dialOpt grpc.DialOption 64 65 if s.cfg.CertFlag != "" { 66 creds, err := credentials.NewClientTLSFromFile(s.cfg.CertFlag, "") 67 if err != nil { 68 log.Errorf("Could not get valid slasher credentials: %v", err) 69 return nil 70 } 71 dialOpt = grpc.WithTransportCredentials(creds) 72 } else { 73 dialOpt = grpc.WithInsecure() 74 log.Warn("You are using an insecure slasher gRPC connection! Please provide a certificate and key to use a secure connection.") 75 } 76 77 s.ctx = grpcutils.AppendHeaders(s.ctx, s.grpcHeaders) 78 79 opts := []grpc.DialOption{ 80 dialOpt, 81 grpc.WithDefaultCallOptions( 82 grpc_retry.WithMax(s.cfg.GrpcRetriesFlag), 83 grpc_retry.WithBackoff(grpc_retry.BackoffLinear(s.cfg.GrpcRetryDelay)), 84 ), 85 grpc.WithStatsHandler(&ocgrpc.ClientHandler{}), 86 grpc.WithStreamInterceptor(middleware.ChainStreamClient( 87 grpc_opentracing.StreamClientInterceptor(), 88 grpc_prometheus.StreamClientInterceptor, 89 grpc_retry.StreamClientInterceptor(), 90 )), 91 grpc.WithUnaryInterceptor(middleware.ChainUnaryClient( 92 grpc_opentracing.UnaryClientInterceptor(), 93 grpc_prometheus.UnaryClientInterceptor, 94 grpc_retry.UnaryClientInterceptor(), 95 grpcutils.LogRequests, 96 )), 97 } 98 conn, err := grpc.DialContext(s.ctx, s.cfg.Endpoint, opts...) 99 if err != nil { 100 log.Errorf("Could not dial slasher endpoint: %s, %v", s.cfg.Endpoint, err) 101 return nil 102 } 103 log.Debug("Successfully started slasher gRPC connection") 104 s.conn = conn 105 return ethsl.NewSlasherClient(s.conn) 106 107 } 108 109 // Stop the validator service. 110 func (s *Service) Stop() error { 111 s.cancel() 112 log.Info("Stopping slashing protection service") 113 if s.conn != nil { 114 return s.conn.Close() 115 } 116 return nil 117 } 118 119 // Status checks if the connection to slasher server is ready, 120 // returns error otherwise. 121 func (s *Service) Status() error { 122 if s.conn == nil { 123 return errors.New("no connection to slasher RPC") 124 } 125 if s.conn.GetState() != connectivity.Ready { 126 return fmt.Errorf("can`t connect to slasher server at: %v connection status: %v ", s.cfg.Endpoint, s.conn.GetState()) 127 } 128 return nil 129 }