Skip to content

Commit 122c8f7

Browse files
alpemattverse
authored andcommitted
Introduce AcceptListStargateQuerier (CosmWasm#1069)
* Stargate query enable * Remove initialized whitelists * Roman's review * Minor improvement * Add tests * Add testings and codec * Fix lint * Fix test * Fix from code review * Refactor Stargate querier init * Fix typo Co-authored-by: mattverse <[email protected]>
1 parent 5cdcf96 commit 122c8f7

File tree

5 files changed

+288
-26
lines changed

5 files changed

+288
-26
lines changed

x/wasm/keeper/keeper.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -119,7 +119,7 @@ func NewKeeper(
119119
capabilityKeeper types.CapabilityKeeper,
120120
portSource types.ICS20TransferPortSource,
121121
router MessageRouter,
122-
queryRouter GRPCQueryRouter,
122+
_ GRPCQueryRouter,
123123
homeDir string,
124124
wasmConfig types.WasmConfig,
125125
availableCapabilities string,
@@ -150,7 +150,7 @@ func NewKeeper(
150150
maxQueryStackSize: types.DefaultMaxQueryStackSize,
151151
acceptedAccountTypes: defaultAcceptedAccountTypes,
152152
}
153-
keeper.wasmVMQueryHandler = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, channelKeeper, queryRouter, keeper)
153+
keeper.wasmVMQueryHandler = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, channelKeeper, keeper)
154154
for _, o := range opts {
155155
o.apply(keeper)
156156
}

x/wasm/keeper/options.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func WithQueryHandlerDecorator(d func(old WasmVMQueryHandler) WasmVMQueryHandler
5757
}
5858

5959
// WithQueryPlugins is an optional constructor parameter to pass custom query plugins for wasmVM requests.
60-
// This option expects the default `QueryHandler` set an should not be combined with Option `WithQueryHandler` or `WithQueryHandlerDecorator`.
60+
// This option expects the default `QueryHandler` set and should not be combined with Option `WithQueryHandler` or `WithQueryHandlerDecorator`.
6161
func WithQueryPlugins(x *QueryPlugins) Option {
6262
return optsFn(func(k *Keeper) {
6363
q, ok := k.wasmVMQueryHandler.(QueryPlugins)

x/wasm/keeper/query_plugins.go

+63-5
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,11 @@ package keeper
33
import (
44
"encoding/json"
55
"errors"
6+
"fmt"
67

78
"github.com/cosmos/cosmos-sdk/baseapp"
9+
"github.com/cosmos/cosmos-sdk/codec"
10+
abci "github.com/tendermint/tendermint/abci/types"
811

912
channeltypes "github.com/cosmos/ibc-go/v3/modules/core/04-channel/types"
1013

@@ -99,15 +102,14 @@ func DefaultQueryPlugins(
99102
staking types.StakingKeeper,
100103
distKeeper types.DistributionKeeper,
101104
channelKeeper types.ChannelKeeper,
102-
queryRouter GRPCQueryRouter,
103105
wasm wasmQueryKeeper,
104106
) QueryPlugins {
105107
return QueryPlugins{
106108
Bank: BankQuerier(bank),
107109
Custom: NoCustomQuerier,
108110
IBC: IBCQuerier(wasm, channelKeeper),
109111
Staking: StakingQuerier(staking, distKeeper),
110-
Stargate: StargateQuerier(queryRouter),
112+
Stargate: RejectStargateQuerier(),
111113
Wasm: WasmQuerier(wasm),
112114
}
113115
}
@@ -278,9 +280,47 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper)
278280
}
279281
}
280282

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)
284324
}
285325
}
286326

@@ -527,6 +567,24 @@ func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin {
527567
}
528568
}
529569

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+
530588
var _ WasmVMQueryHandler = WasmVMQueryHandlerFn(nil)
531589

532590
// WasmVMQueryHandlerFn is a helper to construct a function based query handler.

0 commit comments

Comments
 (0)