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

Allow verification of channels on TimeoutonClose and ChanCloseConfirm #4388

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
3 changes: 2 additions & 1 deletion e2e/tests/interchain_accounts/localhost_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -327,7 +327,8 @@ func (s *LocalhostInterchainAccountsTestSuite) TestInterchainAccounts_ReopenChan
})

t.Run("close interchain accounts host channel end", func(t *testing.T) {
msgCloseConfirm := channeltypes.NewMsgChannelCloseConfirm(icatypes.HostPortID, msgChanOpenTryRes.ChannelId, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress())
// Pass in zero for counterpartyUpgradeSequence given that channel has not undergone any upgrades.
msgCloseConfirm := channeltypes.NewMsgChannelCloseConfirm(icatypes.HostPortID, msgChanOpenTryRes.ChannelId, localhost.SentinelProof, clienttypes.ZeroHeight(), rlyWallet.FormattedAddress(), 0)

txResp := s.BroadcastMessages(ctx, chainA, rlyWallet, msgCloseConfirm)
s.AssertTxSuccess(txResp)
Expand Down
13 changes: 9 additions & 4 deletions modules/core/04-channel/keeper/handshake.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,7 @@ func (k Keeper) ChanCloseConfirm(
chanCap *capabilitytypes.Capability,
proofInit []byte,
proofHeight exported.Height,
counterpartyUpgradeSequence uint64,
) error {
if !k.scopedKeeper.AuthenticateCapability(ctx, chanCap, host.ChannelCapabilityPath(portID, channelID)) {
return errorsmod.Wrap(types.ErrChannelCapabilityNotFound, "caller does not own capability for channel, port ID (%s) channel ID (%s)")
Expand Down Expand Up @@ -460,10 +461,14 @@ func (k Keeper) ChanCloseConfirm(
counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}

counterparty := types.NewCounterparty(portID, channelID)
expectedChannel := types.NewChannel(
types.CLOSED, channel.Ordering, counterparty,
counterpartyHops, channel.Version,
)
expectedChannel := types.Channel{
State: types.CLOSED,
Ordering: channel.Ordering,
Counterparty: counterparty,
ConnectionHops: counterpartyHops,
Version: channel.Version,
UpgradeSequence: counterpartyUpgradeSequence,
}

if err := k.connectionKeeper.VerifyChannelState(
ctx, connectionEnd, proofHeight, proofInit,
Expand Down
33 changes: 27 additions & 6 deletions modules/core/04-channel/keeper/handshake_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
ibctesting "github.com/cosmos/ibc-go/v8/testing"
"github.com/cosmos/ibc-go/v8/testing/mock"
)

type testCase = struct {
Expand Down Expand Up @@ -718,9 +719,10 @@ func (suite *KeeperTestSuite) TestChanCloseInit() {
// bypassed on chainA by setting the channel state in the ChannelKeeper.
func (suite *KeeperTestSuite) TestChanCloseConfirm() {
var (
path *ibctesting.Path
channelCap *capabilitytypes.Capability
heightDiff uint64
path *ibctesting.Path
channelCap *capabilitytypes.Capability
heightDiff uint64
counterpartyUpgradeSequence uint64
)

testCases := []testCase{
Expand Down Expand Up @@ -794,13 +796,32 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() {

channelCap = capabilitytypes.NewCapability(3)
}, false},
{
"failure: invalid counterparty upgrade sequence",
func() {
suite.coordinator.Setup(path)
channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)

// trigger upgradeInit on B which will bump the counterparty upgrade sequence.
path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion
err := path.EndpointB.ChanUpgradeInit()
suite.Require().NoError(err)

err = path.EndpointA.SetChannelState(types.CLOSED)
suite.Require().NoError(err)

channelCap = capabilitytypes.NewCapability(3)
},
false,
},
}

for _, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
suite.SetupTest() // reset
heightDiff = 0 // must explicitly be changed
suite.SetupTest() // reset
heightDiff = 0 // must explicitly be changed
counterpartyUpgradeSequence = 0 // must explicitly be changed
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
path = ibctesting.NewPath(suite.chainA, suite.chainB)

tc.malleate()
Expand All @@ -810,7 +831,7 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() {

err := suite.chainB.App.GetIBCKeeper().ChannelKeeper.ChanCloseConfirm(
suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID, channelCap,
proof, malleateHeight(proofHeight, heightDiff),
proof, malleateHeight(proofHeight, heightDiff), counterpartyUpgradeSequence,
)

if tc.expPass {
Expand Down
12 changes: 9 additions & 3 deletions modules/core/04-channel/keeper/timeout.go
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ func (k Keeper) TimeoutOnClose(
proofClosed []byte,
proofHeight exported.Height,
nextSequenceRecv uint64,
counterpartyUpgradeSequence uint64,
) error {
channel, found := k.GetChannel(ctx, packet.GetSourcePort(), packet.GetSourceChannel())
if !found {
Expand Down Expand Up @@ -263,9 +264,14 @@ func (k Keeper) TimeoutOnClose(
counterpartyHops := []string{connectionEnd.GetCounterparty().GetConnectionID()}

counterparty := types.NewCounterparty(packet.GetSourcePort(), packet.GetSourceChannel())
expectedChannel := types.NewChannel(
types.CLOSED, channel.Ordering, counterparty, counterpartyHops, channel.Version,
)
expectedChannel := types.Channel{
State: types.CLOSED,
Ordering: channel.Ordering,
Counterparty: counterparty,
ConnectionHops: counterpartyHops,
Version: channel.Version,
UpgradeSequence: counterpartyUpgradeSequence,
}

// check that the opposing channel end has closed
if err := k.connectionKeeper.VerifyChannelState(
Expand Down
56 changes: 48 additions & 8 deletions modules/core/04-channel/keeper/timeout_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import (
host "github.com/cosmos/ibc-go/v8/modules/core/24-host"
"github.com/cosmos/ibc-go/v8/modules/core/exported"
ibctesting "github.com/cosmos/ibc-go/v8/testing"
"github.com/cosmos/ibc-go/v8/testing/mock"
)

// TestTimeoutPacket test the TimeoutPacket call on chainA by ensuring the timeout has passed
Expand Down Expand Up @@ -542,11 +543,12 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() {
// channel on chainB after the packet commitment has been created.
func (suite *KeeperTestSuite) TestTimeoutOnClose() {
var (
path *ibctesting.Path
packet types.Packet
chanCap *capabilitytypes.Capability
nextSeqRecv uint64
ordered bool
path *ibctesting.Path
packet types.Packet
chanCap *capabilitytypes.Capability
nextSeqRecv uint64
counterpartyUpgradeSequence uint64
ordered bool
)

testCases := []testCase{
Expand Down Expand Up @@ -711,15 +713,44 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() {
packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, clienttypes.GetSelfHeight(suite.chainB.GetContext()), uint64(suite.chainB.GetContext().BlockTime().UnixNano()))
chanCap = capabilitytypes.NewCapability(100)
}, false},
{
"failure: invalid counterparty upgrade sequence",
func() {
ordered = false
suite.coordinator.Setup(path)

timeoutHeight := clienttypes.GetSelfHeight(suite.chainB.GetContext())

sequence, err := path.EndpointA.SendPacket(timeoutHeight, disabledTimeoutTimestamp, ibctesting.MockPacketData)
suite.Require().NoError(err)

// trigger upgradeInit on B which will bump the counterparty upgrade sequence.
path.EndpointB.ChannelConfig.ProposedUpgrade.Fields.Version = mock.UpgradeVersion
err = path.EndpointB.ChanUpgradeInit()
suite.Require().NoError(err)

err = path.EndpointB.SetChannelState(types.CLOSED)
suite.Require().NoError(err)

// need to update chainA's client representing chainB to prove missing ack
err = path.EndpointA.UpdateClient()
suite.Require().NoError(err)

packet = types.NewPacket(ibctesting.MockPacketData, sequence, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, timeoutHeight, disabledTimeoutTimestamp)
chanCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
},
false,
},
}

for i, tc := range testCases {
tc := tc
suite.Run(fmt.Sprintf("Case %s, %d/%d tests", tc.msg, i, len(testCases)), func() {
var proof []byte

suite.SetupTest() // reset
nextSeqRecv = 1 // must be explicitly changed
suite.SetupTest() // reset
nextSeqRecv = 1 // must be explicitly changed
counterpartyUpgradeSequence = 0 // must be explicitly changed
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
path = ibctesting.NewPath(suite.chainA, suite.chainB)

tc.malleate()
Expand All @@ -736,7 +767,16 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() {
proof, _ = suite.chainB.QueryProof(unorderedPacketKey)
}

err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutOnClose(suite.chainA.GetContext(), chanCap, packet, proof, proofClosed, proofHeight, nextSeqRecv)
err := suite.chainA.App.GetIBCKeeper().ChannelKeeper.TimeoutOnClose(
suite.chainA.GetContext(),
chanCap,
packet,
proof,
proofClosed,
proofHeight,
nextSeqRecv,
counterpartyUpgradeSequence,
)

if tc.expPass {
suite.Require().NoError(err)
Expand Down
27 changes: 15 additions & 12 deletions modules/core/04-channel/types/msgs.go
Original file line number Diff line number Diff line change
Expand Up @@ -225,14 +225,15 @@ func (msg MsgChannelCloseInit) ValidateBasic() error {
// NewMsgChannelCloseConfirm creates a new MsgChannelCloseConfirm instance
func NewMsgChannelCloseConfirm(
portID, channelID string, proofInit []byte, proofHeight clienttypes.Height,
signer string,
signer string, counterpartyUpgradeSequence uint64,
) *MsgChannelCloseConfirm {
return &MsgChannelCloseConfirm{
PortId: portID,
ChannelId: channelID,
ProofInit: proofInit,
ProofHeight: proofHeight,
Signer: signer,
PortId: portID,
ChannelId: channelID,
ProofInit: proofInit,
ProofHeight: proofHeight,
Signer: signer,
CounterpartyUpgradeSequence: counterpartyUpgradeSequence,
}
}

Expand Down Expand Up @@ -320,14 +321,16 @@ func NewMsgTimeoutOnClose(
packet Packet, nextSequenceRecv uint64,
proofUnreceived, proofClose []byte,
proofHeight clienttypes.Height, signer string,
counterpartyUpgradeSequence uint64,
) *MsgTimeoutOnClose {
return &MsgTimeoutOnClose{
Packet: packet,
NextSequenceRecv: nextSequenceRecv,
ProofUnreceived: proofUnreceived,
ProofClose: proofClose,
ProofHeight: proofHeight,
Signer: signer,
Packet: packet,
NextSequenceRecv: nextSequenceRecv,
ProofUnreceived: proofUnreceived,
ProofClose: proofClose,
ProofHeight: proofHeight,
Signer: signer,
CounterpartyUpgradeSequence: counterpartyUpgradeSequence,
}
}

Expand Down
43 changes: 23 additions & 20 deletions modules/core/04-channel/types/msgs_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,11 @@ import (

const (
// valid constants used for testing
portid = "testportid"
chanid = "channel-0"
cpportid = "testcpport"
cpchanid = "testcpchannel"
portid = "testportid"
chanid = "channel-0"
cpportid = "testcpport"
cpchanid = "testcpchannel"
counterpartyUpgradeSequence = 0

version = "1.0"

Expand Down Expand Up @@ -350,14 +351,15 @@ func (suite *TypesTestSuite) TestMsgChannelCloseConfirmValidateBasic() {
msg *types.MsgChannelCloseConfirm
expPass bool
}{
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
{"", types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr), true},
{"too short port id", types.NewMsgChannelCloseConfirm(invalidShortPort, chanid, suite.proof, height, addr), false},
{"too long port id", types.NewMsgChannelCloseConfirm(invalidLongPort, chanid, suite.proof, height, addr), false},
{"port id contains non-alpha", types.NewMsgChannelCloseConfirm(invalidPort, chanid, suite.proof, height, addr), false},
{"too short channel id", types.NewMsgChannelCloseConfirm(portid, invalidShortChannel, suite.proof, height, addr), false},
{"too long channel id", types.NewMsgChannelCloseConfirm(portid, invalidLongChannel, suite.proof, height, addr), false},
{"channel id contains non-alpha", types.NewMsgChannelCloseConfirm(portid, invalidChannel, suite.proof, height, addr), false},
{"empty proof", types.NewMsgChannelCloseConfirm(portid, chanid, emptyProof, height, addr), false},
{"success", types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr, 0), true},
{"success, positive counterparty upgrade sequence", types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr, 1), true},
{"too short port id", types.NewMsgChannelCloseConfirm(invalidShortPort, chanid, suite.proof, height, addr, 0), false},
{"too long port id", types.NewMsgChannelCloseConfirm(invalidLongPort, chanid, suite.proof, height, addr, 0), false},
{"port id contains non-alpha", types.NewMsgChannelCloseConfirm(invalidPort, chanid, suite.proof, height, addr, 0), false},
{"too short channel id", types.NewMsgChannelCloseConfirm(portid, invalidShortChannel, suite.proof, height, addr, 0), false},
{"too long channel id", types.NewMsgChannelCloseConfirm(portid, invalidLongChannel, suite.proof, height, addr, 0), false},
{"channel id contains non-alpha", types.NewMsgChannelCloseConfirm(portid, invalidChannel, suite.proof, height, addr, 0), false},
{"empty proof", types.NewMsgChannelCloseConfirm(portid, chanid, emptyProof, height, addr, 0), false},
}

for _, tc := range testCases {
Expand All @@ -378,7 +380,7 @@ func (suite *TypesTestSuite) TestMsgChannelCloseConfirmValidateBasic() {
func (suite *TypesTestSuite) TestMsgChannelCloseConfirmGetSigners() {
expSigner, err := sdk.AccAddressFromBech32(addr)
suite.Require().NoError(err)
msg := types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr)
msg := types.NewMsgChannelCloseConfirm(portid, chanid, suite.proof, height, addr, counterpartyUpgradeSequence)

encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{})
signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg)
Expand Down Expand Up @@ -472,12 +474,13 @@ func (suite *TypesTestSuite) TestMsgTimeoutOnCloseValidateBasic() {
msg *types.MsgTimeoutOnClose
expPass bool
}{
{"success", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr), true},
{"seq 0", types.NewMsgTimeoutOnClose(packet, 0, suite.proof, suite.proof, height, addr), false},
{"signer address is empty", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, emptyAddr), false},
{"empty proof", types.NewMsgTimeoutOnClose(packet, 1, emptyProof, suite.proof, height, addr), false},
{"empty proof close", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, emptyProof, height, addr), false},
{"invalid packet", types.NewMsgTimeoutOnClose(invalidPacket, 1, suite.proof, suite.proof, height, addr), false},
{"success", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr, 0), true},
DimitrisJim marked this conversation as resolved.
Show resolved Hide resolved
{"success, positive counterparty upgrade sequence", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr, 1), true},
{"seq 0", types.NewMsgTimeoutOnClose(packet, 0, suite.proof, suite.proof, height, addr, 0), false},
{"signer address is empty", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, emptyAddr, 0), false},
{"empty proof", types.NewMsgTimeoutOnClose(packet, 1, emptyProof, suite.proof, height, addr, 0), false},
{"empty proof close", types.NewMsgTimeoutOnClose(packet, 1, suite.proof, emptyProof, height, addr, 0), false},
{"invalid packet", types.NewMsgTimeoutOnClose(invalidPacket, 1, suite.proof, suite.proof, height, addr, 0), false},
}

for _, tc := range testCases {
Expand All @@ -498,7 +501,7 @@ func (suite *TypesTestSuite) TestMsgTimeoutOnCloseValidateBasic() {
func (suite *TypesTestSuite) TestMsgTimeoutOnCloseGetSigners() {
expSigner, err := sdk.AccAddressFromBech32(addr)
suite.Require().NoError(err)
msg := types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr)
msg := types.NewMsgTimeoutOnClose(packet, 1, suite.proof, suite.proof, height, addr, counterpartyUpgradeSequence)

encodingCfg := moduletestutil.MakeTestEncodingConfig(ibc.AppModuleBasic{})
signers, _, err := encodingCfg.Codec.GetMsgV1Signers(msg)
Expand Down
Loading
Loading