-
Notifications
You must be signed in to change notification settings - Fork 690
/
Copy pathquerier.go
182 lines (145 loc) · 5.68 KB
/
querier.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
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
package keeper
import (
"encoding/json"
"fmt"
"slices"
wasmvmtypes "github.com/CosmWasm/wasmvm/v2/types"
errorsmod "cosmossdk.io/errors"
storetypes "cosmossdk.io/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
abci "github.com/cometbft/cometbft/abci/types"
"github.com/cosmos/ibc-go/modules/light-clients/08-wasm/v10/types"
)
/*
`queryHandler` is a contextual querier which references the global `ibcwasm.QueryPluginsI`
to handle queries. The global `ibcwasm.QueryPluginsI` points to a `types.QueryPlugins` which
contains two sub-queriers: `types.CustomQuerier` and `types.StargateQuerier`. These sub-queriers
can be replaced by the user through the options api in the keeper.
In addition, the `types.StargateQuerier` references a global `types.QueryRouter` which points
to `baseapp.GRPCQueryRouter`.
This design is based on wasmd's (v0.50.0) querier plugin design.
*/
var _ wasmvmtypes.Querier = (*queryHandler)(nil)
// defaultAcceptList defines a set of default allowed queries made available to the Querier.
var defaultAcceptList = []string{
"/ibc.core.client.v1.Query/VerifyMembership",
}
// queryHandler is a wrapper around the sdk.Context and the CallerID that calls
// into the query plugins.
type queryHandler struct {
Ctx sdk.Context
Plugins QueryPlugins
CallerID string
}
// newQueryHandler returns a default querier that can be used in the contract.
func newQueryHandler(ctx sdk.Context, plugins QueryPlugins, callerID string) *queryHandler {
return &queryHandler{
Ctx: ctx,
Plugins: plugins,
CallerID: callerID,
}
}
// GasConsumed implements the wasmvmtypes.Querier interface.
func (q *queryHandler) GasConsumed() uint64 {
return types.VMGasRegister.ToWasmVMGas(q.Ctx.GasMeter().GasConsumed())
}
// Query implements the wasmvmtypes.Querier interface.
func (q *queryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) ([]byte, error) {
sdkGas := types.VMGasRegister.FromWasmVMGas(gasLimit)
// discard all changes/events in subCtx by not committing the cached context
subCtx, _ := q.Ctx.WithGasMeter(storetypes.NewGasMeter(sdkGas)).CacheContext()
// make sure we charge the higher level context even on panic
defer func() {
q.Ctx.GasMeter().ConsumeGas(subCtx.GasMeter().GasConsumed(), "contract sub-query")
}()
res, err := q.Plugins.HandleQuery(subCtx, q.CallerID, request)
if err == nil {
return res, nil
}
q.Ctx.Logger().With("module", "x/ibc-wasm").Debug("Redacting query error", "cause", err)
return nil, redactError(err)
}
type (
CustomQuerier func(ctx sdk.Context, request json.RawMessage) ([]byte, error)
StargateQuerier func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error)
// QueryPlugins is a list of queriers that can be used to extend the default querier.
QueryPlugins struct {
Custom CustomQuerier
Stargate StargateQuerier
}
)
// Merge merges the query plugin with a provided one.
func (e *QueryPlugins) Merge(x *QueryPlugins) QueryPlugins {
// only update if this is non-nil and then only set values
if x == nil {
return *e
}
if x.Custom != nil {
e.Custom = x.Custom
}
if x.Stargate != nil {
e.Stargate = x.Stargate
}
return *e
}
// HandleQuery implements the ibcwasm.QueryPluginsI interface.
func (e *QueryPlugins) HandleQuery(ctx sdk.Context, caller string, request wasmvmtypes.QueryRequest) ([]byte, error) {
if request.Stargate != nil {
return e.Stargate(ctx, request.Stargate)
}
if request.Custom != nil {
return e.Custom(ctx, request.Custom)
}
return nil, wasmvmtypes.UnsupportedRequest{Kind: "Unsupported query request"}
}
// NewDefaultQueryPlugins returns the default set of query plugins
func NewDefaultQueryPlugins(queryRouter types.QueryRouter) QueryPlugins {
return QueryPlugins{
Custom: RejectCustomQuerier(),
Stargate: AcceptListStargateQuerier([]string{}, queryRouter),
}
}
// AcceptListStargateQuerier allows all queries that are in the provided accept list.
// This function returns protobuf encoded responses in bytes.
func AcceptListStargateQuerier(acceptedQueries []string, queryRouter types.QueryRouter) func(sdk.Context, *wasmvmtypes.StargateQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
// append user defined accepted queries to default list defined above.
acceptedQueries = append(defaultAcceptList, acceptedQueries...)
isAccepted := slices.Contains(acceptedQueries, request.Path)
if !isAccepted {
return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("'%s' path is not allowed from the contract", request.Path)}
}
route := queryRouter.Route(request.Path)
if route == nil {
return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", request.Path)}
}
res, err := route(ctx, &abci.RequestQuery{
Data: request.Data,
Path: request.Path,
})
if err != nil {
return nil, err
}
if res == nil || res.Value == nil {
return nil, wasmvmtypes.InvalidResponse{Err: "Query response is empty"}
}
return res.Value, nil
}
}
// RejectCustomQuerier rejects all custom queries
func RejectCustomQuerier() func(sdk.Context, json.RawMessage) ([]byte, error) {
return func(ctx sdk.Context, request json.RawMessage) ([]byte, error) {
return nil, wasmvmtypes.UnsupportedRequest{Kind: "Custom queries are not allowed"}
}
}
// Wasmd Issue [#759](https://github.com/CosmWasm/wasmd/issues/759)
// Don't return error string for worries of non-determinism
func redactError(err error) error {
// Do not redact system errors
// SystemErrors must be created in 08-wasm and we can ensure determinism
if wasmvmtypes.ToSystemError(err) != nil {
return err
}
codespace, code, _ := errorsmod.ABCIInfo(err, false)
return fmt.Errorf("codespace: %s, code: %d", codespace, code)
}