@@ -3,8 +3,11 @@ package keeper
3
3
import (
4
4
"encoding/json"
5
5
"errors"
6
+ "fmt"
6
7
7
8
"github.com/cosmos/cosmos-sdk/baseapp"
9
+ "github.com/cosmos/cosmos-sdk/codec"
10
+ abci "github.com/tendermint/tendermint/abci/types"
8
11
9
12
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
10
13
@@ -99,15 +102,14 @@ func DefaultQueryPlugins(
99
102
staking types.StakingKeeper ,
100
103
distKeeper types.DistributionKeeper ,
101
104
channelKeeper types.ChannelKeeper ,
102
- queryRouter GRPCQueryRouter ,
103
105
wasm wasmQueryKeeper ,
104
106
) QueryPlugins {
105
107
return QueryPlugins {
106
108
Bank : BankQuerier (bank ),
107
109
Custom : NoCustomQuerier ,
108
110
IBC : IBCQuerier (wasm , channelKeeper ),
109
111
Staking : StakingQuerier (staking , distKeeper ),
110
- Stargate : StargateQuerier ( queryRouter ),
112
+ Stargate : RejectStargateQuerier ( ),
111
113
Wasm : WasmQuerier (wasm ),
112
114
}
113
115
}
@@ -278,9 +280,47 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper)
278
280
}
279
281
}
280
282
281
- func StargateQuerier (queryRouter GRPCQueryRouter ) func (ctx sdk.Context , request * wasmvmtypes.StargateQuery ) ([]byte , error ) {
282
- return func (ctx sdk.Context , msg * wasmvmtypes.StargateQuery ) ([]byte , error ) {
283
- return nil , wasmvmtypes.UnsupportedRequest {Kind : "Stargate queries are disabled." }
283
+ // RejectStargateQuerier rejects all stargate queries
284
+ func RejectStargateQuerier () func (ctx sdk.Context , request * wasmvmtypes.StargateQuery ) ([]byte , error ) {
285
+ return func (ctx sdk.Context , request * wasmvmtypes.StargateQuery ) ([]byte , error ) {
286
+ return nil , wasmvmtypes.UnsupportedRequest {Kind : "Stargate queries are disabled" }
287
+ }
288
+ }
289
+
290
+ // AcceptedStargateQueries define accepted Stargate queries as a map with path as key and response type as value.
291
+ // For example:
292
+ // acceptList["/cosmos.auth.v1beta1.Query/Account"]= &authtypes.QueryAccountResponse{}
293
+ type AcceptedStargateQueries map [string ]codec.ProtoMarshaler
294
+
295
+ // AcceptListStargateQuerier supports a preconfigured set of stargate queries only.
296
+ // All arguments must be non nil.
297
+ //
298
+ // Warning: Chains need to test and maintain their accept list carefully.
299
+ // There were critical consensus breaking issues in the past with non-deterministic behaviour in the SDK.
300
+ //
301
+ // This queries can be set via WithQueryPlugins option in the wasm keeper constructor:
302
+ // WithQueryPlugins(&QueryPlugins{Stargate: AcceptListStargateQuerier(acceptList, queryRouter, codec)})
303
+ func AcceptListStargateQuerier (acceptList AcceptedStargateQueries , queryRouter GRPCQueryRouter , codec codec.Codec ) func (ctx sdk.Context , request * wasmvmtypes.StargateQuery ) ([]byte , error ) {
304
+ return func (ctx sdk.Context , request * wasmvmtypes.StargateQuery ) ([]byte , error ) {
305
+ protoResponse , accepted := acceptList [request .Path ]
306
+ if ! accepted {
307
+ return nil , wasmvmtypes.UnsupportedRequest {Kind : fmt .Sprintf ("'%s' path is not allowed from the contract" , request .Path )}
308
+ }
309
+
310
+ route := queryRouter .Route (request .Path )
311
+ if route == nil {
312
+ return nil , wasmvmtypes.UnsupportedRequest {Kind : fmt .Sprintf ("No route to query '%s'" , request .Path )}
313
+ }
314
+
315
+ res , err := route (ctx , abci.RequestQuery {
316
+ Data : request .Data ,
317
+ Path : request .Path ,
318
+ })
319
+ if err != nil {
320
+ return nil , err
321
+ }
322
+
323
+ return ConvertProtoToJSONMarshal (codec , protoResponse , res .Value )
284
324
}
285
325
}
286
326
@@ -527,6 +567,24 @@ func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin {
527
567
}
528
568
}
529
569
570
+ // ConvertProtoToJSONMarshal unmarshals the given bytes into a proto message and then marshals it to json.
571
+ // This is done so that clients calling stargate queries do not need to define their own proto unmarshalers,
572
+ // being able to use response directly by json marshalling, which is supported in cosmwasm.
573
+ func ConvertProtoToJSONMarshal (cdc codec.Codec , protoResponse codec.ProtoMarshaler , bz []byte ) ([]byte , error ) {
574
+ // unmarshal binary into stargate response data structure
575
+ err := cdc .Unmarshal (bz , protoResponse )
576
+ if err != nil {
577
+ return nil , sdkerrors .Wrap (err , "to proto" )
578
+ }
579
+
580
+ bz , err = cdc .MarshalJSON (protoResponse )
581
+ if err != nil {
582
+ return nil , sdkerrors .Wrap (err , "to json" )
583
+ }
584
+
585
+ return bz , nil
586
+ }
587
+
530
588
var _ WasmVMQueryHandler = WasmVMQueryHandlerFn (nil )
531
589
532
590
// WasmVMQueryHandlerFn is a helper to construct a function based query handler.
0 commit comments