github.com/Finschia/finschia-sdk@v0.48.1/baseapp/grpcserver.go (about)

     1  package baseapp
     2  
     3  import (
     4  	"context"
     5  	"strconv"
     6  
     7  	gogogrpc "github.com/gogo/protobuf/grpc"
     8  	grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware"
     9  	grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery"
    10  	"google.golang.org/grpc"
    11  	"google.golang.org/grpc/codes"
    12  	"google.golang.org/grpc/metadata"
    13  	"google.golang.org/grpc/status"
    14  
    15  	sdk "github.com/Finschia/finschia-sdk/types"
    16  	sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
    17  	grpctypes "github.com/Finschia/finschia-sdk/types/grpc"
    18  )
    19  
    20  // GRPCQueryRouter returns the GRPCQueryRouter of a BaseApp.
    21  func (app *BaseApp) GRPCQueryRouter() *GRPCQueryRouter { return app.grpcQueryRouter }
    22  
    23  // RegisterGRPCServer registers gRPC services directly with the gRPC server.
    24  func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) {
    25  	// Define an interceptor for all gRPC queries: this interceptor will create
    26  	// a new sdk.Context, and pass it into the query handler.
    27  	interceptor := func(grpcCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
    28  		// If there's some metadata in the context, retrieve it.
    29  		md, ok := metadata.FromIncomingContext(grpcCtx)
    30  		if !ok {
    31  			return nil, status.Error(codes.Internal, "unable to retrieve metadata")
    32  		}
    33  
    34  		var sdkCtx sdk.Context
    35  		// Get height header from the request context, if present.
    36  		var height int64
    37  
    38  		if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) == 1 {
    39  			height, err = strconv.ParseInt(heightHeaders[0], 10, 64)
    40  			if err != nil {
    41  				return nil, sdkerrors.Wrapf(
    42  					sdkerrors.ErrInvalidRequest,
    43  					"Baseapp.RegisterGRPCServer: invalid height header %q: %v", grpctypes.GRPCBlockHeightHeader, err)
    44  			}
    45  			if err := checkNegativeHeight(height); err != nil {
    46  				return nil, err
    47  			}
    48  
    49  			// Create the sdk.Context. Passing false as 2nd arg, as we can't
    50  			// actually support proofs with gRPC right now.
    51  			sdkCtx, err = app.createQueryContext(height, false)
    52  			if err != nil {
    53  				return nil, err
    54  			}
    55  		} else if csHeaders := md.Get(grpctypes.GRPCCheckStateHeader); len(csHeaders) == 1 {
    56  			isCheck := csHeaders[0]
    57  			if isCheck != "on" {
    58  				return nil, sdkerrors.Wrapf(
    59  					sdkerrors.ErrInvalidRequest,
    60  					"Baseapp.RegisterGRPCServer: invalid checkState header %q: %v", grpctypes.GRPCCheckStateHeader, err)
    61  			}
    62  
    63  			sdkCtx = app.createQueryContextWithCheckState()
    64  		} else {
    65  			sdkCtx, err = app.createQueryContext(height, false)
    66  			if err != nil {
    67  				return nil, err
    68  			}
    69  		}
    70  
    71  		// Add relevant gRPC headers
    72  		if height == 0 {
    73  			height = sdkCtx.BlockHeight() // If height was not set in the request, set it to the latest
    74  		}
    75  
    76  		// Attach the sdk.Context into the gRPC's context.Context.
    77  		grpcCtx = context.WithValue(grpcCtx, sdk.SdkContextKey, sdkCtx)
    78  
    79  		md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(height, 10))
    80  		if err = grpc.SetHeader(grpcCtx, md); err != nil {
    81  			return nil, err
    82  		}
    83  
    84  		return handler(grpcCtx, req)
    85  	}
    86  
    87  	// Loop through all services and methods, add the interceptor, and register
    88  	// the service.
    89  	for _, data := range app.GRPCQueryRouter().serviceData {
    90  		desc := data.serviceDesc
    91  		newMethods := make([]grpc.MethodDesc, len(desc.Methods))
    92  
    93  		for i, method := range desc.Methods {
    94  			methodHandler := method.Handler
    95  			newMethods[i] = grpc.MethodDesc{
    96  				MethodName: method.MethodName,
    97  				Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, _ grpc.UnaryServerInterceptor) (interface{}, error) {
    98  					return methodHandler(srv, ctx, dec, grpcmiddleware.ChainUnaryServer(
    99  						grpcrecovery.UnaryServerInterceptor(),
   100  						interceptor,
   101  					))
   102  				},
   103  			}
   104  		}
   105  
   106  		newDesc := &grpc.ServiceDesc{
   107  			ServiceName: desc.ServiceName,
   108  			HandlerType: desc.HandlerType,
   109  			Methods:     newMethods,
   110  			Streams:     desc.Streams,
   111  			Metadata:    desc.Metadata,
   112  		}
   113  
   114  		server.RegisterService(newDesc, data.handler)
   115  	}
   116  }