Skip to content

Commit c3be169

Browse files
authored
Add interchain account OnChanOpenInit and InitInterchainAccount tests (#287)
* add OnChanOpenInit test * add InitInterchainAccount test * Update modules/apps/27-interchain-accounts/keeper/relay.go
1 parent b870be4 commit c3be169

File tree

7 files changed

+213
-39
lines changed

7 files changed

+213
-39
lines changed

modules/apps/27-interchain-accounts/keeper/account.go

Lines changed: 18 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,51 +4,40 @@ import (
44
sdk "github.com/cosmos/cosmos-sdk/types"
55
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
66
authtypes "github.com/cosmos/cosmos-sdk/x/auth/types"
7+
"github.com/tendermint/tendermint/crypto/tmhash"
8+
9+
"github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"
710
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
811
host "github.com/cosmos/ibc-go/modules/core/24-host"
9-
"github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"
10-
"github.com/tendermint/tendermint/crypto/tmhash"
1112
)
1213

13-
// The first step in registering an interchain account
14-
// Binds a new port & calls OnChanOpenInit
14+
// InitInterchainAccount is the entry point to registering an interchain account.
15+
// It generates a new port identifier using the owner address, connection identifier,
16+
// and counterparty connection identifier. It will bind to the port identifier and
17+
// call 04-channel 'ChanOpenInit'. An error is returned if the port identifier is
18+
// already in use. Gaining access to interchain accounts whose channels have closed
19+
// cannot be done with this function. A regular MsgChanOpenInit must be used.
1520
func (k Keeper) InitInterchainAccount(ctx sdk.Context, connectionId, owner string) error {
1621
portId := k.GeneratePortId(owner, connectionId)
1722

18-
// Check if the port is already bound
19-
isBound := k.IsBound(ctx, portId)
20-
if isBound == true {
23+
// check if the port is already bound
24+
if k.IsBound(ctx, portId) {
2125
return sdkerrors.Wrap(types.ErrPortAlreadyBound, portId)
2226
}
2327

2428
portCap := k.portKeeper.BindPort(ctx, portId)
2529
err := k.ClaimCapability(ctx, portCap, host.PortPath(portId))
2630
if err != nil {
31+
return sdkerrors.Wrap(err, "unable to bind to newly generated portID")
32+
}
33+
34+
msg := channeltypes.NewMsgChannelOpenInit(portId, types.Version, channeltypes.ORDERED, []string{connectionId}, types.PortID, types.ModuleName)
35+
handler := k.msgRouter.Handler(msg)
36+
if _, err := handler(ctx, msg); err != nil {
2737
return err
2838
}
2939

30-
counterParty := channeltypes.Counterparty{PortId: "ibcaccount", ChannelId: ""}
31-
order := channeltypes.Order(2)
32-
channelId, cap, err := k.channelKeeper.ChanOpenInit(ctx, order, []string{connectionId}, portId, portCap, counterParty, types.Version)
33-
34-
ctx.EventManager().EmitEvents(sdk.Events{
35-
sdk.NewEvent(
36-
channeltypes.EventTypeChannelOpenInit,
37-
sdk.NewAttribute(channeltypes.AttributeKeyPortID, portId),
38-
sdk.NewAttribute(channeltypes.AttributeKeyChannelID, channelId),
39-
sdk.NewAttribute(channeltypes.AttributeCounterpartyPortID, "ibcaccount"),
40-
sdk.NewAttribute(channeltypes.AttributeCounterpartyChannelID, ""),
41-
sdk.NewAttribute(channeltypes.AttributeKeyConnectionID, connectionId),
42-
),
43-
sdk.NewEvent(
44-
sdk.EventTypeMessage,
45-
sdk.NewAttribute(sdk.AttributeKeyModule, channeltypes.AttributeValueCategory),
46-
),
47-
})
48-
49-
_ = k.OnChanOpenInit(ctx, channeltypes.Order(2), []string{connectionId}, portId, channelId, cap, counterParty, types.Version)
50-
51-
return err
40+
return nil
5241
}
5342

5443
// Register interchain account if it has not already been created
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
package keeper_test
2+
3+
import (
4+
ibctesting "github.com/cosmos/ibc-go/testing"
5+
)
6+
7+
func (suite *KeeperTestSuite) TestInitInterchainAccount() {
8+
var (
9+
owner string
10+
path *ibctesting.Path
11+
err error
12+
)
13+
14+
testCases := []struct {
15+
name string
16+
malleate func()
17+
expPass bool
18+
}{
19+
20+
{
21+
"success", func() {}, true,
22+
},
23+
/*
24+
// TODO: https://github.com/cosmos/ibc-go/issues/288
25+
{
26+
"port is already bound", func() {
27+
// mock init interchain account
28+
portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId(owner, path.EndpointA.ConnectionID)
29+
suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID)
30+
}, false,
31+
},
32+
*/
33+
{
34+
"MsgChanOpenInit fails - channel is already active", func() {
35+
portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId(owner, path.EndpointA.ConnectionID)
36+
suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), portID, path.EndpointA.ChannelID)
37+
}, false,
38+
},
39+
}
40+
41+
for _, tc := range testCases {
42+
tc := tc
43+
44+
suite.Run(tc.name, func() {
45+
suite.SetupTest() // reset
46+
owner = "owner" // must be explicitly changed
47+
path = NewICAPath(suite.chainA, suite.chainB)
48+
suite.coordinator.SetupConnections(path)
49+
50+
tc.malleate() // explicitly change fields in channel and testChannel
51+
52+
err = suite.chainA.GetSimApp().ICAKeeper.InitInterchainAccount(suite.chainA.GetContext(), path.EndpointA.ConnectionID, owner)
53+
54+
if tc.expPass {
55+
suite.Require().NoError(err)
56+
} else {
57+
suite.Require().Error(err)
58+
}
59+
60+
})
61+
}
62+
}

modules/apps/27-interchain-accounts/keeper/handshake.go

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,20 @@ import (
44
sdk "github.com/cosmos/cosmos-sdk/types"
55
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
66
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
7+
8+
"github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"
79
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
10+
porttypes "github.com/cosmos/ibc-go/modules/core/05-port/types"
811
host "github.com/cosmos/ibc-go/modules/core/24-host"
912
)
1013

14+
// OnChanOpenInit performs basic validation of channel initialization.
15+
// The channel order must be ORDERED, the counterparty port identifier
16+
// must be the host chain representation as defined in the types package,
17+
// the channel version must be equal to the version in the types package,
18+
// there must not be an active channel for the specfied port identifier,
19+
// and the interchain accounts module must be able to claim the channel
20+
// capability.
1121
func (k Keeper) OnChanOpenInit(
1222
ctx sdk.Context,
1323
order channeltypes.Order,
@@ -18,11 +28,19 @@ func (k Keeper) OnChanOpenInit(
1828
counterparty channeltypes.Counterparty,
1929
version string,
2030
) error {
21-
//TODO:
22-
// check version string
2331
if order != channeltypes.ORDERED {
2432
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelOrdering, "invalid channel ordering: %s, expected %s", order.String(), channeltypes.ORDERED.String())
2533
}
34+
if counterparty.PortId != types.PortID {
35+
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "counterparty port-id must be '%s', (%s != %s)", types.PortID, counterparty.PortId, types.PortID)
36+
}
37+
if version != types.Version {
38+
return sdkerrors.Wrapf(channeltypes.ErrInvalidChannelVersion, "channel version must be '%s' (%s != %s)", types.Version, version, types.Version)
39+
}
40+
channelID, found := k.GetActiveChannel(ctx, portID)
41+
if found {
42+
return sdkerrors.Wrapf(porttypes.ErrInvalidPort, "existing active channel (%s) for portID (%s)", channelID, portID)
43+
}
2644

2745
// Claim channel capability passed back by IBC module
2846
if err := k.ClaimCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)); err != nil {
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,98 @@
11
package keeper_test
2+
3+
import (
4+
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
5+
6+
"github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"
7+
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
8+
host "github.com/cosmos/ibc-go/modules/core/24-host"
9+
ibctesting "github.com/cosmos/ibc-go/testing"
10+
)
11+
12+
func (suite *KeeperTestSuite) TestOnChanOpenInit() {
13+
var (
14+
channel *channeltypes.Channel
15+
path *ibctesting.Path
16+
chanCap *capabilitytypes.Capability
17+
err error
18+
)
19+
20+
testCases := []struct {
21+
name string
22+
malleate func()
23+
expPass bool
24+
}{
25+
26+
{
27+
"success", func() {}, true,
28+
},
29+
{
30+
"invalid order - UNORDERED", func() {
31+
channel.Ordering = channeltypes.UNORDERED
32+
}, false,
33+
},
34+
{
35+
"invalid counterparty port ID", func() {
36+
channel.Counterparty.PortId = ibctesting.MockPort
37+
}, false,
38+
},
39+
{
40+
"invalid version", func() {
41+
channel.Version = "version"
42+
}, false,
43+
},
44+
{
45+
"channel is already active", func() {
46+
suite.chainA.GetSimApp().ICAKeeper.SetActiveChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
47+
}, false,
48+
},
49+
{
50+
"capability already claimed", func() {
51+
err := suite.chainA.GetSimApp().ScopedICAKeeper.ClaimCapability(suite.chainA.GetContext(), chanCap, host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID))
52+
suite.Require().NoError(err)
53+
}, false,
54+
},
55+
}
56+
57+
for _, tc := range testCases {
58+
tc := tc
59+
60+
suite.Run(tc.name, func() {
61+
suite.SetupTest() // reset
62+
path = NewICAPath(suite.chainA, suite.chainB)
63+
suite.coordinator.SetupConnections(path)
64+
65+
// mock init interchain account
66+
portID := suite.chainA.GetSimApp().ICAKeeper.GeneratePortId("owner", path.EndpointA.ConnectionID)
67+
portCap := suite.chainA.GetSimApp().IBCKeeper.PortKeeper.BindPort(suite.chainA.GetContext(), portID)
68+
suite.chainA.GetSimApp().ICAKeeper.ClaimCapability(suite.chainA.GetContext(), portCap, host.PortPath(portID))
69+
path.EndpointA.ChannelConfig.PortID = portID
70+
71+
// default values
72+
counterparty := channeltypes.NewCounterparty(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
73+
channel = &channeltypes.Channel{
74+
State: channeltypes.INIT,
75+
Ordering: channeltypes.ORDERED,
76+
Counterparty: counterparty,
77+
ConnectionHops: []string{path.EndpointA.ConnectionID},
78+
Version: types.Version,
79+
}
80+
81+
chanCap, err = suite.chainA.App.GetScopedIBCKeeper().NewCapability(suite.chainA.GetContext(), host.ChannelCapabilityPath(portID, path.EndpointA.ChannelID))
82+
suite.Require().NoError(err)
83+
84+
tc.malleate() // explicitly change fields in channel and testChannel
85+
86+
err = suite.chainA.GetSimApp().ICAKeeper.OnChanOpenInit(suite.chainA.GetContext(), channel.Ordering, channel.GetConnectionHops(),
87+
path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, chanCap, channel.Counterparty, channel.GetVersion(),
88+
)
89+
90+
if tc.expPass {
91+
suite.Require().NoError(err)
92+
} else {
93+
suite.Require().Error(err)
94+
}
95+
96+
})
97+
}
98+
}

modules/apps/27-interchain-accounts/keeper/keeper.go

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import (
88
"github.com/cosmos/cosmos-sdk/codec"
99
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
1010
sdk "github.com/cosmos/cosmos-sdk/types"
11-
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
1211
capabilitykeeper "github.com/cosmos/cosmos-sdk/x/capability/keeper"
1312
capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
1413
host "github.com/cosmos/ibc-go/modules/core/24-host"
@@ -145,13 +144,20 @@ func (k Keeper) SetActiveChannel(ctx sdk.Context, portId, channelId string) erro
145144
return nil
146145
}
147146

148-
func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, error) {
147+
func (k Keeper) GetActiveChannel(ctx sdk.Context, portId string) (string, bool) {
149148
store := ctx.KVStore(k.storeKey)
150149
key := types.KeyActiveChannel(portId)
151150
if !store.Has(key) {
152-
return "", sdkerrors.Wrap(types.ErrActiveChannelNotFound, portId)
151+
return "", false
153152
}
154153

155154
activeChannel := string(store.Get(key))
156-
return activeChannel, nil
155+
return activeChannel, true
156+
}
157+
158+
// IsActiveChannel returns true if there exists an active channel for
159+
// the provided portID and false otherwise.
160+
func (k Keeper) IsActiveChannel(ctx sdk.Context, portId string) bool {
161+
_, found := k.GetActiveChannel(ctx, portId)
162+
return found
157163
}

modules/apps/27-interchain-accounts/keeper/relay.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,19 @@ import (
55

66
sdk "github.com/cosmos/cosmos-sdk/types"
77
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
8+
"github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"
89
clienttypes "github.com/cosmos/ibc-go/modules/core/02-client/types"
910
channeltypes "github.com/cosmos/ibc-go/modules/core/04-channel/types"
1011
host "github.com/cosmos/ibc-go/modules/core/24-host"
11-
"github.com/cosmos/ibc-go/modules/apps/27-interchain-accounts/types"
1212
"github.com/tendermint/tendermint/crypto/tmhash"
1313
)
1414

1515
func (k Keeper) TrySendTx(ctx sdk.Context, accountOwner sdk.AccAddress, connectionId string, data interface{}) ([]byte, error) {
1616
portId := k.GeneratePortId(accountOwner.String(), connectionId)
1717
// Check for the active channel
18-
activeChannelId, err := k.GetActiveChannel(ctx, portId)
19-
if err != nil {
20-
return nil, err
18+
activeChannelId, found := k.GetActiveChannel(ctx, portId)
19+
if !found {
20+
return nil, types.ErrActiveChannelNotFound
2121
}
2222

2323
sourceChannelEnd, found := k.channelKeeper.GetChannel(ctx, portId, activeChannelId)

modules/core/04-channel/types/errors.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,4 +30,6 @@ var (
3030

3131
// ORDERED channel error
3232
ErrPacketSequenceOutOfOrder = sdkerrors.Register(SubModuleName, 21, "packet sequence is out of order")
33+
34+
ErrInvalidChannelVersion = sdkerrors.Register(SubModuleName, 24, "invalid channel version")
3335
)

0 commit comments

Comments
 (0)