forked from cosmos/cosmos-sdk
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
gRPC-gateway routes as alternative to legacy tendermint REST endpoints (
cosmos#7965) * WIP * WIP setup * WIP setup testsuite * add node_info * add GetLatestBlock,GetBlockByHeight grpc endpoints * add GetValidatorSetByHeight, GetLatestValidatorSet * fix lint * fix tests * proto format * Update Makefile * review changes * Makefile format * handle nil pagination * rename query.go to service.go * format Makefile * format Makefile * review changes * review changes Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
- Loading branch information
1 parent
a9dd334
commit c58a892
Showing
16 changed files
with
5,153 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package tmservice | ||
|
||
import ( | ||
"context" | ||
|
||
ctypes "github.com/tendermint/tendermint/rpc/core/types" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
) | ||
|
||
func getBlock(clientCtx client.Context, height *int64) (*ctypes.ResultBlock, error) { | ||
// get the node | ||
node, err := clientCtx.GetNode() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return node.Block(context.Background(), height) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
package tmservice | ||
|
||
import ( | ||
"context" | ||
|
||
gogogrpc "github.com/gogo/protobuf/grpc" | ||
"github.com/grpc-ecosystem/grpc-gateway/runtime" | ||
"google.golang.org/grpc/codes" | ||
"google.golang.org/grpc/status" | ||
|
||
"github.com/cosmos/cosmos-sdk/client" | ||
"github.com/cosmos/cosmos-sdk/client/rpc" | ||
codectypes "github.com/cosmos/cosmos-sdk/codec/types" | ||
qtypes "github.com/cosmos/cosmos-sdk/types/query" | ||
"github.com/cosmos/cosmos-sdk/version" | ||
) | ||
|
||
// This is the struct that we will implement all the handlers on. | ||
type queryServer struct { | ||
clientCtx client.Context | ||
interfaceRegistry codectypes.InterfaceRegistry | ||
} | ||
|
||
var _ qtypes.ServiceServer = queryServer{} | ||
|
||
// NewQueryServer creates a new tendermint query server. | ||
func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) qtypes.ServiceServer { | ||
return queryServer{ | ||
clientCtx: clientCtx, | ||
interfaceRegistry: interfaceRegistry, | ||
} | ||
} | ||
|
||
// GetSyncing implements ServiceServer.GetSyncing | ||
func (s queryServer) GetSyncing(_ context.Context, _ *qtypes.GetSyncingRequest) (*qtypes.GetSyncingResponse, error) { | ||
status, err := getNodeStatus(s.clientCtx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &qtypes.GetSyncingResponse{ | ||
Syncing: status.SyncInfo.CatchingUp, | ||
}, nil | ||
} | ||
|
||
// GetLatestBlock implements ServiceServer.GetLatestBlock | ||
func (s queryServer) GetLatestBlock(context.Context, *qtypes.GetLatestBlockRequest) (*qtypes.GetLatestBlockResponse, error) { | ||
status, err := getBlock(s.clientCtx, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
protoBlockID := status.BlockID.ToProto() | ||
protoBlock, err := status.Block.ToProto() | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
return &qtypes.GetLatestBlockResponse{ | ||
BlockId: &protoBlockID, | ||
Block: protoBlock, | ||
}, nil | ||
} | ||
|
||
// GetBlockByHeight implements ServiceServer.GetBlockByHeight | ||
func (s queryServer) GetBlockByHeight(_ context.Context, req *qtypes.GetBlockByHeightRequest) (*qtypes.GetBlockByHeightResponse, error) { | ||
chainHeight, err := rpc.GetChainHeight(s.clientCtx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
if req.Height > chainHeight { | ||
return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length") | ||
} | ||
|
||
res, err := getBlock(s.clientCtx, &req.Height) | ||
if err != nil { | ||
return nil, err | ||
} | ||
protoBlockID := res.BlockID.ToProto() | ||
protoBlock, err := res.Block.ToProto() | ||
if err != nil { | ||
return nil, err | ||
} | ||
return &qtypes.GetBlockByHeightResponse{ | ||
BlockId: &protoBlockID, | ||
Block: protoBlock, | ||
}, nil | ||
} | ||
|
||
// GetLatestValidatorSet implements ServiceServer.GetLatestValidatorSet | ||
func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *qtypes.GetLatestValidatorSetRequest) (*qtypes.GetLatestValidatorSetResponse, error) { | ||
page, limit, err := qtypes.ParsePagination(req.Pagination) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
validatorsRes, err := rpc.GetValidators(s.clientCtx, nil, &page, &limit) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
outputValidatorsRes := &qtypes.GetLatestValidatorSetResponse{ | ||
BlockHeight: validatorsRes.BlockHeight, | ||
Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)), | ||
} | ||
|
||
for i, validator := range validatorsRes.Validators { | ||
outputValidatorsRes.Validators[i] = &qtypes.Validator{ | ||
Address: validator.Address, | ||
ProposerPriority: validator.ProposerPriority, | ||
PubKey: validator.PubKey, | ||
VotingPower: validator.VotingPower, | ||
} | ||
} | ||
return outputValidatorsRes, nil | ||
} | ||
|
||
// GetValidatorSetByHeight implements ServiceServer.GetValidatorSetByHeight | ||
func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *qtypes.GetValidatorSetByHeightRequest) (*qtypes.GetValidatorSetByHeightResponse, error) { | ||
page, limit, err := qtypes.ParsePagination(req.Pagination) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
chainHeight, err := rpc.GetChainHeight(s.clientCtx) | ||
if err != nil { | ||
return nil, status.Error(codes.Internal, "failed to parse chain height") | ||
} | ||
if req.Height > chainHeight { | ||
return nil, status.Error(codes.InvalidArgument, "requested block height is bigger then the chain length") | ||
} | ||
|
||
validatorsRes, err := rpc.GetValidators(s.clientCtx, &req.Height, &page, &limit) | ||
|
||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
outputValidatorsRes := &qtypes.GetValidatorSetByHeightResponse{ | ||
BlockHeight: validatorsRes.BlockHeight, | ||
Validators: make([]*qtypes.Validator, len(validatorsRes.Validators)), | ||
} | ||
|
||
for i, validator := range validatorsRes.Validators { | ||
outputValidatorsRes.Validators[i] = &qtypes.Validator{ | ||
Address: validator.Address, | ||
ProposerPriority: validator.ProposerPriority, | ||
PubKey: validator.PubKey, | ||
VotingPower: validator.VotingPower, | ||
} | ||
} | ||
return outputValidatorsRes, nil | ||
} | ||
|
||
// GetNodeInfo implements ServiceServer.GetNodeInfo | ||
func (s queryServer) GetNodeInfo(ctx context.Context, req *qtypes.GetNodeInfoRequest) (*qtypes.GetNodeInfoResponse, error) { | ||
status, err := getNodeStatus(s.clientCtx) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
protoNodeInfo := status.NodeInfo.ToProto() | ||
nodeInfo := version.NewInfo() | ||
|
||
deps := make([]*qtypes.Module, len(nodeInfo.BuildDeps)) | ||
|
||
for i, dep := range nodeInfo.BuildDeps { | ||
deps[i] = &qtypes.Module{ | ||
Path: dep.Path, | ||
Sum: dep.Sum, | ||
Version: dep.Version, | ||
} | ||
} | ||
|
||
resp := qtypes.GetNodeInfoResponse{ | ||
DefaultNodeInfo: protoNodeInfo, | ||
ApplicationVersion: &qtypes.VersionInfo{ | ||
AppName: nodeInfo.AppName, | ||
Name: nodeInfo.Name, | ||
GitCommit: nodeInfo.GitCommit, | ||
GoVersion: nodeInfo.GoVersion, | ||
Version: nodeInfo.Version, | ||
BuildTags: nodeInfo.BuildTags, | ||
BuildDeps: deps, | ||
}, | ||
} | ||
return &resp, nil | ||
} | ||
|
||
// RegisterTendermintService registers the tendermint queries on the gRPC router. | ||
func RegisterTendermintService( | ||
qrt gogogrpc.Server, | ||
clientCtx client.Context, | ||
interfaceRegistry codectypes.InterfaceRegistry, | ||
) { | ||
qtypes.RegisterServiceServer( | ||
qrt, | ||
NewQueryServer(clientCtx, interfaceRegistry), | ||
) | ||
} | ||
|
||
// RegisterGRPCGatewayRoutes mounts the tendermint service's GRPC-gateway routes on the | ||
// given Mux. | ||
func RegisterGRPCGatewayRoutes(clientConn gogogrpc.ClientConn, mux *runtime.ServeMux) { | ||
qtypes.RegisterServiceHandlerClient(context.Background(), mux, qtypes.NewServiceClient(clientConn)) | ||
} |
Oops, something went wrong.