Skip to content

Commit

Permalink
feat: wire new handlers to grpc (#22333)
Browse files Browse the repository at this point in the history
Co-authored-by: Randy Grok <@faulttolerance.net>
Co-authored-by: Julien Robert <[email protected]>
  • Loading branch information
randygrok and julienrbrt authored Nov 5, 2024
1 parent 8c24b6b commit 62ddd3e
Show file tree
Hide file tree
Showing 9 changed files with 4,276 additions and 0 deletions.
2,590 changes: 2,590 additions & 0 deletions api/cosmos/base/grpc/v2/service.pulsar.go

Large diffs are not rendered by default.

167 changes: 167 additions & 0 deletions api/cosmos/base/grpc/v2/service_grpc.pb.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

39 changes: 39 additions & 0 deletions proto/cosmos/base/grpc/v2/service.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
syntax = "proto3";
package cosmos.base.grpc.v2;

import "google/protobuf/any.proto";

option go_package = "cosmossdk.io/server/v2/api/grpc";

// Service defines the gRPC service for query server for v2
service Service {
// Query queries the server with a request, the request can be any sdk Msg.
rpc Query(QueryRequest) returns (QueryResponse) {}

// ListQueryHandlers lists all the available query handlers.
rpc ListQueryHandlers(ListQueryHandlersRequest) returns (ListQueryHandlersResponse) {}
}

// QueryRequest is the request for the Query method
message QueryRequest {
google.protobuf.Any request = 1;
}

// QueryResponse is the response for the Query method
message QueryResponse {
google.protobuf.Any response = 1;
}

// ListQueryHandlersRequest is the request for the ListQueryHandlers method
message ListQueryHandlersRequest {}

// ListQueryHandlersResponse is the response for the ListQueryHandlers method
message ListQueryHandlersResponse {
repeated Handler handlers = 1;
}

// Handler defines a query handler
message Handler {
string request_name = 1;
string response_name = 2;
}
3 changes: 3 additions & 0 deletions server/v2/api/grpc/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,9 @@ func New[T transaction.Tx](
// Reflection allows external clients to see what services and methods the gRPC server exposes.
gogoreflection.Register(grpcSrv, slices.Collect(maps.Keys(queryHandlers)), logger.With("sub-module", "grpc-reflection"))

// Register V2
RegisterServiceServer(grpcSrv, &v2Service{queryHandlers, queryable})

srv.grpcSrv = grpcSrv
srv.config = serverCfg
srv.logger = logger.With(log.ModuleKey, srv.Name())
Expand Down
73 changes: 73 additions & 0 deletions server/v2/api/grpc/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
package grpc

import (
"context"

"github.com/cosmos/gogoproto/proto"
gogoproto "github.com/cosmos/gogoproto/types/any"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

appmodulev2 "cosmossdk.io/core/appmodule/v2"
"cosmossdk.io/core/transaction"
)

// v2Service implements the gRPC service interface for handling queries and listing handlers.
type v2Service struct {
queryHandlers map[string]appmodulev2.Handler
queryable interface {
Query(ctx context.Context, version uint64, msg transaction.Msg) (transaction.Msg, error)
}
}

// Query handles incoming query requests by unmarshaling the request, processing it,
// and returning the response in an Any protobuf message.
func (s v2Service) Query(ctx context.Context, request *QueryRequest) (*QueryResponse, error) {
if request == nil || request.Request == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}

msgName := request.Request.TypeUrl

handler, exists := s.queryHandlers[msgName]
if !exists {
return nil, status.Errorf(codes.NotFound, "handler not found for %s", msgName)
}

protoMsg := handler.MakeMsg()
if err := proto.Unmarshal(request.Request.Value, protoMsg); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "failed to unmarshal request: %v", err)
}

queryResp, err := s.queryable.Query(ctx, 0, protoMsg)
if err != nil {
return nil, status.Errorf(codes.Internal, "query failed: %v", err)
}

respBytes, err := proto.Marshal(queryResp)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to marshal response: %v", err)
}

anyResp := &gogoproto.Any{
TypeUrl: "/" + proto.MessageName(queryResp),
Value: respBytes,
}

return &QueryResponse{Response: anyResp}, nil
}

func (s v2Service) ListQueryHandlers(_ context.Context, _ *ListQueryHandlersRequest) (*ListQueryHandlersResponse, error) {
var handlerDescriptors []*Handler
for handlerName := range s.queryHandlers {
msg := s.queryHandlers[handlerName].MakeMsg()
resp := s.queryHandlers[handlerName].MakeMsgResp()

handlerDescriptors = append(handlerDescriptors, &Handler{
RequestName: proto.MessageName(msg),
ResponseName: proto.MessageName(resp),
})
}

return &ListQueryHandlersResponse{Handlers: handlerDescriptors}, nil
}
Loading

0 comments on commit 62ddd3e

Please sign in to comment.