feat: implement ABCI Query via gRPC (#11642)

This commit is contained in:
Aleksandr Bezobchuk 2022-04-25 17:54:27 -04:00 committed by GitHub
parent 3c2c937df2
commit 3daa660505
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 5007 additions and 356 deletions

View File

@ -39,6 +39,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### Features
* (grpc) [\#11642](https://github.com/cosmos/cosmos-sdk/pull/11642) Implement `ABCIQuery` in the Tendermint gRPC service, which proxies ABCI `Query` requests directly to the application.
* (x/upgrade) [\#11551](https://github.com/cosmos/cosmos-sdk/pull/11551) Update `ScheduleUpgrade` for chains to schedule an automated upgrade on `BeginBlock` without having to go though governance.
* (cli) [\#11548](https://github.com/cosmos/cosmos-sdk/pull/11548) Add Tendermint's `inspect` command to the `tendermint` sub-command.
* (tx) [#\11533](https://github.com/cosmos/cosmos-sdk/pull/11533) Register [`EIP191`](https://eips.ethereum.org/EIPS/eip-191) as an available `SignMode` for chains to use.
@ -85,6 +86,7 @@ Ref: https://keepachangelog.com/en/1.0.0/
### API Breaking Changes
* (grpc) [\#11642](https://github.com/cosmos/cosmos-sdk/pull/11642) The `RegisterTendermintService` method in the `tmservice` package now requires a `abciQueryFn` query function parameter.
* [\#11496](https://github.com/cosmos/cosmos-sdk/pull/11496) Refactor abstractions for snapshot and pruning; snapshot intervals eventually pruned; unit tests.
* (types) [\#11689](https://github.com/cosmos/cosmos-sdk/pull/11689) Make `Coins#Sub` and `Coins#SafeSub` consistent with `Coins#Add`.
* (store)[\#11152](https://github.com/cosmos/cosmos-sdk/pull/11152) Remove `keep-every` from pruning options.

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,12 @@ type ServiceClient interface {
GetLatestValidatorSet(ctx context.Context, in *GetLatestValidatorSetRequest, opts ...grpc.CallOption) (*GetLatestValidatorSetResponse, error)
// GetValidatorSetByHeight queries validator-set at a given height.
GetValidatorSetByHeight(ctx context.Context, in *GetValidatorSetByHeightRequest, opts ...grpc.CallOption) (*GetValidatorSetByHeightResponse, error)
// ABCIQuery defines a query handler that supports ABCI queries directly to the
// application, bypassing Tendermint completely. The ABCI query must contain
// a valid and supported path, including app, custom, p2p, and store.
//
// Since: cosmos-sdk 0.46
ABCIQuery(ctx context.Context, in *ABCIQueryRequest, opts ...grpc.CallOption) (*ABCIQueryResponse, error)
}
type serviceClient struct {
@ -98,6 +104,15 @@ func (c *serviceClient) GetValidatorSetByHeight(ctx context.Context, in *GetVali
return out, nil
}
func (c *serviceClient) ABCIQuery(ctx context.Context, in *ABCIQueryRequest, opts ...grpc.CallOption) (*ABCIQueryResponse, error) {
out := new(ABCIQueryResponse)
err := c.cc.Invoke(ctx, "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery", in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ServiceServer is the server API for Service service.
// All implementations must embed UnimplementedServiceServer
// for forward compatibility
@ -114,6 +129,12 @@ type ServiceServer interface {
GetLatestValidatorSet(context.Context, *GetLatestValidatorSetRequest) (*GetLatestValidatorSetResponse, error)
// GetValidatorSetByHeight queries validator-set at a given height.
GetValidatorSetByHeight(context.Context, *GetValidatorSetByHeightRequest) (*GetValidatorSetByHeightResponse, error)
// ABCIQuery defines a query handler that supports ABCI queries directly to the
// application, bypassing Tendermint completely. The ABCI query must contain
// a valid and supported path, including app, custom, p2p, and store.
//
// Since: cosmos-sdk 0.46
ABCIQuery(context.Context, *ABCIQueryRequest) (*ABCIQueryResponse, error)
mustEmbedUnimplementedServiceServer()
}
@ -139,6 +160,9 @@ func (UnimplementedServiceServer) GetLatestValidatorSet(context.Context, *GetLat
func (UnimplementedServiceServer) GetValidatorSetByHeight(context.Context, *GetValidatorSetByHeightRequest) (*GetValidatorSetByHeightResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetValidatorSetByHeight not implemented")
}
func (UnimplementedServiceServer) ABCIQuery(context.Context, *ABCIQueryRequest) (*ABCIQueryResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ABCIQuery not implemented")
}
func (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {}
// UnsafeServiceServer may be embedded to opt out of forward compatibility for this service.
@ -260,6 +284,24 @@ func _Service_GetValidatorSetByHeight_Handler(srv interface{}, ctx context.Conte
return interceptor(ctx, in, info, handler)
}
func _Service_ABCIQuery_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ABCIQueryRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ServiceServer).ABCIQuery(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ServiceServer).ABCIQuery(ctx, req.(*ABCIQueryRequest))
}
return interceptor(ctx, in, info, handler)
}
// Service_ServiceDesc is the grpc.ServiceDesc for Service service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
@ -291,6 +333,10 @@ var Service_ServiceDesc = grpc.ServiceDesc{
MethodName: "GetValidatorSetByHeight",
Handler: _Service_GetValidatorSetByHeight_Handler,
},
{
MethodName: "ABCIQuery",
Handler: _Service_ABCIQuery_Handler,
},
},
Streams: []grpc.StreamDesc{},
Metadata: "cosmos/base/tendermint/v1beta1/query.proto",

View File

@ -22,6 +22,14 @@ import (
"github.com/cosmos/cosmos-sdk/types/tx"
)
// Supported ABCI Query prefixes
const (
QueryPathApp = "app"
QueryPathCustom = "custom"
QueryPathP2P = "p2p"
QueryPathStore = "store"
)
// InitChain implements the ABCI interface. It runs the initialization logic
// directly on the CommitMultiStore.
func (app *BaseApp) InitChain(req abci.RequestInitChain) (res abci.ResponseInitChain) {
@ -371,7 +379,6 @@ func (app *BaseApp) halt() {
// Query implements the ABCI interface. It delegates to CommitMultiStore if it
// implements Queryable.
func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
// Add panic recovery for all queries.
// ref: https://github.com/cosmos/cosmos-sdk/pull/8039
defer func() {
@ -391,23 +398,23 @@ func (app *BaseApp) Query(req abci.RequestQuery) (res abci.ResponseQuery) {
return app.handleQueryGRPC(grpcHandler, req)
}
path := splitPath(req.Path)
path := SplitABCIQueryPath(req.Path)
if len(path) == 0 {
sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided"), app.trace)
}
switch path[0] {
// "/app" prefix for special application queries
case "app":
case QueryPathApp:
// "/app" prefix for special application queries
return handleQueryApp(app, path, req)
case "store":
case QueryPathStore:
return handleQueryStore(app, path, req)
case "p2p":
case QueryPathP2P:
return handleQueryP2P(app, path)
case "custom":
case QueryPathCustom:
return handleQueryCustom(app, path, req)
}
@ -839,10 +846,10 @@ func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.
}
}
// splitPath splits a string path using the delimiter '/'.
// SplitABCIQueryPath splits a string path using the delimiter '/'.
//
// e.g. "this/is/funny" becomes []string{"this", "is", "funny"}
func splitPath(requestPath string) (path []string) {
func SplitABCIQueryPath(requestPath string) (path []string) {
path = strings.Split(requestPath, "/")
// first element is empty string

View File

@ -3,16 +3,13 @@ package baseapp
import (
"fmt"
"google.golang.org/grpc/encoding"
"github.com/cosmos/cosmos-sdk/codec"
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
gogogrpc "github.com/gogo/protobuf/grpc"
abci "github.com/tendermint/tendermint/abci/types"
"google.golang.org/grpc"
"google.golang.org/grpc/encoding"
"github.com/cosmos/cosmos-sdk/client/grpc/reflection"
"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
)

File diff suppressed because it is too large Load Diff

View File

@ -249,6 +249,42 @@ func local_request_Service_GetValidatorSetByHeight_0(ctx context.Context, marsha
}
var (
filter_Service_ABCIQuery_0 = &utilities.DoubleArray{Encoding: map[string]int{}, Base: []int(nil), Check: []int(nil)}
)
func request_Service_ABCIQuery_0(ctx context.Context, marshaler runtime.Marshaler, client ServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ABCIQueryRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_ABCIQuery_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ABCIQuery(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_Service_ABCIQuery_0(ctx context.Context, marshaler runtime.Marshaler, server ServiceServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ABCIQueryRequest
var metadata runtime.ServerMetadata
if err := req.ParseForm(); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
if err := runtime.PopulateQueryParameters(&protoReq, req.Form, filter_Service_ABCIQuery_0); err != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ABCIQuery(ctx, &protoReq)
return msg, metadata, err
}
// RegisterServiceHandlerServer registers the http handlers for service Service to "mux".
// UnaryRPC :call ServiceServer directly.
// StreamingRPC :currently unsupported pending https://github.com/grpc/grpc-go/issues/906.
@ -393,6 +429,29 @@ func RegisterServiceHandlerServer(ctx context.Context, mux *runtime.ServeMux, se
})
mux.Handle("GET", pattern_Service_ABCIQuery_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateIncomingContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_Service_ABCIQuery_0(rctx, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_ABCIQuery_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@ -554,6 +613,26 @@ func RegisterServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, cl
})
mux.Handle("GET", pattern_Service_ABCIQuery_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
rctx, err := runtime.AnnotateContext(ctx, mux, req)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_Service_ABCIQuery_0(rctx, inboundMarshaler, client, req, pathParams)
ctx = runtime.NewServerMetadataContext(ctx, md)
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
forward_Service_ABCIQuery_0(ctx, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
return nil
}
@ -569,6 +648,8 @@ var (
pattern_Service_GetLatestValidatorSet_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 2, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validatorsets", "latest"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_GetValidatorSetByHeight_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4, 1, 0, 4, 1, 5, 5}, []string{"cosmos", "base", "tendermint", "v1beta1", "validatorsets", "height"}, "", runtime.AssumeColonVerbOpt(false)))
pattern_Service_ABCIQuery_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2, 2, 3, 2, 4}, []string{"cosmos", "base", "tendermint", "v1beta1", "abci_query"}, "", runtime.AssumeColonVerbOpt(false)))
)
var (
@ -583,4 +664,6 @@ var (
forward_Service_GetLatestValidatorSet_0 = runtime.ForwardResponseMessage
forward_Service_GetValidatorSetByHeight_0 = runtime.ForwardResponseMessage
forward_Service_ABCIQuery_0 = runtime.ForwardResponseMessage
)

View File

@ -5,9 +5,11 @@ import (
gogogrpc "github.com/gogo/protobuf/grpc"
"github.com/grpc-ecosystem/grpc-gateway/runtime"
abci "github.com/tendermint/tendermint/abci/types"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"github.com/cosmos/cosmos-sdk/baseapp"
"github.com/cosmos/cosmos-sdk/client"
"github.com/cosmos/cosmos-sdk/client/rpc"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
@ -16,20 +18,31 @@ import (
"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 (
_ ServiceServer = queryServer{}
_ codectypes.UnpackInterfacesMessage = &GetLatestValidatorSetResponse{}
)
var _ ServiceServer = queryServer{}
var _ codectypes.UnpackInterfacesMessage = &GetLatestValidatorSetResponse{}
type (
abciQueryFn = func(abci.RequestQuery) abci.ResponseQuery
queryServer struct {
clientCtx client.Context
interfaceRegistry codectypes.InterfaceRegistry
queryFn abciQueryFn
}
)
// NewQueryServer creates a new tendermint query server.
func NewQueryServer(clientCtx client.Context, interfaceRegistry codectypes.InterfaceRegistry) ServiceServer {
func NewQueryServer(
clientCtx client.Context,
interfaceRegistry codectypes.InterfaceRegistry,
queryFn abciQueryFn,
) ServiceServer {
return queryServer{
clientCtx: clientCtx,
interfaceRegistry: interfaceRegistry,
queryFn: queryFn,
}
}
@ -39,6 +52,7 @@ func (s queryServer) GetSyncing(ctx context.Context, _ *GetSyncingRequest) (*Get
if err != nil {
return nil, err
}
return &GetSyncingResponse{
Syncing: status.SyncInfo.CatchingUp,
}, nil
@ -78,6 +92,7 @@ func (s queryServer) GetBlockByHeight(ctx context.Context, req *GetBlockByHeight
if err != nil {
return nil, err
}
return &GetBlockByHeightResponse{
BlockId: &protoBlockID,
Block: protoBlock,
@ -90,6 +105,7 @@ func (s queryServer) GetLatestValidatorSet(ctx context.Context, req *GetLatestVa
if err != nil {
return nil, err
}
return validatorsOutput(ctx, s.clientCtx, nil, page, limit)
}
@ -101,6 +117,7 @@ func (m *GetLatestValidatorSetResponse) UnpackInterfaces(unpacker codectypes.Any
return err
}
}
return nil
}
@ -115,13 +132,16 @@ func (s queryServer) GetValidatorSetByHeight(ctx context.Context, req *GetValida
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")
}
r, err := validatorsOutput(ctx, s.clientCtx, &req.Height, page, limit)
if err != nil {
return nil, err
}
return &GetValidatorSetByHeightResponse{
BlockHeight: r.BlockHeight,
Validators: r.Validators,
@ -134,6 +154,7 @@ func validatorsOutput(ctx context.Context, cctx client.Context, height *int64, p
if err != nil {
return nil, err
}
resp := GetLatestValidatorSetResponse{
BlockHeight: vs.BlockHeight,
Validators: make([]*Validator, len(vs.Validators)),
@ -141,11 +162,13 @@ func validatorsOutput(ctx context.Context, cctx client.Context, height *int64, p
Total: vs.Total,
},
}
for i, v := range vs.Validators {
anyPub, err := codectypes.NewAnyWithValue(v.PubKey)
if err != nil {
return nil, err
}
resp.Validators[i] = &Validator{
Address: v.Address.String(),
ProposerPriority: v.ProposerPriority,
@ -153,6 +176,7 @@ func validatorsOutput(ctx context.Context, cctx client.Context, height *int64, p
VotingPower: v.VotingPower,
}
}
return &resp, nil
}
@ -192,16 +216,41 @@ func (s queryServer) GetNodeInfo(ctx context.Context, req *GetNodeInfoRequest) (
return &resp, nil
}
func (s queryServer) ABCIQuery(ctx context.Context, req *ABCIQueryRequest) (*ABCIQueryResponse, error) {
if s.queryFn == nil {
return nil, status.Error(codes.Internal, "ABCI Query handler undefined")
}
if req == nil {
return nil, status.Error(codes.InvalidArgument, "empty request")
}
if len(req.Path) == 0 {
return nil, status.Error(codes.InvalidArgument, "empty query path")
}
if path := baseapp.SplitABCIQueryPath(req.Path); len(path) > 0 {
switch path[0] {
case baseapp.QueryPathApp, baseapp.QueryPathStore, baseapp.QueryPathP2P, baseapp.QueryPathCustom:
// valid path
default:
// Otherwise, error as to prevent either valid gRPC service requests or
// bogus ABCI queries.
return nil, status.Errorf(codes.InvalidArgument, "unsupported ABCI query path: %s", req.Path)
}
}
res := s.queryFn(req.ToABCIRequestQuery())
return FromABCIResponseQuery(res), nil
}
// RegisterTendermintService registers the tendermint queries on the gRPC router.
func RegisterTendermintService(
qrt gogogrpc.Server,
clientCtx client.Context,
interfaceRegistry codectypes.InterfaceRegistry,
server gogogrpc.Server,
iRegistry codectypes.InterfaceRegistry,
queryFn abciQueryFn,
) {
RegisterServiceServer(
qrt,
NewQueryServer(clientCtx, interfaceRegistry),
)
RegisterServiceServer(server, NewQueryServer(clientCtx, iRegistry, queryFn))
}
// RegisterGRPCGatewayRoutes mounts the tendermint service's GRPC-gateway routes on the

View File

@ -19,12 +19,15 @@ import (
type IntegrationTestSuite struct {
suite.Suite
cfg network.Config
network *network.Network
cfg network.Config
network *network.Network
queryClient tmservice.ServiceClient
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
}
func (s *IntegrationTestSuite) SetupSuite() {
s.T().Log("setting up integration test suite")
@ -254,6 +257,91 @@ func (s IntegrationTestSuite) TestValidatorSetByHeight_GRPCGateway() {
}
}
func TestIntegrationTestSuite(t *testing.T) {
suite.Run(t, new(IntegrationTestSuite))
func (s IntegrationTestSuite) TestABCIQuery() {
testCases := []struct {
name string
req *tmservice.ABCIQueryRequest
expectErr bool
expectedCode uint32
validQuery bool
}{
{
name: "valid request with proof",
req: &tmservice.ABCIQueryRequest{
Path: "/store/gov/key",
Data: []byte{0x03},
Prove: true,
},
validQuery: true,
},
{
name: "valid request without proof",
req: &tmservice.ABCIQueryRequest{
Path: "/store/gov/key",
Data: []byte{0x03},
Prove: false,
},
validQuery: true,
},
{
name: "request with invalid path",
req: &tmservice.ABCIQueryRequest{
Path: "/foo/bar",
Data: []byte{0x03},
},
expectErr: true,
},
{
name: "request with invalid path recursive",
req: &tmservice.ABCIQueryRequest{
Path: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
Data: s.cfg.Codec.MustMarshal(&tmservice.ABCIQueryRequest{
Path: "/cosmos.base.tendermint.v1beta1.Service/ABCIQuery",
}),
},
expectErr: true,
},
{
name: "request with invalid broadcast tx path",
req: &tmservice.ABCIQueryRequest{
Path: "/cosmos.tx.v1beta1.Service/BroadcastTx",
Data: []byte{0x00},
},
expectErr: true,
},
{
name: "request with invalid data",
req: &tmservice.ABCIQueryRequest{
Path: "/store/gov/key",
Data: []byte{0x0044, 0x00},
},
validQuery: false,
},
}
for _, tc := range testCases {
tc := tc
s.Run(tc.name, func() {
res, err := s.queryClient.ABCIQuery(context.Background(), tc.req)
if tc.expectErr {
s.Require().Error(err)
s.Require().Nil(res)
} else {
s.Require().NoError(err)
s.Require().NotNil(res)
s.Require().Equal(res.Code, tc.expectedCode)
}
if tc.validQuery {
s.Require().Greater(res.Height, int64(0))
s.Require().Greater(len(res.Key), 0, "expected non-empty key")
s.Require().Greater(len(res.Value), 0, "expected non-empty value")
}
if tc.req.Prove {
s.Require().Greater(len(res.ProofOps.Ops), 0, "expected proofs")
}
})
}
}

View File

@ -0,0 +1,47 @@
package tmservice
import (
abci "github.com/tendermint/tendermint/abci/types"
)
// ToABCIRequestQuery converts a gRPC ABCIQueryRequest type to an ABCI
// RequestQuery type.
func (req *ABCIQueryRequest) ToABCIRequestQuery() abci.RequestQuery {
return abci.RequestQuery{
Data: req.Data,
Path: req.Path,
Height: req.Height,
Prove: req.Prove,
}
}
// FromABCIResponseQuery converts an ABCI ResponseQuery type to a gRPC
// ABCIQueryResponse type.
func FromABCIResponseQuery(res abci.ResponseQuery) *ABCIQueryResponse {
var proofOps *ProofOps
if res.ProofOps != nil {
proofOps = &ProofOps{
Ops: make([]ProofOp, len(res.ProofOps.Ops)),
}
for i, proofOp := range res.ProofOps.Ops {
proofOps.Ops[i] = ProofOp{
Type: proofOp.Type,
Key: proofOp.Key,
Data: proofOp.Data,
}
}
}
return &ABCIQueryResponse{
Code: res.Code,
Log: res.Log,
Info: res.Info,
Index: res.Index,
Key: res.Key,
Value: res.Value,
ProofOps: proofOps,
Height: res.Height,
Codespace: res.Codespace,
}
}

View File

@ -1,6 +1,7 @@
syntax = "proto3";
package cosmos.base.tendermint.v1beta1;
import "gogoproto/gogo.proto";
import "google/protobuf/any.proto";
import "google/api/annotations.proto";
import "tendermint/p2p/types.proto";
@ -17,14 +18,17 @@ service Service {
rpc GetNodeInfo(GetNodeInfoRequest) returns (GetNodeInfoResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/node_info";
}
// GetSyncing queries node syncing.
rpc GetSyncing(GetSyncingRequest) returns (GetSyncingResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/syncing";
}
// GetLatestBlock returns the latest block.
rpc GetLatestBlock(GetLatestBlockRequest) returns (GetLatestBlockResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/blocks/latest";
}
// GetBlockByHeight queries block for given height.
rpc GetBlockByHeight(GetBlockByHeightRequest) returns (GetBlockByHeightResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/blocks/{height}";
@ -34,10 +38,20 @@ service Service {
rpc GetLatestValidatorSet(GetLatestValidatorSetRequest) returns (GetLatestValidatorSetResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/validatorsets/latest";
}
// GetValidatorSetByHeight queries validator-set at a given height.
rpc GetValidatorSetByHeight(GetValidatorSetByHeightRequest) returns (GetValidatorSetByHeightResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/validatorsets/{height}";
}
// ABCIQuery defines a query handler that supports ABCI queries directly to the
// application, bypassing Tendermint completely. The ABCI query must contain
// a valid and supported path, including app, custom, p2p, and store.
//
// Since: cosmos-sdk 0.46
rpc ABCIQuery(ABCIQueryRequest) returns (ABCIQueryResponse) {
option (google.api.http).get = "/cosmos/base/tendermint/v1beta1/abci_query";
}
}
// GetValidatorSetByHeightRequest is the request type for the Query/GetValidatorSetByHeight RPC method.
@ -136,3 +150,47 @@ message Module {
// checksum
string sum = 3;
}
// ABCIQueryRequest defines the request structure for the ABCIQuery gRPC query.
message ABCIQueryRequest {
bytes data = 1;
string path = 2;
int64 height = 3;
bool prove = 4;
}
// ABCIQueryResponse defines the response structure for the ABCIQuery gRPC query.
//
// Note: This type is a duplicate of the ResponseQuery proto type defined in
// Tendermint.
message ABCIQueryResponse {
uint32 code = 1;
// DEPRECATED: use "value" instead
reserved 2;
string log = 3; // nondeterministic
string info = 4; // nondeterministic
int64 index = 5;
bytes key = 6;
bytes value = 7;
ProofOps proof_ops = 8;
int64 height = 9;
string codespace = 10;
}
// ProofOp defines an operation used for calculating Merkle root. The data could
// be arbitrary format, providing nessecary data for example neighbouring node
// hash.
//
// Note: This type is a duplicate of the ProofOp proto type defined in Tendermint.
message ProofOp {
string type = 1;
bytes key = 2;
bytes data = 3;
}
// ProofOps is Merkle proof defined by the list of ProofOps.
//
// Note: This type is a duplicate of the ProofOps proto type defined in Tendermint.
message ProofOps {
repeated ProofOp ops = 1 [(gogoproto.nullable) = false];
}

View File

@ -7,8 +7,6 @@ import (
"os"
"path/filepath"
"github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar"
"github.com/gorilla/mux"
"github.com/rakyll/statik/fs"
"github.com/spf13/cast"
@ -29,6 +27,7 @@ import (
simappparams "github.com/cosmos/cosmos-sdk/simapp/params"
"github.com/cosmos/cosmos-sdk/store/streaming"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
"github.com/cosmos/cosmos-sdk/testutil/testdata_pulsar"
sdk "github.com/cosmos/cosmos-sdk/types"
"github.com/cosmos/cosmos-sdk/types/module"
"github.com/cosmos/cosmos-sdk/version"
@ -598,7 +597,12 @@ func (app *SimApp) RegisterTxService(clientCtx client.Context) {
// RegisterTendermintService implements the Application.RegisterTendermintService method.
func (app *SimApp) RegisterTendermintService(clientCtx client.Context) {
tmservice.RegisterTendermintService(app.BaseApp.GRPCQueryRouter(), clientCtx, app.interfaceRegistry)
tmservice.RegisterTendermintService(
clientCtx,
app.BaseApp.GRPCQueryRouter(),
app.interfaceRegistry,
app.Query,
)
}
// RegisterSwaggerAPI registers swagger route with API Server