github.com/cosmos/cosmos-sdk@v0.50.10/server/grpc/server.go (about) 1 package grpc 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 8 "google.golang.org/grpc" 9 10 "cosmossdk.io/log" 11 12 "github.com/cosmos/cosmos-sdk/client" 13 "github.com/cosmos/cosmos-sdk/codec" 14 "github.com/cosmos/cosmos-sdk/server/config" 15 "github.com/cosmos/cosmos-sdk/server/grpc/gogoreflection" 16 reflection "github.com/cosmos/cosmos-sdk/server/grpc/reflection/v2alpha1" 17 "github.com/cosmos/cosmos-sdk/server/types" 18 sdk "github.com/cosmos/cosmos-sdk/types" 19 _ "github.com/cosmos/cosmos-sdk/types/tx/amino" // Import amino.proto file for reflection 20 ) 21 22 // NewGRPCServer returns a correctly configured and initialized gRPC server. 23 // Note, the caller is responsible for starting the server. See StartGRPCServer. 24 func NewGRPCServer(clientCtx client.Context, app types.Application, cfg config.GRPCConfig) (*grpc.Server, error) { 25 maxSendMsgSize := cfg.MaxSendMsgSize 26 if maxSendMsgSize == 0 { 27 maxSendMsgSize = config.DefaultGRPCMaxSendMsgSize 28 } 29 30 maxRecvMsgSize := cfg.MaxRecvMsgSize 31 if maxRecvMsgSize == 0 { 32 maxRecvMsgSize = config.DefaultGRPCMaxRecvMsgSize 33 } 34 35 grpcSrv := grpc.NewServer( 36 grpc.ForceServerCodec(codec.NewProtoCodec(clientCtx.InterfaceRegistry).GRPCCodec()), 37 grpc.MaxSendMsgSize(maxSendMsgSize), 38 grpc.MaxRecvMsgSize(maxRecvMsgSize), 39 ) 40 41 app.RegisterGRPCServer(grpcSrv) 42 43 // Reflection allows consumers to build dynamic clients that can write to any 44 // Cosmos SDK application without relying on application packages at compile 45 // time. 46 err := reflection.Register(grpcSrv, reflection.Config{ 47 SigningModes: func() map[string]int32 { 48 supportedModes := clientCtx.TxConfig.SignModeHandler().SupportedModes() 49 modes := make(map[string]int32, len(supportedModes)) 50 for _, m := range supportedModes { 51 modes[m.String()] = (int32)(m) 52 } 53 54 return modes 55 }(), 56 ChainID: clientCtx.ChainID, 57 SdkConfig: sdk.GetConfig(), 58 InterfaceRegistry: clientCtx.InterfaceRegistry, 59 }) 60 if err != nil { 61 return nil, fmt.Errorf("failed to register reflection service: %w", err) 62 } 63 64 // Reflection allows external clients to see what services and methods 65 // the gRPC server exposes. 66 gogoreflection.Register(grpcSrv) 67 68 return grpcSrv, nil 69 } 70 71 // StartGRPCServer starts the provided gRPC server on the address specified in cfg. 72 // 73 // Note, this creates a blocking process if the server is started successfully. 74 // Otherwise, an error is returned. The caller is expected to provide a Context 75 // that is properly canceled or closed to indicate the server should be stopped. 76 func StartGRPCServer(ctx context.Context, logger log.Logger, cfg config.GRPCConfig, grpcSrv *grpc.Server) error { 77 listener, err := net.Listen("tcp", cfg.Address) 78 if err != nil { 79 return fmt.Errorf("failed to listen on address %s: %w", cfg.Address, err) 80 } 81 82 errCh := make(chan error) 83 84 // Start the gRPC in an external goroutine as Serve is blocking and will return 85 // an error upon failure, which we'll send on the error channel that will be 86 // consumed by the for block below. 87 go func() { 88 logger.Info("starting gRPC server...", "address", cfg.Address) 89 errCh <- grpcSrv.Serve(listener) 90 }() 91 92 // Start a blocking select to wait for an indication to stop the server or that 93 // the server failed to start properly. 94 select { 95 case <-ctx.Done(): 96 // The calling process canceled or closed the provided context, so we must 97 // gracefully stop the gRPC server. 98 logger.Info("stopping gRPC server...", "address", cfg.Address) 99 grpcSrv.GracefulStop() 100 101 return nil 102 103 case err := <-errCh: 104 logger.Error("failed to start gRPC server", "err", err) 105 return err 106 } 107 }