Skip to content

Commit

Permalink
Merge pull request cosmos#435 from CosmWasm/stargate-msg-and-query
Browse files Browse the repository at this point in the history
Stargate msg and query
  • Loading branch information
ethanfrey authored Mar 4, 2021
2 parents b09a925 + cec6dcd commit b98353e
Show file tree
Hide file tree
Showing 9 changed files with 217 additions and 36 deletions.
7 changes: 3 additions & 4 deletions app/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -346,14 +346,12 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
)
app.evidenceKeeper = *evidenceKeeper

// just re-use the full router - do we want to limit this more?
var wasmRouter = bApp.Router()
wasmDir := filepath.Join(homePath, "wasm")

wasmConfig, err := wasm.ReadWasmConfig(appOpts)
if err != nil {
panic("error while reading wasm config: " + err.Error())
}

// The last arguments can contain custom message handlers, and custom query handlers,
// if we want to allow any custom callbacks
supportedFeatures := "staking,stargate"
Expand All @@ -368,7 +366,8 @@ func NewWasmApp(logger log.Logger, db dbm.DB, traceStore io.Writer, loadLatest b
app.ibcKeeper.ChannelKeeper,
&app.ibcKeeper.PortKeeper,
scopedWasmKeeper,
wasmRouter,
app.Router(),
app.GRPCQueryRouter(),
wasmDir,
wasmConfig,
supportedFeatures,
Expand Down
2 changes: 1 addition & 1 deletion x/wasm/internal/keeper/genesis_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,7 @@ func setupKeeper(t *testing.T) (*Keeper, sdk.Context, []sdk.StoreKey) {
wasmConfig := wasmTypes.DefaultWasmConfig()
pk := paramskeeper.NewKeeper(encodingConfig.Marshaler, encodingConfig.Amino, keyParams, tkeyParams)

srcKeeper := NewKeeper(encodingConfig.Marshaler, keyWasm, pk.Subspace(wasmTypes.DefaultParamspace), authkeeper.AccountKeeper{}, nil, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, nil, nil, nil, tempDir, wasmConfig, SupportedFeatures, nil, nil)
srcKeeper := NewKeeper(encodingConfig.Marshaler, keyWasm, pk.Subspace(wasmTypes.DefaultParamspace), authkeeper.AccountKeeper{}, nil, stakingkeeper.Keeper{}, distributionkeeper.Keeper{}, nil, nil, nil, nil, nil, tempDir, wasmConfig, SupportedFeatures, nil, nil)
return &srcKeeper, ctx, []sdk.StoreKey{keyWasm, keyParams}
}

Expand Down
63 changes: 45 additions & 18 deletions x/wasm/internal/keeper/handler_plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@ package keeper

import (
"encoding/json"
"fmt"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"
wasmvmtypes "github.com/CosmWasm/wasmvm/types"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
banktypes "github.com/cosmos/cosmos-sdk/x/bank/types"
Expand All @@ -20,8 +22,8 @@ type DefaultMessageHandler struct {
encoders MessageEncoders
}

func NewDefaultMessageHandler(router sdk.Router, channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper, customEncoders *MessageEncoders) DefaultMessageHandler {
encoders := DefaultEncoders(channelKeeper, capabilityKeeper).Merge(customEncoders)
func NewDefaultMessageHandler(router sdk.Router, channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper, unpacker codectypes.AnyUnpacker, customEncoders *MessageEncoders) DefaultMessageHandler {
encoders := DefaultEncoders(channelKeeper, capabilityKeeper, unpacker).Merge(customEncoders)
return DefaultMessageHandler{
router: router,
encoders: encoders,
Expand All @@ -31,24 +33,27 @@ func NewDefaultMessageHandler(router sdk.Router, channelKeeper types.ChannelKeep
type BankEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.BankMsg) ([]sdk.Msg, error)
type CustomEncoder func(sender sdk.AccAddress, msg json.RawMessage) ([]sdk.Msg, error)
type StakingEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk.Msg, error)
type StargateEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error)
type WasmEncoder func(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error)
type IBCEncoder func(ctx sdk.Context, sender sdk.AccAddress, contractIBCPortID string, msg *wasmvmtypes.IBCMsg) ([]sdk.Msg, error)

type MessageEncoders struct {
Bank BankEncoder
Custom CustomEncoder
Staking StakingEncoder
Wasm WasmEncoder
IBC IBCEncoder
Bank BankEncoder
Custom CustomEncoder
IBC IBCEncoder
Staking StakingEncoder
Stargate StargateEncoder
Wasm WasmEncoder
}

func DefaultEncoders(channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper) MessageEncoders {
func DefaultEncoders(channelKeeper types.ChannelKeeper, capabilityKeeper types.CapabilityKeeper, unpacker codectypes.AnyUnpacker) MessageEncoders {
return MessageEncoders{
Bank: EncodeBankMsg,
Custom: NoCustomMsg,
Staking: EncodeStakingMsg,
Wasm: EncodeWasmMsg,
IBC: EncodeIBCMsg(channelKeeper, capabilityKeeper),
Bank: EncodeBankMsg,
Custom: NoCustomMsg,
IBC: EncodeIBCMsg(channelKeeper, capabilityKeeper),
Staking: EncodeStakingMsg,
Stargate: EncodeStargateMsg(unpacker),
Wasm: EncodeWasmMsg,
}
}

Expand All @@ -62,15 +67,18 @@ func (e MessageEncoders) Merge(o *MessageEncoders) MessageEncoders {
if o.Custom != nil {
e.Custom = o.Custom
}
if o.IBC != nil {
e.IBC = o.IBC
}
if o.Staking != nil {
e.Staking = o.Staking
}
if o.Stargate != nil {
e.Stargate = o.Stargate
}
if o.Wasm != nil {
e.Wasm = o.Wasm
}
if o.IBC != nil {
e.IBC = o.IBC
}
return e
}

Expand All @@ -80,12 +88,14 @@ func (e MessageEncoders) Encode(ctx sdk.Context, contractAddr sdk.AccAddress, co
return e.Bank(contractAddr, msg.Bank)
case msg.Custom != nil:
return e.Custom(contractAddr, msg.Custom)
case msg.IBC != nil:
return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC)
case msg.Staking != nil:
return e.Staking(contractAddr, msg.Staking)
case msg.Stargate != nil:
return e.Stargate(contractAddr, msg.Stargate)
case msg.Wasm != nil:
return e.Wasm(contractAddr, msg.Wasm)
case msg.IBC != nil:
return e.IBC(ctx, contractAddr, contractIBCPortID, msg.IBC)
}
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, "Unknown variant of Wasm")
}
Expand Down Expand Up @@ -170,6 +180,23 @@ func EncodeStakingMsg(sender sdk.AccAddress, msg *wasmvmtypes.StakingMsg) ([]sdk
}
}

func EncodeStargateMsg(unpacker codectypes.AnyUnpacker) StargateEncoder {
return func(sender sdk.AccAddress, msg *wasmvmtypes.StargateMsg) ([]sdk.Msg, error) {
any := codectypes.Any{
TypeUrl: msg.TypeURL,
Value: msg.Value,
}
var sdkMsg sdk.Msg
if err := unpacker.UnpackAny(&any, &sdkMsg); err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("Cannot unpack proto message with type URL: %s", msg.TypeURL))
}
if err := codectypes.UnpackInterfaces(sdkMsg, unpacker); err != nil {
return nil, sdkerrors.Wrap(types.ErrInvalidMsg, fmt.Sprintf("UnpackInterfaces inside msg: %s", err))
}
return []sdk.Msg{sdkMsg}, nil
}
}

func EncodeWasmMsg(sender sdk.AccAddress, msg *wasmvmtypes.WasmMsg) ([]sdk.Msg, error) {
switch {
case msg.Execute != nil:
Expand Down
36 changes: 35 additions & 1 deletion x/wasm/internal/keeper/handler_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/core/02-client/types"
channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/core/04-channel/types"
ibcexported "github.com/cosmos/cosmos-sdk/x/ibc/core/exported"
"github.com/golang/protobuf/proto"
"testing"

"github.com/CosmWasm/wasmd/x/wasm/internal/types"
Expand All @@ -32,6 +33,17 @@ func TestEncoding(t *testing.T) {

jsonMsg := json.RawMessage(`{"foo": 123}`)

bankMsg := &banktypes.MsgSend{
FromAddress: addr2.String(),
ToAddress: addr1.String(),
Amount: sdk.Coins{
sdk.NewInt64Coin("uatom", 12345),
sdk.NewInt64Coin("utgd", 54321),
},
}
bankMsgBin, err := proto.Marshal(bankMsg)
require.NoError(t, err)

cases := map[string]struct {
sender sdk.AccAddress
srcMsg wasmvmtypes.CosmosMsg
Expand Down Expand Up @@ -276,6 +288,27 @@ func TestEncoding(t *testing.T) {
},
},
},
// TODO: alpe? can you add an example with sub-interfaces (where the UnpackInterfaces call would be needed)
"stargate encoded bank msg": {
sender: addr2,
srcMsg: wasmvmtypes.CosmosMsg{
Stargate: &wasmvmtypes.StargateMsg{
TypeURL: "/cosmos.bank.v1beta1.MsgSend",
Value: bankMsgBin,
},
},
output: []sdk.Msg{bankMsg},
},
"stargate encoded invalid typeUrl": {
sender: addr2,
srcMsg: wasmvmtypes.CosmosMsg{
Stargate: &wasmvmtypes.StargateMsg{
TypeURL: "/cosmos.bank.v2.MsgSend",
Value: bankMsgBin,
},
},
isError: true,
},
"IBC transfer with block timeout": {
sender: addr1,
srcIBCPort: "myIBCPort",
Expand Down Expand Up @@ -355,7 +388,8 @@ func TestEncoding(t *testing.T) {
},
},
}
encoder := DefaultEncoders(nil, nil)
encodingConfig := MakeEncodingConfig(t)
encoder := DefaultEncoders(nil, nil, encodingConfig.Marshaler)
for name, tc := range cases {
tc := tc
t.Run(name, func(t *testing.T) {
Expand Down
6 changes: 3 additions & 3 deletions x/wasm/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ func NewKeeper(
portKeeper types.PortKeeper,
capabilityKeeper types.CapabilityKeeper,
router sdk.Router,
queryRouter GRPCQueryRouter,
homeDir string,
wasmConfig types.WasmConfig,
supportedFeatures string,
Expand All @@ -105,7 +106,6 @@ func NewKeeper(
paramSpace = paramSpace.WithKeyTable(types.ParamKeyTable())
}

messageEncoders := DefaultEncoders(channelKeeper, capabilityKeeper).Merge(customEncoders)
keeper := Keeper{
storeKey: storeKey,
cdc: cdc,
Expand All @@ -115,12 +115,12 @@ func NewKeeper(
ChannelKeeper: channelKeeper,
portKeeper: portKeeper,
capabilityKeeper: capabilityKeeper,
messenger: NewDefaultMessageHandler(router, channelKeeper, capabilityKeeper, &messageEncoders),
messenger: NewDefaultMessageHandler(router, channelKeeper, capabilityKeeper, cdc, customEncoders),
queryGasLimit: wasmConfig.SmartQueryGasLimit,
authZPolicy: DefaultAuthorizationPolicy{},
paramSpace: paramSpace,
}
keeper.queryPlugins = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, &keeper).Merge(customPlugins)
keeper.queryPlugins = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, queryRouter, &keeper).Merge(customPlugins)
for _, o := range opts {
o.apply(&keeper)
}
Expand Down
1 change: 1 addition & 0 deletions x/wasm/internal/keeper/options_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ func TestConstructorOptions(t *testing.T) {
nil,
nil,
nil,
nil,
"tempDir",
types.DefaultWasmConfig(),
SupportedFeatures,
Expand Down
58 changes: 49 additions & 9 deletions x/wasm/internal/keeper/query_plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package keeper

import (
"encoding/json"
"fmt"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -11,13 +12,26 @@ import (
distributiontypes "github.com/cosmos/cosmos-sdk/x/distribution/types"
stakingkeeper "github.com/cosmos/cosmos-sdk/x/staking/keeper"
stakingtypes "github.com/cosmos/cosmos-sdk/x/staking/types"
abci "github.com/tendermint/tendermint/abci/types"
)

type QueryHandler struct {
Ctx sdk.Context
Plugins QueryPlugins
}

// -- interfaces from baseapp - so we can use the GPRQueryRouter --

// GRPCQueryHandler defines a function type which handles ABCI Query requests
// using gRPC
type GRPCQueryHandler = func(ctx sdk.Context, req abci.RequestQuery) (abci.ResponseQuery, error)

type GRPCQueryRouter interface {
Route(path string) GRPCQueryHandler
}

// -- end baseapp interfaces --

var _ wasmvmtypes.Querier = QueryHandler{}

func (q QueryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) ([]byte, error) {
Expand All @@ -40,6 +54,9 @@ func (q QueryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) (
if request.Staking != nil {
return q.Plugins.Staking(subctx, request.Staking)
}
if request.Stargate != nil {
return q.Plugins.Stargate(subctx, request.Stargate)
}
if request.Wasm != nil {
return q.Plugins.Wasm(subctx, request.Wasm)
}
Expand All @@ -53,18 +70,20 @@ func (q QueryHandler) GasConsumed() uint64 {
type CustomQuerier func(ctx sdk.Context, request json.RawMessage) ([]byte, error)

type QueryPlugins struct {
Bank func(ctx sdk.Context, request *wasmvmtypes.BankQuery) ([]byte, error)
Custom CustomQuerier
Staking func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error)
Wasm func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error)
Bank func(ctx sdk.Context, request *wasmvmtypes.BankQuery) ([]byte, error)
Custom CustomQuerier
Staking func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error)
Stargate func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error)
Wasm func(ctx sdk.Context, request *wasmvmtypes.WasmQuery) ([]byte, error)
}

func DefaultQueryPlugins(bank bankkeeper.ViewKeeper, staking stakingkeeper.Keeper, distKeeper distributionkeeper.Keeper, wasm *Keeper) QueryPlugins {
func DefaultQueryPlugins(bank bankkeeper.ViewKeeper, staking stakingkeeper.Keeper, distKeeper distributionkeeper.Keeper, queryRouter GRPCQueryRouter, wasm *Keeper) QueryPlugins {
return QueryPlugins{
Bank: BankQuerier(bank),
Custom: NoCustomQuerier,
Staking: StakingQuerier(staking, distKeeper),
Wasm: WasmQuerier(wasm),
Bank: BankQuerier(bank),
Custom: NoCustomQuerier,
Staking: StakingQuerier(staking, distKeeper),
Stargate: StargateQuerier(queryRouter),
Wasm: WasmQuerier(wasm),
}
}

Expand All @@ -82,6 +101,9 @@ func (e QueryPlugins) Merge(o *QueryPlugins) QueryPlugins {
if o.Staking != nil {
e.Staking = o.Staking
}
if o.Stargate != nil {
e.Stargate = o.Stargate
}
if o.Wasm != nil {
e.Wasm = o.Wasm
}
Expand Down Expand Up @@ -124,6 +146,24 @@ func NoCustomQuerier(sdk.Context, json.RawMessage) ([]byte, error) {
return nil, wasmvmtypes.UnsupportedRequest{Kind: "custom"}
}

func StargateQuerier(queryRouter GRPCQueryRouter) func(ctx sdk.Context, request *wasmvmtypes.StargateQuery) ([]byte, error) {
return func(ctx sdk.Context, msg *wasmvmtypes.StargateQuery) ([]byte, error) {
route := queryRouter.Route(msg.Path)
if route == nil {
return nil, wasmvmtypes.UnsupportedRequest{Kind: fmt.Sprintf("No route to query '%s'", msg.Path)}
}
req := abci.RequestQuery{
Data: msg.Data,
Path: msg.Path,
}
res, err := route(ctx, req)
if err != nil {
return nil, err
}
return res.Value, nil
}
}

func StakingQuerier(keeper stakingkeeper.Keeper, distKeeper distributionkeeper.Keeper) func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) {
return func(ctx sdk.Context, request *wasmvmtypes.StakingQuery) ([]byte, error) {
if request.BondedDenom != nil {
Expand Down
Loading

0 comments on commit b98353e

Please sign in to comment.