Skip to content

Commit

Permalink
Merge pull request #1620 from CosmWasm/channel_query
Browse files Browse the repository at this point in the history
Start rework channel query
  • Loading branch information
alpe authored Sep 14, 2023
2 parents dd22204 + d5fa278 commit e0bfaa5
Show file tree
Hide file tree
Showing 5 changed files with 213 additions and 148 deletions.
189 changes: 189 additions & 0 deletions x/wasm/keeper/query_plugin_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (

wasmvmtypes "github.com/CosmWasm/wasmvm/types"
"github.com/cosmos/gogoproto/proto"
channeltypes "github.com/cosmos/ibc-go/v7/modules/core/04-channel/types"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"

Expand Down Expand Up @@ -642,6 +643,194 @@ func TestDistributionQuery(t *testing.T) {
}
}

func TestIBCListChannelsQuery(t *testing.T) {
cdc := MakeEncodingConfig(t).Codec
pCtx, keepers := CreateTestInput(t, false, ReflectFeatures, WithMessageEncoders(reflectEncoders(cdc)), WithQueryPlugins(reflectPlugins()))
keeper := keepers.WasmKeeper
nonIbcExample := InstantiateReflectExampleContract(t, pCtx, keepers)
ibcExample := InstantiateReflectExampleContract(t, pCtx, keepers)
// add an ibc port for testing
myIBCPortID := "myValidPortID"
cInfo := keeper.GetContractInfo(pCtx, ibcExample.Contract)
cInfo.IBCPortID = myIBCPortID
keeper.storeContractInfo(pCtx, ibcExample.Contract, cInfo)
// store a random channel to be ignored in queries
unusedChan := channeltypes.Channel{
State: channeltypes.OPEN,
Ordering: channeltypes.UNORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "counterPartyPortID",
ChannelId: "counterPartyChannelID",
},
ConnectionHops: []string{"any"},
Version: "any",
}
keepers.IBCKeeper.ChannelKeeper.SetChannel(pCtx, "nonContractPortID", "channel-99", unusedChan)

// mixed channel examples for testing
myExampleChannels := []channeltypes.Channel{
{
State: channeltypes.OPEN,
Ordering: channeltypes.ORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "counterPartyPortID",
ChannelId: "counterPartyChannelID",
},
ConnectionHops: []string{"one"},
Version: "v1",
},
{
State: channeltypes.INIT,
Ordering: channeltypes.UNORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "foobar",
},
ConnectionHops: []string{"one"},
Version: "initversion",
},
{
State: channeltypes.OPEN,
Ordering: channeltypes.UNORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "otherCounterPartyPortID",
ChannelId: "otherCounterPartyChannelID",
},
ConnectionHops: []string{"other", "second"},
Version: "otherVersion",
},
{
State: channeltypes.CLOSED,
Ordering: channeltypes.ORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "super",
ChannelId: "duper",
},
ConnectionHops: []string{"no-more"},
Version: "closedVersion",
},
}

withChannelsStored := func(portID string, channels ...channeltypes.Channel) func(t *testing.T, ctx sdk.Context) sdk.Context {
return func(t *testing.T, ctx sdk.Context) sdk.Context {
for i, v := range channels {
keepers.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, fmt.Sprintf("channel-%d", i), v)
}
return ctx
}
}
noopSetup := func(t *testing.T, ctx sdk.Context) sdk.Context { return ctx }

specs := map[string]struct {
setup func(t *testing.T, ctx sdk.Context) sdk.Context
contract sdk.AccAddress
query *wasmvmtypes.IBCQuery
expErr bool
assert func(t *testing.T, d []byte)
}{
"open channels - with query portID empty": {
contract: ibcExample.Contract,
setup: withChannelsStored(myIBCPortID, myExampleChannels...),
query: &wasmvmtypes.IBCQuery{ListChannels: &wasmvmtypes.ListChannelsQuery{}},
assert: func(t *testing.T, d []byte) {
rsp := unmarshalReflect[wasmvmtypes.ListChannelsResponse](t, d)
exp := wasmvmtypes.ListChannelsResponse{Channels: []wasmvmtypes.IBCChannel{
{
Endpoint: wasmvmtypes.IBCEndpoint{PortID: myIBCPortID, ChannelID: "channel-0"},
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{
PortID: "counterPartyPortID",
ChannelID: "counterPartyChannelID",
},
Order: channeltypes.ORDERED.String(),
Version: "v1",
ConnectionID: "one",
}, {
Endpoint: wasmvmtypes.IBCEndpoint{PortID: myIBCPortID, ChannelID: "channel-2"},
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{
PortID: "otherCounterPartyPortID",
ChannelID: "otherCounterPartyChannelID",
},
Order: channeltypes.UNORDERED.String(),
Version: "otherVersion",
ConnectionID: "other",
},
}}
assert.Equal(t, exp, rsp)
},
},
"open channels - with query portID passed": {
contract: ibcExample.Contract,
setup: withChannelsStored("OtherPortID", myExampleChannels...),
query: &wasmvmtypes.IBCQuery{ListChannels: &wasmvmtypes.ListChannelsQuery{PortID: "OtherPortID"}},
assert: func(t *testing.T, d []byte) {
rsp := unmarshalReflect[wasmvmtypes.ListChannelsResponse](t, d)
exp := wasmvmtypes.ListChannelsResponse{Channels: []wasmvmtypes.IBCChannel{
{
Endpoint: wasmvmtypes.IBCEndpoint{PortID: "OtherPortID", ChannelID: "channel-0"},
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{
PortID: "counterPartyPortID",
ChannelID: "counterPartyChannelID",
},
Order: channeltypes.ORDERED.String(),
Version: "v1",
ConnectionID: "one",
}, {
Endpoint: wasmvmtypes.IBCEndpoint{PortID: "OtherPortID", ChannelID: "channel-2"},
CounterpartyEndpoint: wasmvmtypes.IBCEndpoint{
PortID: "otherCounterPartyPortID",
ChannelID: "otherCounterPartyChannelID",
},
Order: channeltypes.UNORDERED.String(),
Version: "otherVersion",
ConnectionID: "other",
},
}}
assert.Equal(t, exp, rsp)
},
},
"non ibc contract - with query portID empty": {
contract: nonIbcExample.Contract,
setup: withChannelsStored(myIBCPortID, myExampleChannels...),
query: &wasmvmtypes.IBCQuery{ListChannels: &wasmvmtypes.ListChannelsQuery{}},
assert: func(t *testing.T, d []byte) {
rsp := unmarshalReflect[wasmvmtypes.ListChannelsResponse](t, d)
assert.Nil(t, rsp.Channels)
},
},
"no matching channels": {
contract: ibcExample.Contract,
setup: noopSetup,
query: &wasmvmtypes.IBCQuery{ListChannels: &wasmvmtypes.ListChannelsQuery{}},
assert: func(t *testing.T, d []byte) {
rsp := unmarshalReflect[wasmvmtypes.ListChannelsResponse](t, d)
assert.Empty(t, rsp.Channels)
},
},
}
for name, spec := range specs {
t.Run(name, func(t *testing.T) {
ctx, _ := pCtx.CacheContext()
ctx = spec.setup(t, ctx)

// when
queryBz := mustMarshal(t, testdata.ReflectQueryMsg{
Chain: &testdata.ChainQuery{
Request: &wasmvmtypes.QueryRequest{IBC: spec.query},
},
})
simpleRes, gotErr := keeper.QuerySmart(ctx, spec.contract, queryBz)
if spec.expErr {
require.Error(t, gotErr)
return
}
// then
require.NoError(t, gotErr)
var rsp testdata.ChainResponse
mustUnmarshal(t, simpleRes, &rsp)
spec.assert(t, rsp.Data)
})
}
}

func unmarshalReflect[T any](t *testing.T, d []byte) T {
var v T
mustUnmarshal(t, d, &v)
Expand Down
23 changes: 14 additions & 9 deletions x/wasm/keeper/query_plugins.go
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,18 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper)
}
if request.ListChannels != nil {
portID := request.ListChannels.PortID
channels := make(wasmvmtypes.IBCChannels, 0)
channelKeeper.IterateChannels(ctx, func(ch channeltypes.IdentifiedChannel) bool {
// it must match the port and be in open state
if (portID == "" || portID == ch.PortId) && ch.State == channeltypes.OPEN {
newChan := wasmvmtypes.IBCChannel{
if portID == "" { // then fallback to contract port address
portID = wasm.GetContractInfo(ctx, caller).IBCPortID
}
var channels wasmvmtypes.IBCChannels
if portID != "" { // then return empty list for non ibc contracts; no channels possible
gotChannels := channelKeeper.GetAllChannelsWithPortPrefix(ctx, portID)
channels = make(wasmvmtypes.IBCChannels, 0, len(gotChannels))
for _, ch := range gotChannels {
if ch.State != channeltypes.OPEN {
continue
}
channels = append(channels, wasmvmtypes.IBCChannel{
Endpoint: wasmvmtypes.IBCEndpoint{
PortID: ch.PortId,
ChannelID: ch.ChannelId,
Expand All @@ -265,11 +272,9 @@ func IBCQuerier(wasm contractMetaDataSource, channelKeeper types.ChannelKeeper)
Order: ch.Ordering.String(),
Version: ch.Version,
ConnectionID: ch.ConnectionHops[0],
}
channels = append(channels, newChan)
})
}
return false
})
}
res := wasmvmtypes.ListChannelsResponse{
Channels: channels,
}
Expand Down
129 changes: 0 additions & 129 deletions x/wasm/keeper/query_plugins_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,59 +40,6 @@ import (
)

func TestIBCQuerier(t *testing.T) {
myExampleChannels := []channeltypes.IdentifiedChannel{
// this is returned
{
State: channeltypes.OPEN,
Ordering: channeltypes.ORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "counterPartyPortID",
ChannelId: "counterPartyChannelID",
},
ConnectionHops: []string{"one"},
Version: "v1",
PortId: "myPortID",
ChannelId: "myChannelID",
},
// this is filtered out
{
State: channeltypes.INIT,
Ordering: channeltypes.UNORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "foobar",
},
ConnectionHops: []string{"one"},
Version: "initversion",
PortId: "initPortID",
ChannelId: "initChannelID",
},
// this is returned
{
State: channeltypes.OPEN,
Ordering: channeltypes.UNORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "otherCounterPartyPortID",
ChannelId: "otherCounterPartyChannelID",
},
ConnectionHops: []string{"other", "second"},
Version: "otherVersion",
PortId: "otherPortID",
ChannelId: "otherChannelID",
},
// this is filtered out
{
State: channeltypes.CLOSED,
Ordering: channeltypes.ORDERED,
Counterparty: channeltypes.Counterparty{
PortId: "super",
ChannelId: "duper",
},
ConnectionHops: []string{"no-more"},
Version: "closedVersion",
PortId: "closedPortID",
ChannelId: "closedChannelID",
},
}
specs := map[string]struct {
srcQuery *wasmvmtypes.IBCQuery
wasmKeeper *mockWasmQueryKeeper
Expand All @@ -112,82 +59,6 @@ func TestIBCQuerier(t *testing.T) {
channelKeeper: &wasmtesting.MockChannelKeeper{},
expJSONResult: `{"port_id":"myIBCPortID"}`,
},
"query list channels - all": {
srcQuery: &wasmvmtypes.IBCQuery{
ListChannels: &wasmvmtypes.ListChannelsQuery{},
},
channelKeeper: &wasmtesting.MockChannelKeeper{
IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels),
},
expJSONResult: `{
"channels": [
{
"endpoint": {
"port_id": "myPortID",
"channel_id": "myChannelID"
},
"counterparty_endpoint": {
"port_id": "counterPartyPortID",
"channel_id": "counterPartyChannelID"
},
"order": "ORDER_ORDERED",
"version": "v1",
"connection_id": "one"
},
{
"endpoint": {
"port_id": "otherPortID",
"channel_id": "otherChannelID"
},
"counterparty_endpoint": {
"port_id": "otherCounterPartyPortID",
"channel_id": "otherCounterPartyChannelID"
},
"order": "ORDER_UNORDERED",
"version": "otherVersion",
"connection_id": "other"
}
]
}`,
},
"query list channels - filtered": {
srcQuery: &wasmvmtypes.IBCQuery{
ListChannels: &wasmvmtypes.ListChannelsQuery{
PortID: "otherPortID",
},
},
channelKeeper: &wasmtesting.MockChannelKeeper{
IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels),
},
expJSONResult: `{
"channels": [
{
"endpoint": {
"port_id": "otherPortID",
"channel_id": "otherChannelID"
},
"counterparty_endpoint": {
"port_id": "otherCounterPartyPortID",
"channel_id": "otherCounterPartyChannelID"
},
"order": "ORDER_UNORDERED",
"version": "otherVersion",
"connection_id": "other"
}
]
}`,
},
"query list channels - filtered empty": {
srcQuery: &wasmvmtypes.IBCQuery{
ListChannels: &wasmvmtypes.ListChannelsQuery{
PortID: "none-existing",
},
},
channelKeeper: &wasmtesting.MockChannelKeeper{
IterateChannelsFn: wasmtesting.MockChannelKeeperIterator(myExampleChannels),
},
expJSONResult: `{"channels": []}`,
},
"query channel": {
srcQuery: &wasmvmtypes.IBCQuery{
Channel: &wasmvmtypes.ChannelQuery{
Expand Down
Loading

0 comments on commit e0bfaa5

Please sign in to comment.