Some checks failed
CodeQL / Analyze (push) Waiting to run
Docker Build & Push Simapp (main) / docker-build (push) Waiting to run
golangci-lint / lint (push) Waiting to run
Tests / Code Coverage / build (amd64) (push) Waiting to run
Tests / Code Coverage / build (arm64) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[additional-args:-tags="test_e2e" name:e2e path:./e2e]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:08-wasm path:./modules/light-clients/08-wasm]) (push) Waiting to run
Tests / Code Coverage / unit-tests (map[name:ibc-go path:.]) (push) Waiting to run
Deploy to GitHub Pages / Deploy to GitHub Pages (push) Has been cancelled
Buf-Push / push (push) Has been cancelled
161 lines
4.6 KiB
Go
161 lines
4.6 KiB
Go
package query
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
"github.com/cosmos/gogoproto/proto"
|
|
"github.com/cosmos/interchaintest/v10/ibc"
|
|
"google.golang.org/grpc"
|
|
"google.golang.org/grpc/credentials/insecure"
|
|
pb "google.golang.org/protobuf/proto"
|
|
|
|
msgv1 "cosmossdk.io/api/cosmos/msg/v1"
|
|
reflectionv1 "cosmossdk.io/api/cosmos/reflection/v1"
|
|
|
|
"github.com/cosmos/ibc-go/e2e/testvalues"
|
|
)
|
|
|
|
var queryReqToPath = make(map[string]string)
|
|
|
|
func PopulateQueryReqToPath(ctx context.Context, chain ibc.Chain) error {
|
|
if !testvalues.ReflectionServiceFeatureReleases.IsSupported(chain.Config().Images[0].Version) {
|
|
return nil
|
|
}
|
|
resp, err := queryFileDescriptors(ctx, chain)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
for _, fileDescriptor := range resp.Files {
|
|
for _, service := range fileDescriptor.GetService() {
|
|
// Skip services that are annotated with the "cosmos.msg.v1.service" option.
|
|
if ext := pb.GetExtension(service.GetOptions(), msgv1.E_Service); ext != nil {
|
|
if ok, extBool := ext.(bool); ok && extBool {
|
|
continue
|
|
}
|
|
}
|
|
|
|
for _, method := range service.GetMethod() {
|
|
// trim the first character from input which is a dot
|
|
queryReqToPath[method.GetInputType()[1:]] = fileDescriptor.GetPackage() + "." + service.GetName() + "/" + method.GetName()
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// GRPCQuery queries the chain with a query request and deserializes the response to T
|
|
func GRPCQuery[T any](ctx context.Context, chain ibc.Chain, req proto.Message, opts ...grpc.CallOption) (*T, error) {
|
|
var path string
|
|
if testvalues.ReflectionServiceFeatureReleases.IsSupported(chain.Config().Images[0].Version) {
|
|
var ok bool
|
|
path, ok = queryReqToPath[proto.MessageName(req)]
|
|
if !ok {
|
|
return nil, fmt.Errorf("no path found for %s", proto.MessageName(req))
|
|
}
|
|
} else {
|
|
var err error
|
|
path, err = getProtoPath(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
return grpcQueryWithMethod[T](ctx, chain, req, path, opts...)
|
|
}
|
|
|
|
// grpcQueryWithMethod queries the chain with a query request with a specific method (grpc path) and deserializes the response to T
|
|
func grpcQueryWithMethod[T any](ctx context.Context, chain ibc.Chain, req proto.Message, method string, opts ...grpc.CallOption) (*T, error) {
|
|
// Create a connection to the gRPC server.
|
|
grpcConn, err := grpc.Dial(
|
|
chain.GetHostGRPCAddress(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer grpcConn.Close()
|
|
|
|
resp := new(T)
|
|
err = grpcConn.Invoke(ctx, method, req, resp, opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func queryFileDescriptors(ctx context.Context, chain ibc.Chain) (*reflectionv1.FileDescriptorsResponse, error) {
|
|
// Create a connection to the gRPC server.
|
|
grpcConn, err := grpc.Dial(
|
|
chain.GetHostGRPCAddress(),
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer grpcConn.Close()
|
|
|
|
resp := new(reflectionv1.FileDescriptorsResponse)
|
|
err = grpcConn.Invoke(
|
|
ctx, reflectionv1.ReflectionService_FileDescriptors_FullMethodName,
|
|
&reflectionv1.FileDescriptorsRequest{}, resp,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
// TODO: Remove all of the below when v6 -> v7 upgrade is not supported anymore:
|
|
func getProtoPath(req proto.Message) (string, error) {
|
|
typeURL := "/" + proto.MessageName(req)
|
|
|
|
switch {
|
|
case strings.Contains(typeURL, "Query"):
|
|
return getQueryProtoPath(typeURL)
|
|
case strings.Contains(typeURL, "cosmos.base.tendermint"):
|
|
return getCmtProtoPath(typeURL)
|
|
default:
|
|
return "", fmt.Errorf("unsupported typeURL: %s", typeURL)
|
|
}
|
|
}
|
|
|
|
func getQueryProtoPath(queryTypeURL string) (string, error) {
|
|
queryIndex := strings.Index(queryTypeURL, "Query")
|
|
if queryIndex == -1 {
|
|
return "", fmt.Errorf("invalid typeURL: %s", queryTypeURL)
|
|
}
|
|
|
|
// Add to the index to account for the length of "Query"
|
|
queryIndex += len("Query")
|
|
|
|
// Add a slash before the query
|
|
urlWithSlash := queryTypeURL[:queryIndex] + "/" + queryTypeURL[queryIndex:]
|
|
if !strings.HasSuffix(urlWithSlash, "Request") {
|
|
return "", fmt.Errorf("invalid typeURL: %s", queryTypeURL)
|
|
}
|
|
|
|
return strings.TrimSuffix(urlWithSlash, "Request"), nil
|
|
}
|
|
|
|
func getCmtProtoPath(cmtTypeURL string) (string, error) {
|
|
cmtIndex := strings.Index(cmtTypeURL, "Get")
|
|
if cmtIndex == -1 {
|
|
return "", fmt.Errorf("invalid typeURL: %s", cmtTypeURL)
|
|
}
|
|
|
|
// Add a slash before the commitment
|
|
urlWithSlash := cmtTypeURL[:cmtIndex] + "Service/" + cmtTypeURL[cmtIndex:]
|
|
if !strings.HasSuffix(urlWithSlash, "Request") {
|
|
return "", fmt.Errorf("invalid typeURL: %s", cmtTypeURL)
|
|
}
|
|
|
|
return strings.TrimSuffix(urlWithSlash, "Request"), nil
|
|
}
|