Skip to content

Commit

Permalink
fix(simapp/v2): register extra gRPC gateway routes (backport #22786) (#…
Browse files Browse the repository at this point in the history
…22798)

Co-authored-by: Julien Robert <[email protected]>
  • Loading branch information
mergify[bot] and julienrbrt authored Dec 9, 2024
1 parent aa9a8d9 commit db667a8
Show file tree
Hide file tree
Showing 2 changed files with 166 additions and 60 deletions.
195 changes: 142 additions & 53 deletions server/v2/cometbft/grpc.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package cometbft
import (
"context"
"fmt"
"strings"

abci "github.com/cometbft/cometbft/abci/types"
abciproto "github.com/cometbft/cometbft/api/cometbft/abci/v1"
Expand All @@ -24,6 +25,8 @@ import (
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/x/auth/migrations/legacytx"
authtx "github.com/cosmos/cosmos-sdk/x/auth/tx"
)

type appSimulator[T transaction.Tx] interface {
Expand All @@ -50,51 +53,6 @@ func gRPCServiceRegistrar[T transaction.Tx](
}
}

// CometBFTAutoCLIDescriptor is the auto-generated CLI descriptor for the CometBFT service
var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{
Service: cmtv1beta1.Service_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "GetNodeInfo",
Use: "node-info",
Short: "Query the current node info",
},
{
RpcMethod: "GetSyncing",
Use: "syncing",
Short: "Query node syncing status",
},
{
RpcMethod: "GetLatestBlock",
Use: "block-latest",
Short: "Query for the latest committed block",
},
{
RpcMethod: "GetBlockByHeight",
Use: "block-by-height <height>",
Short: "Query for a committed block by height",
Long: "Query for a specific committed block using the CometBFT RPC `block_by_height` method",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}},
},
{
RpcMethod: "GetLatestValidatorSet",
Use: "validator-set",
Alias: []string{"validator-set-latest", "comet-validator-set", "cometbft-validator-set", "tendermint-validator-set"},
Short: "Query for the latest validator set",
},
{
RpcMethod: "GetValidatorSetByHeight",
Use: "validator-set-by-height <height>",
Short: "Query for a validator set by height",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}},
},
{
RpcMethod: "ABCIQuery",
Skip: true,
},
},
}

type txServer[T transaction.Tx] struct {
clientCtx client.Context
txCodec transaction.Codec[T]
Expand All @@ -112,8 +70,33 @@ func (t txServer[T]) GetBlockWithTxs(context.Context, *txtypes.GetBlockWithTxsRe
}

// GetTx implements tx.ServiceServer.
func (t txServer[T]) GetTx(context.Context, *txtypes.GetTxRequest) (*txtypes.GetTxResponse, error) {
return nil, status.Error(codes.Unimplemented, "not implemented")
func (t txServer[T]) GetTx(ctx context.Context, req *txtypes.GetTxRequest) (*txtypes.GetTxResponse, error) {
if req == nil {
return nil, status.Error(codes.InvalidArgument, "request cannot be nil")
}

if len(req.Hash) == 0 {
return nil, status.Error(codes.InvalidArgument, "tx hash cannot be empty")
}

result, err := authtx.QueryTx(t.clientCtx, req.Hash)
if err != nil {
if strings.Contains(err.Error(), "not found") {
return nil, status.Errorf(codes.NotFound, "tx not found: %s", req.Hash)
}

return nil, err
}

protoTx, ok := result.Tx.GetCachedValue().(*txtypes.Tx)
if !ok {
return nil, status.Errorf(codes.Internal, "expected %T, got %T", txtypes.Tx{}, result.Tx.GetCachedValue())
}

return &txtypes.GetTxResponse{
Tx: protoTx,
TxResponse: result,
}, nil
}

// GetTxsEvent implements tx.ServiceServer.
Expand Down Expand Up @@ -181,18 +164,79 @@ func (t txServer[T]) TxDecode(context.Context, *txtypes.TxDecodeRequest) (*txtyp
}

// TxDecodeAmino implements tx.ServiceServer.
func (t txServer[T]) TxDecodeAmino(context.Context, *txtypes.TxDecodeAminoRequest) (*txtypes.TxDecodeAminoResponse, error) {
return nil, status.Error(codes.Unimplemented, "not implemented")
func (t txServer[T]) TxDecodeAmino(_ context.Context, req *txtypes.TxDecodeAminoRequest) (*txtypes.TxDecodeAminoResponse, error) {
if req.AminoBinary == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx bytes")
}

var stdTx legacytx.StdTx
err := t.clientCtx.LegacyAmino.Unmarshal(req.AminoBinary, &stdTx)
if err != nil {
return nil, err
}

res, err := t.clientCtx.LegacyAmino.MarshalJSON(stdTx)
if err != nil {
return nil, err
}

return &txtypes.TxDecodeAminoResponse{
AminoJson: string(res),
}, nil
}

// TxEncode implements tx.ServiceServer.
func (t txServer[T]) TxEncode(context.Context, *txtypes.TxEncodeRequest) (*txtypes.TxEncodeResponse, error) {
return nil, status.Error(codes.Unimplemented, "not implemented")
func (t txServer[T]) TxEncode(_ context.Context, req *txtypes.TxEncodeRequest) (*txtypes.TxEncodeResponse, error) {
if req.Tx == nil {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx")
}

bodyBytes, err := t.clientCtx.Codec.Marshal(req.Tx.Body)
if err != nil {
return nil, err
}

authInfoBytes, err := t.clientCtx.Codec.Marshal(req.Tx.AuthInfo)
if err != nil {
return nil, err
}

raw := &txtypes.TxRaw{
BodyBytes: bodyBytes,
AuthInfoBytes: authInfoBytes,
Signatures: req.Tx.Signatures,
}

encodedBytes, err := t.clientCtx.Codec.Marshal(raw)
if err != nil {
return nil, err
}

return &txtypes.TxEncodeResponse{
TxBytes: encodedBytes,
}, nil
}

// TxEncodeAmino implements tx.ServiceServer.
func (t txServer[T]) TxEncodeAmino(context.Context, *txtypes.TxEncodeAminoRequest) (*txtypes.TxEncodeAminoResponse, error) {
return nil, status.Error(codes.Unimplemented, "not implemented")
func (t txServer[T]) TxEncodeAmino(_ context.Context, req *txtypes.TxEncodeAminoRequest) (*txtypes.TxEncodeAminoResponse, error) {
if req.AminoJson == "" {
return nil, status.Error(codes.InvalidArgument, "invalid empty tx json")
}

var stdTx legacytx.StdTx
err := t.clientCtx.LegacyAmino.UnmarshalJSON([]byte(req.AminoJson), &stdTx)
if err != nil {
return nil, err
}

encodedBytes, err := t.clientCtx.LegacyAmino.Marshal(stdTx)
if err != nil {
return nil, err
}

return &txtypes.TxEncodeAminoResponse{
AminoBinary: encodedBytes,
}, nil
}

var _ txtypes.ServiceServer = txServer[transaction.Tx]{}
Expand Down Expand Up @@ -236,3 +280,48 @@ func (s nodeServer[T]) Status(ctx context.Context, _ *nodeservice.StatusRequest)
ValidatorHash: nodeInfo.LastBlockAppHash,
}, nil
}

// CometBFTAutoCLIDescriptor is the auto-generated CLI descriptor for the CometBFT service
var CometBFTAutoCLIDescriptor = &autocliv1.ServiceCommandDescriptor{
Service: cmtv1beta1.Service_ServiceDesc.ServiceName,
RpcCommandOptions: []*autocliv1.RpcCommandOptions{
{
RpcMethod: "GetNodeInfo",
Use: "node-info",
Short: "Query the current node info",
},
{
RpcMethod: "GetSyncing",
Use: "syncing",
Short: "Query node syncing status",
},
{
RpcMethod: "GetLatestBlock",
Use: "block-latest",
Short: "Query for the latest committed block",
},
{
RpcMethod: "GetBlockByHeight",
Use: "block-by-height <height>",
Short: "Query for a committed block by height",
Long: "Query for a specific committed block using the CometBFT RPC `block_by_height` method",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}},
},
{
RpcMethod: "GetLatestValidatorSet",
Use: "validator-set",
Alias: []string{"validator-set-latest", "comet-validator-set", "cometbft-validator-set", "tendermint-validator-set"},
Short: "Query for the latest validator set",
},
{
RpcMethod: "GetValidatorSetByHeight",
Use: "validator-set-by-height <height>",
Short: "Query for a validator set by height",
PositionalArgs: []*autocliv1.PositionalArgDescriptor{{ProtoField: "height"}},
},
{
RpcMethod: "ABCIQuery",
Skip: true,
},
},
}
31 changes: 24 additions & 7 deletions simapp/v2/simdv2/cmd/commands.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package cmd

import (
"context"
"io"

"github.com/spf13/cobra"
Expand All @@ -23,11 +24,14 @@ import (
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/config"
"github.com/cosmos/cosmos-sdk/client/debug"
"github.com/cosmos/cosmos-sdk/client/grpc/cmtservice"
nodeservice "github.com/cosmos/cosmos-sdk/client/grpc/node"
"github.com/cosmos/cosmos-sdk/client/keys"
"github.com/cosmos/cosmos-sdk/client/rpc"
sdktelemetry "github.com/cosmos/cosmos-sdk/telemetry"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
txtypes "github.com/cosmos/cosmos-sdk/types/tx"
"github.com/cosmos/cosmos-sdk/version"
authcmd "github.com/cosmos/cosmos-sdk/x/auth/client/cli"
"github.com/cosmos/cosmos-sdk/x/genutil"
Expand Down Expand Up @@ -153,13 +157,7 @@ func InitRootCmd[T transaction.Tx](
if err != nil {
return nil, err
}

for _, mod := range deps.ModuleManager.Modules() {
if gmod, ok := mod.(module.HasGRPCGateway); ok {
// TODO(@julienrbrt) https://github.com/cosmos/cosmos-sdk/pull/22701#pullrequestreview-2470651390
gmod.RegisterGRPCGatewayRoutes(deps.ClientContext, grpcgatewayServer.GRPCGatewayRouter)
}
}
registerGRPCGatewayRoutes[T](deps, grpcgatewayServer)

// wire server commands
return serverv2.AddCommands[T](
Expand Down Expand Up @@ -264,3 +262,22 @@ func RootCommandPersistentPreRun(clientCtx client.Context) func(*cobra.Command,
return nil
}
}

// registerGRPCGatewayRoutes registers the gRPC gateway routes for all modules and other components
// TODO(@julienrbrt): Eventually, this should removed and directly done within the grpcgateway.Server
// ref: https://github.com/cosmos/cosmos-sdk/pull/22701#pullrequestreview-2470651390
func registerGRPCGatewayRoutes[T transaction.Tx](
deps CommandDependencies[T],
server *grpcgateway.Server[T],
) {
// those are the extra services that the CometBFT server implements (server/v2/cometbft/grpc.go)
cmtservice.RegisterGRPCGatewayRoutes(deps.ClientContext, server.GRPCGatewayRouter)
_ = nodeservice.RegisterServiceHandlerClient(context.Background(), server.GRPCGatewayRouter, nodeservice.NewServiceClient(deps.ClientContext))
_ = txtypes.RegisterServiceHandlerClient(context.Background(), server.GRPCGatewayRouter, txtypes.NewServiceClient(deps.ClientContext))

for _, mod := range deps.ModuleManager.Modules() {
if gmod, ok := mod.(module.HasGRPCGateway); ok {
gmod.RegisterGRPCGatewayRoutes(deps.ClientContext, server.GRPCGatewayRouter)
}
}
}

0 comments on commit db667a8

Please sign in to comment.