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  }