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

Fix Optimistic Channel Handshake bugs #7678

Merged
merged 6 commits into from
Oct 27, 2020
Merged
Show file tree
Hide file tree
Changes from 4 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
31 changes: 24 additions & 7 deletions x/ibc/core/04-channel/keeper/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,16 +187,33 @@ func (k Keeper) ChanOpenTry(
return nil, err
}

k.SetChannel(ctx, portID, desiredChannelID, channel)
var (
capKey *capabilitytypes.Capability
err error
)

capKey, err := k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, desiredChannelID))
if err != nil {
return nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, desiredChannelID)
// Only create a capability and set the sequences if the previous channel does not exist
_, found = k.GetChannel(ctx, portID, desiredChannelID)
if !found {
capKey, err = k.scopedKeeper.NewCapability(ctx, host.ChannelCapabilityPath(portID, desiredChannelID))
if err != nil {
return nil, sdkerrors.Wrapf(err, "could not create channel capability for port ID %s and channel ID %s", portID, desiredChannelID)
}

k.SetNextSequenceSend(ctx, portID, desiredChannelID, 1)
k.SetNextSequenceRecv(ctx, portID, desiredChannelID, 1)
k.SetNextSequenceAck(ctx, portID, desiredChannelID, 1)
} else {
// capability initialized in ChanOpenInit
capKey, found = k.scopedKeeper.GetCapability(ctx, host.ChannelCapabilityPath(portID, desiredChannelID))
if !found {
return nil, sdkerrors.Wrapf(types.ErrChannelCapabilityNotFound,
"capability not found for existing channel, portID (%s) channelID (%s)", portID, desiredChannelID,
)
}
}

k.SetNextSequenceSend(ctx, portID, desiredChannelID, 1)
k.SetNextSequenceRecv(ctx, portID, desiredChannelID, 1)
k.SetNextSequenceAck(ctx, portID, desiredChannelID, 1)
k.SetChannel(ctx, portID, desiredChannelID, channel)

k.Logger(ctx).Info("channel state updated", "port-id", portID, "channel-id", desiredChannelID, "previous-state", previousChannel.State.String(), "new-state", "TRYOPEN")

Expand Down
6 changes: 6 additions & 0 deletions x/ibc/core/04-channel/keeper/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,12 @@ func (suite *KeeperTestSuite) TestChanOpenTry() {
suite.chainB.CreatePortCapability(connB.NextTestChannel(ibctesting.MockPort).PortID)
portCap = suite.chainB.GetPortCapability(connB.NextTestChannel(ibctesting.MockPort).PortID)
}, true},
{"success with crossing hello", func() {
_, _, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, ibctesting.Tendermint)
suite.coordinator.ChanOpenInitOnBothChains(suite.chainA, suite.chainB, connA, connB, ibctesting.MockPort, ibctesting.MockPort, types.ORDERED)

portCap = suite.chainB.GetPortCapability(connB.NextTestChannel(ibctesting.MockPort).PortID)
}, true},
{"success with empty counterparty chosen channel id", func() {
var clientA, clientB string
clientA, clientB, connA, connB = suite.coordinator.SetupClientConnections(suite.chainA, suite.chainB, ibctesting.Tendermint)
Expand Down
48 changes: 48 additions & 0 deletions x/ibc/testing/coordinator.go
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,54 @@ func (coord *Coordinator) ChanOpenInit(
return sourceChannel, counterpartyChannel, nil
}

// ChanOpenInitOnBothChains initializes a channel on the source chain and counterparty chain
// with the state INIT using the OpenInit handshake call.
func (coord *Coordinator) ChanOpenInitOnBothChains(
source, counterparty *TestChain,
connection, counterpartyConnection *TestConnection,
sourcePortID, counterpartyPortID string,
order channeltypes.Order,
) (TestChannel, TestChannel, error) {
sourceChannel := connection.AddTestChannel(sourcePortID)
counterpartyChannel := counterpartyConnection.AddTestChannel(counterpartyPortID)

// NOTE: only creation of a capability for a transfer or mock port is supported
// Other applications must bind to the port in InitGenesis or modify this code.
source.CreatePortCapability(sourceChannel.PortID)
counterparty.CreatePortCapability(counterpartyChannel.PortID)
coord.IncrementTime()

// initialize channel on source
if err := source.ChanOpenInit(sourceChannel, counterpartyChannel, order, connection.ID); err != nil {
return sourceChannel, counterpartyChannel, err
}
coord.IncrementTime()

// initialize channel on counterparty
if err := counterparty.ChanOpenInit(counterpartyChannel, sourceChannel, order, counterpartyConnection.ID); err != nil {
return sourceChannel, counterpartyChannel, err
}
coord.IncrementTime()

// update counterparty client on source connection
if err := coord.UpdateClient(
source, counterparty,
connection.ClientID, Tendermint,
); err != nil {
return sourceChannel, counterpartyChannel, err
}

// update source client on counterparty connection
if err := coord.UpdateClient(
counterparty, source,
counterpartyConnection.ClientID, Tendermint,
); err != nil {
return sourceChannel, counterpartyChannel, err
}

return sourceChannel, counterpartyChannel, nil
}

// ChanOpenTry initializes a channel on the source chain with the state TRYOPEN
// using the OpenTry handshake call.
func (coord *Coordinator) ChanOpenTry(
Expand Down