This repository was archived by the owner on Apr 21, 2022. It is now read-only.
forked from hyperledger-labs/yui-fabric-ibc
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathquery.go
141 lines (117 loc) · 4.07 KB
/
query.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
package app
import (
"strings"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
abci "github.com/tendermint/tendermint/abci/types"
tmproto "github.com/tendermint/tendermint/proto/tendermint/types"
"google.golang.org/grpc/codes"
grpcstatus "google.golang.org/grpc/status"
)
// Query implements the ABCI interface. It delegates to CommitMultiStore if it
// implements Queryable.
func (app *BaseApp) Query(req abci.RequestQuery) abci.ResponseQuery {
// handle gRPC routes first rather than calling splitPath because '/' characters
// are used as part of gRPC paths
if grpcHandler := app.grpcQueryRouter.Route(req.Path); grpcHandler != nil {
return app.handleQueryGRPC(grpcHandler, req)
}
path := splitPath(req.Path)
if len(path) == 0 {
return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no query path provided"))
}
switch path[0] {
case "store":
return handleQueryStore(app, path, req)
case "custom":
return handleQueryCustom(app, path, req)
}
return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "unknown query path"))
}
func (app *BaseApp) handleQueryGRPC(handler GRPCQueryHandler, req abci.RequestQuery) abci.ResponseQuery {
ctx, err := app.createQueryContext(req.Height, req.Prove)
if err != nil {
return sdkerrors.QueryResult(err)
}
res, err := handler(ctx, req)
if err != nil {
res = sdkerrors.QueryResult(gRPCErrorToSDKError(err))
res.Height = req.Height
return res
}
return res
}
func handleQueryStore(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
// "/store" prefix for store queries
req.Path = "/" + strings.Join(path[1:], "/")
return app.cms.Query(req)
}
func handleQueryCustom(app *BaseApp, path []string, req abci.RequestQuery) abci.ResponseQuery {
// path[0] should be "custom" because "/custom" prefix is required for keeper
// queries.
//
// The QueryRouter routes using path[1]. For example, in the path
// "custom/gov/proposal", QueryRouter routes using "gov".
if len(path) < 2 || path[1] == "" {
return sdkerrors.QueryResult(sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, "no route for custom query specified"))
}
querier := app.queryRouter.Route(path[1])
if querier == nil {
return sdkerrors.QueryResult(sdkerrors.Wrapf(sdkerrors.ErrUnknownRequest, "no custom querier found for route %s", path[1]))
}
ctx, err := app.createQueryContext(req.Height, req.Prove)
if err != nil {
return sdkerrors.QueryResult(err)
}
// Passes the rest of the path as an argument to the querier.
//
// For example, in the path "custom/gov/proposal/test", the gov querier gets
// []string{"proposal", "test"} as the path.
resBytes, err := querier(ctx, path[2:], req)
if err != nil {
res := sdkerrors.QueryResult(err)
res.Height = req.Height
return res
}
return abci.ResponseQuery{
Height: req.Height,
Value: resBytes,
}
}
func (app *BaseApp) createQueryContext(height int64, prove bool) (sdk.Context, error) {
cacheMS := app.cms.CacheMultiStore()
// cache wrap the commit-multistore for safety
ctx := sdk.NewContext(
cacheMS, tmproto.Header{}, true, app.logger,
)
return ctx, nil
}
// splitPath splits a string path using the delimiter '/'.
//
// e.g. "this/is/funny" becomes []string{"this", "is", "funny"}
func splitPath(requestPath string) (path []string) {
path = strings.Split(requestPath, "/")
// first element is empty string
if len(path) > 0 && path[0] == "" {
path = path[1:]
}
return path
}
func gRPCErrorToSDKError(err error) error {
status, ok := grpcstatus.FromError(err)
if !ok {
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
}
switch status.Code() {
case codes.NotFound:
return sdkerrors.Wrap(sdkerrors.ErrKeyNotFound, err.Error())
case codes.InvalidArgument:
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
case codes.FailedPrecondition:
return sdkerrors.Wrap(sdkerrors.ErrInvalidRequest, err.Error())
case codes.Unauthenticated:
return sdkerrors.Wrap(sdkerrors.ErrUnauthorized, err.Error())
default:
return sdkerrors.Wrap(sdkerrors.ErrUnknownRequest, err.Error())
}
}