Skip to content

Commit

Permalink
Merge pull request #439 from CosmWasm/ibc-query-support
Browse files Browse the repository at this point in the history
Ibc query support
  • Loading branch information
ethanfrey authored Mar 9, 2021
2 parents 4072abf + 9ce450a commit 8d9ed87
Show file tree
Hide file tree
Showing 5 changed files with 115 additions and 46 deletions.
27 changes: 6 additions & 21 deletions x/wasm/internal/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ func NewKeeper(
authZPolicy: DefaultAuthorizationPolicy{},
paramSpace: paramSpace,
}
keeper.queryPlugins = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, queryRouter, &keeper).Merge(customPlugins)
keeper.queryPlugins = DefaultQueryPlugins(bankKeeper, stakingKeeper, distKeeper, channelKeeper, queryRouter, &keeper).Merge(customPlugins)
for _, o := range opts {
o.apply(&keeper)
}
Expand Down Expand Up @@ -269,10 +269,7 @@ func (k Keeper) instantiate(ctx sdk.Context, codeID uint64, creator, admin sdk.A
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey)

// prepare querier
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddress)

// instantiate wasm contract
gas := gasForContract(ctx)
Expand Down Expand Up @@ -343,10 +340,7 @@ func (k Keeper) Execute(ctx sdk.Context, contractAddress sdk.AccAddress, caller
info := types.NewInfo(caller, coins)

// prepare querier
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddress)
gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.Execute(codeInfo.CodeHash, env, info, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas)
consumeGas(ctx, gasUsed)
Expand Down Expand Up @@ -410,10 +404,7 @@ func (k Keeper) migrate(ctx sdk.Context, contractAddress sdk.AccAddress, caller
env := types.NewEnv(ctx, contractAddress)

// prepare querier
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddress)

prefixStoreKey := types.GetContractStorePrefix(contractAddress)
prefixStore := prefix.NewStore(ctx.KVStore(k.storeKey), prefixStoreKey)
Expand Down Expand Up @@ -461,10 +452,7 @@ func (k Keeper) Sudo(ctx sdk.Context, contractAddress sdk.AccAddress, msg []byte
env := types.NewEnv(ctx, contractAddress)

// prepare querier
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddress)
gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.Sudo(codeInfo.CodeHash, env, msg, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gas)
consumeGas(ctx, gasUsed)
Expand Down Expand Up @@ -552,10 +540,7 @@ func (k Keeper) QuerySmart(ctx sdk.Context, contractAddr sdk.AccAddress, req []b
}

// prepare querier
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

env := types.NewEnv(ctx, contractAddr)
queryResult, gasUsed, qErr := k.wasmer.Query(codeInfo.CodeHash, env, req, prefixStore, cosmwasmAPI, querier, gasMeter(ctx), gasForContract(ctx))
Expand Down
81 changes: 80 additions & 1 deletion x/wasm/internal/keeper/query_plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package keeper
import (
"encoding/json"
"fmt"
"github.com/CosmWasm/wasmd/x/wasm/internal/types"

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
sdk "github.com/cosmos/cosmos-sdk/types"
Expand All @@ -18,6 +19,15 @@ import (
type QueryHandler struct {
Ctx sdk.Context
Plugins QueryPlugins
Caller sdk.AccAddress
}

func NewQueryHandler(ctx sdk.Context, plugins QueryPlugins, caller sdk.AccAddress) QueryHandler {
return QueryHandler{
Ctx: ctx,
Plugins: plugins,
Caller: caller,
}
}

// -- interfaces from baseapp - so we can use the GPRQueryRouter --
Expand Down Expand Up @@ -51,6 +61,9 @@ func (q QueryHandler) Query(request wasmvmtypes.QueryRequest, gasLimit uint64) (
if request.Custom != nil {
return q.Plugins.Custom(subctx, request.Custom)
}
if request.IBC != nil {
return q.Plugins.IBC(subctx, q.Caller, request.IBC)
}
if request.Staking != nil {
return q.Plugins.Staking(subctx, request.Staking)
}
Expand All @@ -72,15 +85,17 @@ 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
IBC func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error)
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, queryRouter GRPCQueryRouter, wasm *Keeper) QueryPlugins {
func DefaultQueryPlugins(bank bankkeeper.ViewKeeper, staking stakingkeeper.Keeper, distKeeper distributionkeeper.Keeper, channelKeeper types.ChannelKeeper, queryRouter GRPCQueryRouter, wasm *Keeper) QueryPlugins {
return QueryPlugins{
Bank: BankQuerier(bank),
Custom: NoCustomQuerier,
IBC: IBCQuerier(wasm, channelKeeper),
Staking: StakingQuerier(staking, distKeeper),
Stargate: StargateQuerier(queryRouter),
Wasm: WasmQuerier(wasm),
Expand All @@ -98,6 +113,9 @@ func (e QueryPlugins) Merge(o *QueryPlugins) QueryPlugins {
if o.Custom != nil {
e.Custom = o.Custom
}
if o.IBC != nil {
e.IBC = o.IBC
}
if o.Staking != nil {
e.Staking = o.Staking
}
Expand Down Expand Up @@ -146,6 +164,67 @@ func NoCustomQuerier(sdk.Context, json.RawMessage) ([]byte, error) {
return nil, wasmvmtypes.UnsupportedRequest{Kind: "custom"}
}

func IBCQuerier(wasm *Keeper, channelKeeper types.ChannelKeeper) func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) {
return func(ctx sdk.Context, caller sdk.AccAddress, request *wasmvmtypes.IBCQuery) ([]byte, error) {
if request.PortID != nil {
contractInfo := wasm.GetContractInfo(ctx, caller)
res := wasmvmtypes.PortIDResponse{
PortID: contractInfo.IBCPortID,
}
return json.Marshal(res)
}
if request.ListChannels != nil {
portID := request.ListChannels.PortID
var channels wasmvmtypes.IBCEndpoints
channelKeeper.IterateChannels(ctx, func(ch types.IdentifiedChannel) bool {
if portID == "" || portID == ch.PortId {
newChan := wasmvmtypes.IBCEndpoint{
PortID: ch.PortId,
ChannelID: ch.ChannelId,
}
channels = append(channels, newChan)
}
return false
})
res := wasmvmtypes.ListChannelsResponse{
Channels: channels,
}
return json.Marshal(res)
}
if request.Channel != nil {
channelID := request.Channel.ChannelID
portID := request.Channel.PortID
if portID == "" {
contractInfo := wasm.GetContractInfo(ctx, caller)
portID = contractInfo.IBCPortID
}
got, found := channelKeeper.GetChannel(ctx, portID, channelID)
var channel *wasmvmtypes.IBCChannel
if found {
channel = &wasmvmtypes.IBCChannel{
Endpoint: wasmvmtypes.IBCEndpoint{
PortID: portID,
ChannelID: channelID,
},
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{
PortID: got.Counterparty.PortId,
ChannelID: got.Counterparty.ChannelId,
},
Order: got.Ordering.String(),
Version: got.Version,
CounterpartyVersion: "",
ConnectionID: got.ConnectionHops[0],
}
}
res := wasmvmtypes.ChannelResponse{
Channel: channel,
}
return json.Marshal(res)
}
return nil, wasmvmtypes.UnsupportedRequest{Kind: "unknown IBCQuery variant"}
}
}

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)
Expand Down
30 changes: 6 additions & 24 deletions x/wasm/internal/keeper/relay.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ func (k Keeper) OnOpenChannel(
}

env := types.NewEnv(ctx, contractAddr)
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

gas := gasForContract(ctx)
gasUsed, execErr := k.wasmer.IBCChannelOpen(codeInfo.CodeHash, env, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
Expand Down Expand Up @@ -56,10 +53,7 @@ func (k Keeper) OnConnectChannel(
}

env := types.NewEnv(ctx, contractAddr)
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.IBCChannelConnect(codeInfo.CodeHash, env, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
Expand Down Expand Up @@ -95,10 +89,7 @@ func (k Keeper) OnCloseChannel(
}

params := types.NewEnv(ctx, contractAddr)
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.IBCChannelClose(codeInfo.CodeHash, params, channel, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
Expand Down Expand Up @@ -134,10 +125,7 @@ func (k Keeper) OnRecvPacket(
}

env := types.NewEnv(ctx, contractAddr)
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.IBCPacketReceive(codeInfo.CodeHash, env, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
Expand Down Expand Up @@ -174,10 +162,7 @@ func (k Keeper) OnAckPacket(
}

env := types.NewEnv(ctx, contractAddr)
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.IBCPacketAck(codeInfo.CodeHash, env, acknowledgement, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
Expand Down Expand Up @@ -210,10 +195,7 @@ func (k Keeper) OnTimeoutPacket(
}

env := types.NewEnv(ctx, contractAddr)
querier := QueryHandler{
Ctx: ctx,
Plugins: k.queryPlugins,
}
querier := NewQueryHandler(ctx, k.queryPlugins, contractAddr)

gas := gasForContract(ctx)
res, gasUsed, execErr := k.wasmer.IBCPacketTimeout(codeInfo.CodeHash, env, packet, prefixStore, cosmwasmAPI, querier, ctx.GasMeter(), gas)
Expand Down
19 changes: 19 additions & 0 deletions x/wasm/internal/keeper/wasmtesting/mock_keepers.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ type MockChannelKeeper struct {
GetNextSequenceSendFn func(ctx sdk.Context, portID, channelID string) (uint64, bool)
SendPacketFn func(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error
ChanCloseInitFn func(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error
GetAllChannelsFn func(ctx sdk.Context) []channeltypes.IdentifiedChannel
}

func (m *MockChannelKeeper) GetChannel(ctx sdk.Context, srcPort, srcChan string) (channel channeltypes.Channel, found bool) {
Expand All @@ -21,6 +22,24 @@ func (m *MockChannelKeeper) GetChannel(ctx sdk.Context, srcPort, srcChan string)
return m.GetChannelFn(ctx, srcPort, srcChan)
}

func (m *MockChannelKeeper) GetAllChannels(ctx sdk.Context) []channeltypes.IdentifiedChannel {
if m.GetAllChannelsFn == nil {
panic("not supposed to be called!")
}
return m.GetAllChannelsFn(ctx)
}

// Auto-implemented from GetAllChannels data
func (m *MockChannelKeeper) IterateChannels(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool) {
channels := m.GetAllChannels(ctx)
for _, channel := range channels {
stop := cb(channel)
if stop {
break
}
}
}

func (m *MockChannelKeeper) GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool) {
if m.GetNextSequenceSendFn == nil {
panic("not supposed to be called!")
Expand Down
4 changes: 4 additions & 0 deletions x/wasm/internal/types/ibc.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ type ChannelKeeper interface {
GetNextSequenceSend(ctx sdk.Context, portID, channelID string) (uint64, bool)
SendPacket(ctx sdk.Context, channelCap *capabilitytypes.Capability, packet ibcexported.PacketI) error
ChanCloseInit(ctx sdk.Context, portID, channelID string, chanCap *capabilitytypes.Capability) error
GetAllChannels(ctx sdk.Context) (channels []channeltypes.IdentifiedChannel)
IterateChannels(ctx sdk.Context, cb func(channeltypes.IdentifiedChannel) bool)
}

type IdentifiedChannel = channeltypes.IdentifiedChannel

// ClientKeeper defines the expected IBC client keeper
type ClientKeeper interface {
GetClientConsensusState(ctx sdk.Context, clientID string) (connection ibcexported.ConsensusState, found bool)
Expand Down

0 comments on commit 8d9ed87

Please sign in to comment.