github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/cmd/priv_val_server/main.go (about)

     1  package main
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"crypto/x509"
     7  	"flag"
     8  	"fmt"
     9  	"net"
    10  	"net/http"
    11  	"os"
    12  	"os/signal"
    13  	"syscall"
    14  	"time"
    15  
    16  	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
    17  	"github.com/prometheus/client_golang/prometheus"
    18  	"github.com/prometheus/client_golang/prometheus/promhttp"
    19  	"google.golang.org/grpc"
    20  	"google.golang.org/grpc/credentials"
    21  
    22  	"github.com/ari-anchor/sei-tendermint/libs/log"
    23  	tmnet "github.com/ari-anchor/sei-tendermint/libs/net"
    24  	"github.com/ari-anchor/sei-tendermint/privval"
    25  	grpcprivval "github.com/ari-anchor/sei-tendermint/privval/grpc"
    26  	privvalproto "github.com/ari-anchor/sei-tendermint/proto/tendermint/privval"
    27  )
    28  
    29  var (
    30  	// Create a metrics registry.
    31  	reg = prometheus.NewRegistry()
    32  
    33  	// Create some standard server metrics.
    34  	grpcMetrics = grpc_prometheus.NewServerMetrics()
    35  )
    36  
    37  func main() {
    38  	var (
    39  		addr             = flag.String("addr", "127.0.0.1:26659", "Address to listen on (host:port)")
    40  		chainID          = flag.String("chain-id", "mychain", "chain id")
    41  		privValKeyPath   = flag.String("priv-key", "", "priv val key file path")
    42  		privValStatePath = flag.String("priv-state", "", "priv val state file path")
    43  		insecure         = flag.Bool("insecure", false, "allow server to run insecurely (no TLS)")
    44  		certFile         = flag.String("certfile", "", "absolute path to server certificate")
    45  		keyFile          = flag.String("keyfile", "", "absolute path to server key")
    46  		rootCA           = flag.String("rootcafile", "", "absolute path to root CA")
    47  		prometheusAddr   = flag.String("prometheus-addr", "", "address for prometheus endpoint (host:port)")
    48  	)
    49  	flag.Parse()
    50  
    51  	logger, err := log.NewDefaultLogger(log.LogFormatPlain, log.LogLevelInfo)
    52  	if err != nil {
    53  		fmt.Fprintf(os.Stderr, "failed to construct logger: %v", err)
    54  		os.Exit(1)
    55  	}
    56  	logger = logger.With("module", "priv_val")
    57  
    58  	ctx, cancel := context.WithCancel(context.Background())
    59  	defer cancel()
    60  
    61  	logger.Info(
    62  		"Starting private validator",
    63  		"addr", *addr,
    64  		"chainID", *chainID,
    65  		"privKeyPath", *privValKeyPath,
    66  		"privStatePath", *privValStatePath,
    67  		"insecure", *insecure,
    68  		"certFile", *certFile,
    69  		"keyFile", *keyFile,
    70  		"rootCA", *rootCA,
    71  	)
    72  
    73  	pv, err := privval.LoadFilePV(*privValKeyPath, *privValStatePath)
    74  	if err != nil {
    75  		fmt.Fprint(os.Stderr, err)
    76  		os.Exit(1)
    77  	}
    78  
    79  	opts := []grpc.ServerOption{}
    80  	if !*insecure {
    81  		certificate, err := tls.LoadX509KeyPair(*certFile, *keyFile)
    82  		if err != nil {
    83  			fmt.Fprintf(os.Stderr, "failed to load X509 key pair: %v", err)
    84  			os.Exit(1)
    85  		}
    86  
    87  		certPool := x509.NewCertPool()
    88  		bs, err := os.ReadFile(*rootCA)
    89  		if err != nil {
    90  			fmt.Fprintf(os.Stderr, "failed to read client ca cert: %s", err)
    91  			os.Exit(1)
    92  		}
    93  
    94  		if ok := certPool.AppendCertsFromPEM(bs); !ok {
    95  			fmt.Fprintf(os.Stderr, "failed to append client certs")
    96  			os.Exit(1)
    97  		}
    98  
    99  		tlsConfig := &tls.Config{
   100  			ClientAuth:   tls.RequireAndVerifyClientCert,
   101  			Certificates: []tls.Certificate{certificate},
   102  			ClientCAs:    certPool,
   103  			MinVersion:   tls.VersionTLS13,
   104  		}
   105  
   106  		creds := grpc.Creds(credentials.NewTLS(tlsConfig))
   107  		opts = append(opts, creds)
   108  		logger.Info("SignerServer: Creating security credentials")
   109  	} else {
   110  		logger.Info("SignerServer: You are using an insecure gRPC connection!")
   111  	}
   112  
   113  	// add prometheus metrics for unary RPC calls
   114  	opts = append(opts, grpc.UnaryInterceptor(grpc_prometheus.UnaryServerInterceptor))
   115  
   116  	ss := grpcprivval.NewSignerServer(logger, *chainID, pv)
   117  
   118  	protocol, address := tmnet.ProtocolAndAddress(*addr)
   119  
   120  	lis, err := net.Listen(protocol, address)
   121  	if err != nil {
   122  		fmt.Fprintf(os.Stderr, "SignerServer: Failed to listen %v", err)
   123  		os.Exit(1)
   124  	}
   125  
   126  	s := grpc.NewServer(opts...)
   127  
   128  	privvalproto.RegisterPrivValidatorAPIServer(s, ss)
   129  
   130  	var httpSrv *http.Server
   131  	if *prometheusAddr != "" {
   132  		httpSrv = registerPrometheus(*prometheusAddr, s)
   133  	}
   134  
   135  	logger.Info("SignerServer: Starting grpc server")
   136  	if err := s.Serve(lis); err != nil {
   137  		fmt.Fprintf(os.Stderr, "Unable to listen on port %s: %v", *addr, err)
   138  		os.Exit(1)
   139  	}
   140  
   141  	opctx, opcancel := signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM)
   142  	defer opcancel()
   143  	go func() {
   144  		<-opctx.Done()
   145  		if *prometheusAddr != "" {
   146  			ctx, cancel := context.WithTimeout(context.Background(), 1*time.Second)
   147  			defer cancel()
   148  			if err := httpSrv.Shutdown(ctx); err != nil {
   149  				fmt.Fprintf(os.Stderr, "Unable to stop http server: %v", err)
   150  				os.Exit(1)
   151  			}
   152  		}
   153  		s.GracefulStop()
   154  	}()
   155  
   156  	// Run forever.
   157  	select {}
   158  }
   159  
   160  func registerPrometheus(addr string, s *grpc.Server) *http.Server {
   161  	// Initialize all metrics.
   162  	grpcMetrics.InitializeMetrics(s)
   163  	// create http server to serve prometheus
   164  	httpServer := &http.Server{Handler: promhttp.HandlerFor(reg, promhttp.HandlerOpts{}), Addr: addr}
   165  
   166  	go func() {
   167  		if err := httpServer.ListenAndServe(); err != nil {
   168  			fmt.Fprintf(os.Stderr, "Unable to start a http server: %v", err)
   169  			os.Exit(1)
   170  		}
   171  	}()
   172  
   173  	return httpServer
   174  }