2020-05-20 15:23:22 +00:00
|
|
|
package slashingprotection
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"errors"
|
2020-07-27 20:06:49 +00:00
|
|
|
"fmt"
|
2020-05-20 15:23:22 +00:00
|
|
|
"strings"
|
2020-07-22 03:45:52 +00:00
|
|
|
"time"
|
2020-05-20 15:23:22 +00:00
|
|
|
|
|
|
|
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"
|
2020-07-27 20:06:49 +00:00
|
|
|
"google.golang.org/grpc/connectivity"
|
2020-05-20 15:23:22 +00:00
|
|
|
"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
|
2020-07-22 03:45:52 +00:00
|
|
|
grpcRetryDelay time.Duration
|
2020-05-20 15:23:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Config for the validator service.
|
|
|
|
type Config struct {
|
|
|
|
Endpoint string
|
|
|
|
CertFlag string
|
|
|
|
GrpcMaxCallRecvMsgSizeFlag int
|
|
|
|
GrpcRetriesFlag uint
|
2020-07-22 03:45:52 +00:00
|
|
|
GrpcRetryDelay time.Duration
|
2020-05-20 15:23:22 +00:00
|
|
|
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,
|
2020-07-22 03:45:52 +00:00
|
|
|
grpcRetryDelay: cfg.GrpcRetryDelay,
|
2020-05-20 15:23:22 +00:00
|
|
|
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),
|
2020-07-22 03:45:52 +00:00
|
|
|
grpc_retry.WithBackoff(grpc_retry.BackoffLinear(s.grpcRetryDelay)),
|
2020-05-20 15:23:22 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2020-07-27 20:06:49 +00:00
|
|
|
// Status checks if the connection to slasher server is ready,
|
|
|
|
// returns error otherwise.
|
2020-05-20 15:23:22 +00:00
|
|
|
func (s *Service) Status() error {
|
|
|
|
if s.conn == nil {
|
|
|
|
return errors.New("no connection to slasher RPC")
|
|
|
|
}
|
2020-07-27 20:06:49 +00:00
|
|
|
if s.conn.GetState() != connectivity.Ready {
|
2020-08-18 03:04:39 +00:00
|
|
|
return fmt.Errorf("can`t connect to slasher server at: %v connection status: %v ", s.endpoint, s.conn.GetState())
|
2020-07-27 20:06:49 +00:00
|
|
|
}
|
2020-05-20 15:23:22 +00:00
|
|
|
return nil
|
|
|
|
}
|