You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

121 lines
3.1 KiB

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