prysm-pulse/validator/slashing-protection/slasher_client.go
Shay Zluf 17169e5a2d
External slashing protection (#5895)
* slasher grpc client

* do not export

* slasher on a different package

* fix featureconfig

* change to rough time

* revert roughtime

* remove extra comma

* revert order change

* goimports

* fix comments and tests

* fix package name

* revert reorder

* comment for start

* service

* fix visibility

* external slasher validator protection implementation

* gaz

* fix comment

* add comments

* nishant feedback

* raul feedback

* preston feedback

* fix flags

* fix imports

* fix imports

* port 4002

* added tests

* fix log

* fix imports

* fix imports name

* raul feedback

* gaz

* terence comment

* change name

* runtime fixes

* add flag check

Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
2020-05-20 10:23:22 -05:00

142 lines
3.8 KiB
Go

package slashingprotection
import (
"context"
"errors"
"strings"
middleware "github.com/grpc-ecosystem/go-grpc-middleware"
grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
grpc_opentracing "github.com/grpc-ecosystem/go-grpc-middleware/tracing/opentracing"
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
ethsl "github.com/prysmaticlabs/prysm/proto/slashing"
"github.com/prysmaticlabs/prysm/shared/grpcutils"
log "github.com/sirupsen/logrus"
"go.opencensus.io/plugin/ocgrpc"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials"
"google.golang.org/grpc/metadata"
)
// Service represents a service to manage the validator
// ￿slashing protection.
type Service struct {
ctx context.Context
cancel context.CancelFunc
conn *grpc.ClientConn
endpoint string
withCert string
maxCallRecvMsgSize int
grpcRetries uint
grpcHeaders []string
slasherClient ethsl.SlasherClient
}
// Config for the validator service.
type Config struct {
Endpoint string
CertFlag string
GrpcMaxCallRecvMsgSizeFlag int
GrpcRetriesFlag uint
GrpcHeadersFlag string
}
// NewSlashingProtectionService creates a new validator service for the service
// registry.
func NewSlashingProtectionService(ctx context.Context, cfg *Config) (*Service, error) {
ctx, cancel := context.WithCancel(ctx)
return &Service{
ctx: ctx,
cancel: cancel,
endpoint: cfg.Endpoint,
withCert: cfg.CertFlag,
maxCallRecvMsgSize: cfg.GrpcMaxCallRecvMsgSizeFlag,
grpcRetries: cfg.GrpcRetriesFlag,
grpcHeaders: strings.Split(cfg.GrpcHeadersFlag, ","),
}, nil
}
// Start the slasher protection service and grpc client.
func (s *Service) Start() {
if s.endpoint != "" {
s.slasherClient = s.startSlasherClient()
}
}
func (s *Service) startSlasherClient() ethsl.SlasherClient {
var dialOpt grpc.DialOption
if s.withCert != "" {
creds, err := credentials.NewClientTLSFromFile(s.withCert, "")
if err != nil {
log.Errorf("Could not get valid slasher credentials: %v", err)
return nil
}
dialOpt = grpc.WithTransportCredentials(creds)
} else {
dialOpt = grpc.WithInsecure()
log.Warn("You are using an insecure slasher gRPC connection! Please provide a certificate and key to use a secure connection.")
}
md := make(metadata.MD)
for _, hdr := range s.grpcHeaders {
if hdr != "" {
ss := strings.Split(hdr, "=")
if len(ss) != 2 {
log.Warnf("Incorrect gRPC header flag format. Skipping %v", hdr)
continue
}
md.Set(ss[0], ss[1])
}
}
opts := []grpc.DialOption{
dialOpt,
grpc.WithDefaultCallOptions(
grpc_retry.WithMax(s.grpcRetries),
grpc.Header(&md),
),
grpc.WithStatsHandler(&ocgrpc.ClientHandler{}),
grpc.WithStreamInterceptor(middleware.ChainStreamClient(
grpc_opentracing.StreamClientInterceptor(),
grpc_prometheus.StreamClientInterceptor,
grpc_retry.StreamClientInterceptor(),
)),
grpc.WithUnaryInterceptor(middleware.ChainUnaryClient(
grpc_opentracing.UnaryClientInterceptor(),
grpc_prometheus.UnaryClientInterceptor,
grpc_retry.UnaryClientInterceptor(),
grpcutils.LogGRPCRequests,
)),
}
conn, err := grpc.DialContext(s.ctx, s.endpoint, opts...)
if err != nil {
log.Errorf("Could not dial slasher endpoint: %s, %v", s.endpoint, err)
return nil
}
log.Debug("Successfully started slasher gRPC connection")
s.conn = conn
return ethsl.NewSlasherClient(s.conn)
}
// Stop the validator service.
func (s *Service) Stop() error {
s.cancel()
log.Info("Stopping slashing protection service")
if s.conn != nil {
return s.conn.Close()
}
return nil
}
// Status ...
//
// WIP - not done.
func (s *Service) Status() error {
if s.conn == nil {
return errors.New("no connection to slasher RPC")
}
return nil
}