Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Introduce AcceptListStargateQuerier #84

Merged
merged 3 commits into from
Aug 23, 2023
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## [Unreleased](https://github.com/Finschia/wasmd/compare/v0.1.4...HEAD)

### Features
* [\#84](https://github.com/Finschia/wasmd/pull/84) add AcceptlistStaragteQuerier

### Improvements

Expand Down
2 changes: 1 addition & 1 deletion x/wasm/keeper/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func WithQueryHandlerDecorator(d func(old WasmVMQueryHandler) WasmVMQueryHandler
}

// WithQueryPlugins is an optional constructor parameter to pass custom query plugins for wasmVM requests.
// This option expects the default `QueryHandler` set an should not be combined with Option `WithQueryHandler` or `WithQueryHandlerDecorator`.
// This option expects the default `QueryHandler` set and should not be combined with Option `WithQueryHandler` or `WithQueryHandlerDecorator`.
func WithQueryPlugins(x *QueryPlugins) Option {
return optsFn(func(k *Keeper) {
q, ok := k.wasmVMQueryHandler.(QueryPlugins)
Expand Down
66 changes: 62 additions & 4 deletions x/wasm/keeper/query_plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@ package keeper
import (
"encoding/json"
"errors"
"fmt"

abci "github.com/tendermint/tendermint/abci/types"

baseapp "github.com/Finschia/finschia-sdk/baseapp"
"github.com/Finschia/finschia-sdk/codec"
sdk "github.com/Finschia/finschia-sdk/types"
sdkerrors "github.com/Finschia/finschia-sdk/types/errors"
distributiontypes "github.com/Finschia/finschia-sdk/x/distribution/types"
Expand Down Expand Up @@ -107,7 +109,7 @@ func DefaultQueryPlugins(
Custom: CustomQuerierImpl(queryRouter),
IBC: IBCQuerier(wasm, channelKeeper),
Staking: StakingQuerier(staking, distKeeper),
Stargate: StargateQuerier(queryRouter),
Stargate: RejectStargateQuerier(),
Wasm: WasmQuerier(wasm),
}
}
Expand Down Expand Up @@ -302,9 +304,47 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper)
}
}

func StargateQuerier(queryRouter GRPCQueryRouter) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
return func(ctx sdk.Context, msg *wasmvmtypes.StargateQuery) ([]byte, error) {
return nil, wasmvmtypes.UnsupportedRequest{Kind: "Stargate queries are disabled."}
// RejectStargateQuerier rejects all stargate queries
func RejectStargateQuerier() func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
return nil, wasmvmtypes.UnsupportedRequest{Kind: "Stargate queries are disabled"}
}
}

// AcceptedStargateQueries define accepted Stargate queries as a map with path as key and response type as value.
// For example:
// acceptList["/cosmos.auth.v1beta1.Query/Account"]= &authtypes.QueryAccountResponse{}
type AcceptedStargateQueries map[string]codec.ProtoMarshaler

// AcceptListStargateQuerier supports a preconfigured set of stargate queries only.
// All arguments must be non nil.
//
// Warning: Chains need to test and maintain their accept list carefully.
// There were critical consensus breaking issues in the past with non-deterministic behaviour in the SDK.
//
// This queries can be set via WithQueryPlugins option in the wasm keeper constructor:
// WithQueryPlugins(&QueryPlugins{Stargate: AcceptListStargateQuerier(acceptList, queryRouter, codec)})
func AcceptListStargateQuerier(acceptList AcceptedStargateQueries, queryRouter GRPCQueryRouter, codec codec.Codec) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
protoResponse, accepted := acceptList[request.Path]
if !accepted {
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
}

return ConvertProtoToJSONMarshal(codec, protoResponse, res.Value)
}
}

Expand Down Expand Up @@ -551,6 +591,24 @@ func ConvertSdkCoinToWasmCoin(coin sdk.Coin) wasmvmtypes.Coin {
}
}

// ConvertProtoToJSONMarshal unmarshals the given bytes into a proto message and then marshals it to json.
// This is done so that clients calling stargate queries do not need to define their own proto unmarshalers,
// being able to use response directly by json marshalling, which is supported in cosmwasm.
func ConvertProtoToJSONMarshal(cdc codec.Codec, protoResponse codec.ProtoMarshaler, bz []byte) ([]byte, error) {
// unmarshal binary into stargate response data structure
err := cdc.Unmarshal(bz, protoResponse)
if err != nil {
return nil, sdkerrors.Wrap(err, "to proto")
}

bz, err = cdc.MarshalJSON(protoResponse)
if err != nil {
return nil, sdkerrors.Wrap(err, "to json")
}

return bz, nil
}

var _ WasmVMQueryHandler = WasmVMQueryHandlerFn(nil)

// WasmVMQueryHandlerFn is a helper to construct a function based query handler.
Expand Down
Loading