github.com/cosmos/cosmos-sdk@v0.50.10/client/grpc/cmtservice/service.go (about)

     1  package cmtservice
     2  
     3  import (
     4  	"context"
     5  
     6  	abci "github.com/cometbft/cometbft/abci/types"
     7  	gogogrpc "github.com/cosmos/gogoproto/grpc"
     8  	"github.com/grpc-ecosystem/grpc-gateway/runtime"
     9  	"google.golang.org/grpc/codes"
    10  	"google.golang.org/grpc/status"
    11  
    12  	"github.com/cosmos/cosmos-sdk/baseapp"
    13  	"github.com/cosmos/cosmos-sdk/client"
    14  	codectypes "github.com/cosmos/cosmos-sdk/codec/types"
    15  	cryptocodec "github.com/cosmos/cosmos-sdk/crypto/codec"
    16  	cryptotypes "github.com/cosmos/cosmos-sdk/crypto/types"
    17  	sdk "github.com/cosmos/cosmos-sdk/types"
    18  	qtypes "github.com/cosmos/cosmos-sdk/types/query"
    19  	"github.com/cosmos/cosmos-sdk/version"
    20  )
    21  
    22  var (
    23  	_ ServiceServer                      = queryServer{}
    24  	_ codectypes.UnpackInterfacesMessage = &GetLatestValidatorSetResponse{}
    25  )
    26  
    27  type (
    28  	abciQueryFn = func(context.Context, *abci.RequestQuery) (*abci.ResponseQuery, error)
    29  
    30  	queryServer struct {
    31  		clientCtx         client.Context
    32  		interfaceRegistry codectypes.InterfaceRegistry
    33  		queryFn           abciQueryFn
    34  	}
    35  )
    36  
    37  // NewQueryServer creates a new CometBFT query server.
    38  func NewQueryServer(
    39  	clientCtx client.Context,
    40  	interfaceRegistry codectypes.InterfaceRegistry,
    41  	queryFn abciQueryFn,
    42  ) ServiceServer {
    43  	return queryServer{
    44  		clientCtx:         clientCtx,
    45  		interfaceRegistry: interfaceRegistry,
    46  		queryFn:           queryFn,
    47  	}
    48  }
    49  
    50  // GetSyncing implements ServiceServer.GetSyncing
    51  func (s queryServer) GetSyncing(ctx context.Context, _ *GetSyncingRequest) (*GetSyncingResponse, error) {
    52  	status, err := GetNodeStatus(ctx, s.clientCtx)
    53  	if err != nil {
    54  		return nil, err
    55  	}
    56  
    57  	return &GetSyncingResponse{
    58  		Syncing: status.SyncInfo.CatchingUp,
    59  	}, nil
    60  }
    61  
    62  // GetLatestBlock implements ServiceServer.GetLatestBlock
    63  func (s queryServer) GetLatestBlock(ctx context.Context, _ *GetLatestBlockRequest) (*GetLatestBlockResponse, error) {
    64  	status, err := getBlock(ctx, s.clientCtx, nil)
    65  	if err != nil {
    66  		return nil, err
    67  	}
    68  
    69  	protoBlockID := status.BlockID.ToProto()
    70  	protoBlock, err := status.Block.ToProto()
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  
    75  	return &GetLatestBlockResponse{
    76  		BlockId:  &protoBlockID,
    77  		Block:    protoBlock,
    78  		SdkBlock: convertBlock(protoBlock),
    79  	}, nil
    80  }
    81  
    82  // GetBlockByHeight implements ServiceServer.GetBlockByHeight
    83  func (s queryServer) GetBlockByHeight(ctx context.Context, req *GetBlockByHeightRequest) (*GetBlockByHeightResponse, error) {
    84  	blockHeight, err := getBlockHeight(ctx, s.clientCtx)
    85  	if err != nil {
    86  		return nil, err
    87  	}
    88  
    89  	if req.Height > blockHeight {
    90  		return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length")
    91  	}
    92  
    93  	protoBlockID, protoBlock, err := GetProtoBlock(ctx, s.clientCtx, &req.Height)
    94  	if err != nil {
    95  		return nil, err
    96  	}
    97  
    98  	return &GetBlockByHeightResponse{
    99  		BlockId:  &protoBlockID,
   100  		Block:    protoBlock,
   101  		SdkBlock: convertBlock(protoBlock),
   102  	}, nil
   103  }
   104  
   105  // GetLatestValidatorSet implements ServiceServer.GetLatestValidatorSet
   106  func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestValidatorSetRequest) (*GetLatestValidatorSetResponse, error) {
   107  	page, limit, err := qtypes.ParsePagination(req.Pagination)
   108  	if err != nil {
   109  		return nil, err
   110  	}
   111  
   112  	return ValidatorsOutput(ctx, s.clientCtx, nil, page, limit)
   113  }
   114  
   115  func (m *GetLatestValidatorSetResponse) UnpackInterfaces(unpacker codectypes.AnyUnpacker) error {
   116  	var pubKey cryptotypes.PubKey
   117  	for _, val := range m.Validators {
   118  		err := unpacker.UnpackAny(val.PubKey, &pubKey)
   119  		if err != nil {
   120  			return err
   121  		}
   122  	}
   123  
   124  	return nil
   125  }
   126  
   127  // GetValidatorSetByHeight implements ServiceServer.GetValidatorSetByHeight
   128  func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValidatorSetByHeightRequest) (*GetValidatorSetByHeightResponse, error) {
   129  	page, limit, err := qtypes.ParsePagination(req.Pagination)
   130  	if err != nil {
   131  		return nil, err
   132  	}
   133  
   134  	blockHeight, err := getBlockHeight(ctx, s.clientCtx)
   135  	if err != nil {
   136  		return nil, status.Error(codes.Internal, "failed to parse chain height")
   137  	}
   138  
   139  	if req.Height > blockHeight {
   140  		return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length")
   141  	}
   142  
   143  	r, err := ValidatorsOutput(ctx, s.clientCtx, &req.Height, page, limit)
   144  	if err != nil {
   145  		return nil, err
   146  	}
   147  
   148  	return &GetValidatorSetByHeightResponse{
   149  		BlockHeight: r.BlockHeight,
   150  		Validators:  r.Validators,
   151  		Pagination:  r.Pagination,
   152  	}, nil
   153  }
   154  
   155  func ValidatorsOutput(ctx context.Context, clientCtx client.Context, height *int64, page, limit int) (*GetLatestValidatorSetResponse, error) {
   156  	vs, err := getValidators(ctx, clientCtx, height, page, limit)
   157  	if err != nil {
   158  		return nil, err
   159  	}
   160  
   161  	resp := GetLatestValidatorSetResponse{
   162  		BlockHeight: vs.BlockHeight,
   163  		Validators:  make([]*Validator, len(vs.Validators)),
   164  		Pagination: &qtypes.PageResponse{
   165  			Total: uint64(vs.Total),
   166  		},
   167  	}
   168  
   169  	for i, v := range vs.Validators {
   170  		pk, err := cryptocodec.FromCmtPubKeyInterface(v.PubKey)
   171  		if err != nil {
   172  			return nil, err
   173  		}
   174  		anyPub, err := codectypes.NewAnyWithValue(pk)
   175  		if err != nil {
   176  			return nil, err
   177  		}
   178  
   179  		resp.Validators[i] = &Validator{
   180  			Address:          sdk.ConsAddress(v.Address).String(),
   181  			ProposerPriority: v.ProposerPriority,
   182  			PubKey:           anyPub,
   183  			VotingPower:      v.VotingPower,
   184  		}
   185  	}
   186  
   187  	return &resp, nil
   188  }
   189  
   190  // GetNodeInfo implements ServiceServer.GetNodeInfo
   191  func (s queryServer) GetNodeInfo(ctx context.Context, _ *GetNodeInfoRequest) (*GetNodeInfoResponse, error) {
   192  	status, err := GetNodeStatus(ctx, s.clientCtx)
   193  	if err != nil {
   194  		return nil, err
   195  	}
   196  
   197  	protoNodeInfo := status.NodeInfo.ToProto()
   198  	nodeInfo := version.NewInfo()
   199  
   200  	deps := make([]*Module, len(nodeInfo.BuildDeps))
   201  
   202  	for i, dep := range nodeInfo.BuildDeps {
   203  		deps[i] = &Module{
   204  			Path:    dep.Path,
   205  			Sum:     dep.Sum,
   206  			Version: dep.Version,
   207  		}
   208  	}
   209  
   210  	resp := GetNodeInfoResponse{
   211  		DefaultNodeInfo: protoNodeInfo,
   212  		ApplicationVersion: &VersionInfo{
   213  			AppName:          nodeInfo.AppName,
   214  			Name:             nodeInfo.Name,
   215  			GitCommit:        nodeInfo.GitCommit,
   216  			GoVersion:        nodeInfo.GoVersion,
   217  			Version:          nodeInfo.Version,
   218  			BuildTags:        nodeInfo.BuildTags,
   219  			BuildDeps:        deps,
   220  			CosmosSdkVersion: nodeInfo.CosmosSdkVersion,
   221  		},
   222  	}
   223  	return &resp, nil
   224  }
   225  
   226  func (s queryServer) ABCIQuery(ctx context.Context, req *ABCIQueryRequest) (*ABCIQueryResponse, error) {
   227  	if s.queryFn == nil {
   228  		return nil, status.Error(codes.Internal, "ABCI Query handler undefined")
   229  	}
   230  	if req == nil {
   231  		return nil, status.Error(codes.InvalidArgument, "empty request")
   232  	}
   233  	if len(req.Path) == 0 {
   234  		return nil, status.Error(codes.InvalidArgument, "empty query path")
   235  	}
   236  
   237  	if path := baseapp.SplitABCIQueryPath(req.Path); len(path) > 0 {
   238  		switch path[0] {
   239  		case baseapp.QueryPathApp, baseapp.QueryPathStore, baseapp.QueryPathP2P, baseapp.QueryPathCustom:
   240  			// valid path
   241  
   242  		default:
   243  			// Otherwise, error as to prevent either valid gRPC service requests or
   244  			// bogus ABCI queries.
   245  			return nil, status.Errorf(codes.InvalidArgument, "unsupported ABCI query path: %s", req.Path)
   246  		}
   247  	}
   248  
   249  	res, err := s.queryFn(ctx, req.ToABCIRequestQuery())
   250  	if err != nil {
   251  		return nil, err
   252  	}
   253  	return FromABCIResponseQuery(res), nil
   254  }
   255  
   256  // RegisterTendermintService registers the CometBFT queries on the gRPC router.
   257  func RegisterTendermintService(
   258  	clientCtx client.Context,
   259  	server gogogrpc.Server,
   260  	iRegistry codectypes.InterfaceRegistry,
   261  	queryFn abciQueryFn,
   262  ) {
   263  	RegisterServiceServer(server, NewQueryServer(clientCtx, iRegistry, queryFn))
   264  }
   265  
   266  // RegisterGRPCGatewayRoutes mounts the CometBFT service's GRPC-gateway routes on the
   267  // given Mux.
   268  func RegisterGRPCGatewayRoutes(clientConn gogogrpc.ClientConn, mux *runtime.ServeMux) {
   269  	_ = RegisterServiceHandlerClient(context.Background(), mux, NewServiceClient(clientConn))
   270  }