github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/privval/grpc/util.go (about)

     1  package grpc
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"os"
     8  	"time"
     9  
    10  	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
    11  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
    12  
    13  	"google.golang.org/grpc"
    14  	"google.golang.org/grpc/credentials"
    15  
    16  	"google.golang.org/grpc/keepalive"
    17  
    18  	"github.com/ari-anchor/sei-tendermint/config"
    19  	"github.com/ari-anchor/sei-tendermint/libs/log"
    20  	tmnet "github.com/ari-anchor/sei-tendermint/libs/net"
    21  )
    22  
    23  // DefaultDialOptions constructs a list of grpc dial options
    24  func DefaultDialOptions(
    25  	extraOpts ...grpc.DialOption,
    26  ) []grpc.DialOption {
    27  	const (
    28  		retries            = 50 // 50 * 100ms = 5s total
    29  		timeout            = 1 * time.Second
    30  		maxCallRecvMsgSize = 1 << 20 // Default 5Mb
    31  	)
    32  
    33  	var kacp = keepalive.ClientParameters{
    34  		Time:    10 * time.Second, // send pings every 10 seconds if there is no activity
    35  		Timeout: 2 * time.Second,  // wait 2 seconds for ping ack before considering the connection dead
    36  	}
    37  
    38  	opts := []grpc_retry.CallOption{
    39  		grpc_retry.WithBackoff(grpc_retry.BackoffExponential(timeout)),
    40  	}
    41  
    42  	dialOpts := []grpc.DialOption{
    43  		grpc.WithKeepaliveParams(kacp),
    44  		grpc.WithDefaultCallOptions(
    45  			grpc.MaxCallRecvMsgSize(maxCallRecvMsgSize),
    46  			grpc_retry.WithMax(retries),
    47  		),
    48  		grpc.WithUnaryInterceptor(
    49  			grpc_retry.UnaryClientInterceptor(opts...),
    50  		),
    51  	}
    52  
    53  	dialOpts = append(dialOpts, extraOpts...)
    54  
    55  	return dialOpts
    56  }
    57  
    58  func GenerateTLS(certPath, keyPath, ca string, log log.Logger) grpc.DialOption {
    59  	certificate, err := tls.LoadX509KeyPair(
    60  		certPath,
    61  		keyPath,
    62  	)
    63  	if err != nil {
    64  		log.Error("error", err)
    65  		os.Exit(1)
    66  	}
    67  
    68  	certPool := x509.NewCertPool()
    69  	bs, err := os.ReadFile(ca)
    70  	if err != nil {
    71  		log.Error("failed to read ca cert:", "error", err)
    72  		os.Exit(1)
    73  	}
    74  
    75  	ok := certPool.AppendCertsFromPEM(bs)
    76  	if !ok {
    77  		log.Error("failed to append certs")
    78  		os.Exit(1)
    79  	}
    80  
    81  	transportCreds := credentials.NewTLS(&tls.Config{
    82  		Certificates: []tls.Certificate{certificate},
    83  		RootCAs:      certPool,
    84  		MinVersion:   tls.VersionTLS13,
    85  	})
    86  
    87  	return grpc.WithTransportCredentials(transportCreds)
    88  }
    89  
    90  // DialRemoteSigner is  a generalized function to dial the gRPC server.
    91  func DialRemoteSigner(
    92  	ctx context.Context,
    93  	cfg *config.PrivValidatorConfig,
    94  	chainID string,
    95  	logger log.Logger,
    96  	usePrometheus bool,
    97  ) (*SignerClient, error) {
    98  	var transportSecurity grpc.DialOption
    99  	if cfg.AreSecurityOptionsPresent() {
   100  		transportSecurity = GenerateTLS(cfg.ClientCertificateFile(),
   101  			cfg.ClientKeyFile(), cfg.RootCAFile(), logger)
   102  	} else {
   103  		transportSecurity = grpc.WithInsecure()
   104  		logger.Info("Using an insecure gRPC connection!")
   105  	}
   106  
   107  	dialOptions := DefaultDialOptions()
   108  	if usePrometheus {
   109  		grpcMetrics := grpc_prometheus.DefaultClientMetrics
   110  		dialOptions = append(dialOptions, grpc.WithUnaryInterceptor(grpcMetrics.UnaryClientInterceptor()))
   111  	}
   112  
   113  	dialOptions = append(dialOptions, transportSecurity)
   114  
   115  	_, address := tmnet.ProtocolAndAddress(cfg.ListenAddr)
   116  	conn, err := grpc.DialContext(ctx, address, dialOptions...)
   117  	if err != nil {
   118  		logger.Error("unable to connect to server", "target", address, "err", err)
   119  	}
   120  
   121  	return NewSignerClient(conn, chainID, logger)
   122  }