github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/cosmos-sdk/baseapp/baseapp_ibc_adapter.go (about) 1 package baseapp 2 3 import ( 4 "context" 5 "strconv" 6 7 "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/codec/types" 8 sdk "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types" 9 sdkerrors "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/errors" 10 grpctypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/types/grpc" 11 abci "github.com/fibonacci-chain/fbc/libs/tendermint/abci/types" 12 gogogrpc "github.com/gogo/protobuf/grpc" 13 grpcmiddleware "github.com/grpc-ecosystem/go-grpc-middleware" 14 grpcrecovery "github.com/grpc-ecosystem/go-grpc-middleware/recovery" 15 "google.golang.org/grpc" 16 "google.golang.org/grpc/codes" 17 "google.golang.org/grpc/metadata" 18 "google.golang.org/grpc/status" 19 grpcstatus "google.golang.org/grpc/status" 20 ) 21 22 // SetInterfaceRegistry sets the InterfaceRegistry. 23 func (app *BaseApp) SetInterfaceRegistry(registry types.InterfaceRegistry) { 24 app.interfaceRegistry = registry 25 app.grpcQueryRouter.SetInterfaceRegistry(registry) 26 app.msgServiceRouter.SetInterfaceRegistry(registry) 27 } 28 29 // MountMemoryStores mounts all in-memory KVStores with the BaseApp's internal 30 // commit multi-store. 31 func (app *BaseApp) MountMemoryStores(keys map[string]*sdk.MemoryStoreKey) { 32 for _, memKey := range keys { 33 app.MountStore(memKey, sdk.StoreTypeMemory) 34 } 35 } 36 37 func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQuery) abci.ResponseQuery { 38 ctx, err := app.createQueryContext(req.Height, req.Prove) 39 if err != nil { 40 return sdkerrors.QueryResult(err) 41 } 42 43 res, err := handler(ctx, req) 44 if err != nil { 45 res = sdkerrors.QueryResult(gRPCErrorToSDKError(err)) 46 res.Height = req.Height 47 return res 48 } 49 50 return res 51 } 52 53 func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, error) { 54 if err := checkNegativeHeight(height); err != nil { 55 return sdk.Context{}, err 56 } 57 58 // when a client did not provide a query height, manually inject the latest 59 if height == 0 { 60 height = app.LastBlockHeight() 61 } 62 63 if height <= 1 && prove { 64 return sdk.Context{}, 65 sdkerrors.Wrap( 66 sdkerrors.ErrInvalidRequest, 67 "cannot query with proof when height <= 1; please provide a valid height", 68 ) 69 } 70 71 cacheMS, err := app.cms.CacheMultiStoreWithVersion(height) 72 if err != nil { 73 return sdk.Context{}, 74 sdkerrors.Wrapf( 75 sdkerrors.ErrInvalidRequest, 76 "failed to load state at height %d; %s (latest height: %d)", height, err, app.LastBlockHeight(), 77 ) 78 } 79 80 // branch the commit-multistore for safety 81 ctx := sdk.NewContext( 82 cacheMS, app.checkState.ctx.BlockHeader(), true, app.logger, 83 ) 84 ctx.SetMinGasPrices(app.minGasPrices) 85 86 return ctx, nil 87 } 88 89 func checkNegativeHeight(height int64) error { 90 if height < 0 { 91 // Reject invalid heights. 92 return sdkerrors.Wrap( 93 sdkerrors.ErrInvalidRequest, 94 "cannot query with height < 0; please provide a valid height", 95 ) 96 } 97 return nil 98 } 99 100 func gRPCErrorToSDKError(err error) error { 101 status, ok := grpcstatus.FromError(err) 102 if !ok { 103 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) 104 } 105 106 switch status.Code() { 107 case codes.NotFound: 108 return sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, err.Error()) 109 case codes.InvalidArgument: 110 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) 111 case codes.FailedPrecondition: 112 return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error()) 113 case codes.Unauthenticated: 114 return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, err.Error()) 115 default: 116 return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, err.Error()) 117 } 118 } 119 120 func (app *BaseApp) RegisterGRPCServer(server gogogrpc.Server) { 121 // Define an interceptor for all gRPC queries: this interceptor will create 122 // a new sdk.Context, and pass it into the query handler. 123 interceptor := func(grpcCtx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) { 124 // If there's some metadata in the context, retrieve it. 125 md, ok := metadata.FromIncomingContext(grpcCtx) 126 if !ok { 127 return nil, status.Error(codes.Internal, "unable to retrieve metadata") 128 } 129 130 // Get height header from the request context, if present. 131 var height int64 132 if heightHeaders := md.Get(grpctypes.GRPCBlockHeightHeader); len(heightHeaders) == 1 { 133 height, err = strconv.ParseInt(heightHeaders[0], 10, 64) 134 if err != nil { 135 return nil, sdkerrors.Wrapf( 136 sdkerrors.ErrInvalidRequest, 137 "Baseapp.RegisterGRPCServer: invalid height header %q: %v", grpctypes.GRPCBlockHeightHeader, err) 138 } 139 if err := checkNegativeHeight(height); err != nil { 140 return nil, err 141 } 142 } 143 144 // Create the sdk.Context. Passing false as 2nd arg, as we can't 145 // actually support proofs with gRPC right now. 146 sdkCtx, err := app.createQueryContext(height, false) 147 if err != nil { 148 return nil, err 149 } 150 151 // Add relevant gRPC headers 152 if height == 0 { 153 height = sdkCtx.BlockHeight() // If height was not set in the request, set it to the latest 154 } 155 156 // Attach the sdk.Context into the gRPC's context.Context. 157 grpcCtx = context.WithValue(grpcCtx, sdk.SdkContextKey, sdkCtx) 158 159 md = metadata.Pairs(grpctypes.GRPCBlockHeightHeader, strconv.FormatInt(height, 10)) 160 if err = grpc.SetHeader(grpcCtx, md); err != nil { 161 app.logger.Error("failed to set gRPC header", "err", err) 162 } 163 164 return handler(grpcCtx, req) 165 } 166 167 // Loop through all services and methods, add the interceptor, and register 168 // the service. 169 for _, data := range app.GRPCQueryRouter().serviceData { 170 desc := data.serviceDesc 171 newMethods := make([]grpc.MethodDesc, len(desc.Methods)) 172 173 for i, method := range desc.Methods { 174 methodHandler := method.Handler 175 newMethods[i] = grpc.MethodDesc{ 176 MethodName: method.MethodName, 177 Handler: func(srv interface{}, ctx context.Context, dec func(interface{}) error, _ grpc.UnaryServerInterceptor) (interface{}, error) { 178 return methodHandler(srv, ctx, dec, grpcmiddleware.ChainUnaryServer( 179 grpcrecovery.UnaryServerInterceptor(), 180 interceptor, 181 )) 182 }, 183 } 184 } 185 186 newDesc := &grpc.ServiceDesc{ 187 ServiceName: desc.ServiceName, 188 HandlerType: desc.HandlerType, 189 Methods: newMethods, 190 Streams: desc.Streams, 191 Metadata: desc.Metadata, 192 } 193 194 server.RegisterService(newDesc, data.handler) 195 } 196 } 197 198 // it is like hooker ,grap the request and do sth....(like redirect the path or anything else) 199 type Interceptor interface { 200 Intercept(req *abci.RequestQuery) 201 } 202 203 var ( 204 _ Interceptor = (*functionInterceptor)(nil) 205 ) 206 207 type functionInterceptor struct { 208 hookF func(req *abci.RequestQuery) 209 } 210 211 func (f *functionInterceptor) Intercept(req *abci.RequestQuery) { 212 f.hookF(req) 213 } 214 215 func NewRedirectInterceptor(redirectPath string) Interceptor { 216 return newFunctionInterceptor(func(req *abci.RequestQuery) { 217 req.Path = redirectPath 218 }) 219 } 220 221 func newFunctionInterceptor(f func(req *abci.RequestQuery)) *functionInterceptor { 222 return &functionInterceptor{hookF: f} 223 }