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

Start rework channel query #1620

Merged
merged 3 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all 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
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)
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

really good tests!

},
"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
webmaster128 marked this conversation as resolved.
Show resolved Hide resolved
}
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