github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/core/04-channel/keeper/handshake_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"fmt"
     5  
     6  	capabilitytypes "github.com/fibonacci-chain/fbc/libs/cosmos-sdk/x/capability/types"
     7  
     8  	clienttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/02-client/types"
     9  	connectiontypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/03-connection/types"
    10  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/04-channel/types"
    11  	host "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/24-host"
    12  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/exported"
    13  
    14  	// capabilitytypes "github.com/cosmos/cosmos-sdk/x/capability/types"
    15  	ibctesting "github.com/fibonacci-chain/fbc/libs/ibc-go/testing"
    16  )
    17  
    18  type testCase = struct {
    19  	msg      string
    20  	malleate func()
    21  	expPass  bool
    22  }
    23  
    24  // TestChanOpenInit tests the OpenInit handshake call for channels. It uses message passing
    25  // to enter into the appropriate state and then calls ChanOpenInit directly. The channel is
    26  // being created on chainA. The port capability must be created on chainA before ChanOpenInit
    27  // can succeed.
    28  func (suite *KeeperTestSuite) TestChanOpenInit() {
    29  	var (
    30  		path     *ibctesting.Path
    31  		features []string
    32  		portCap  *capabilitytypes.Capability
    33  	)
    34  
    35  	testCases := []testCase{
    36  		{"success", func() {
    37  			suite.coordinator.SetupConnections(path)
    38  			features = []string{"ORDER_ORDERED", "ORDER_UNORDERED"}
    39  			suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
    40  			portCap = suite.chainA.GetPortCapability(ibctesting.MockPort)
    41  		}, true},
    42  		{"channel already exists", func() {
    43  			suite.coordinator.Setup(path)
    44  		}, false},
    45  		{"connection doesn't exist", func() {
    46  			// any non-empty values
    47  			path.EndpointA.ConnectionID = "connection-0"
    48  			path.EndpointB.ConnectionID = "connection-0"
    49  		}, false},
    50  		{"capability is incorrect", func() {
    51  			suite.coordinator.SetupConnections(path)
    52  			features = []string{"ORDER_ORDERED", "ORDER_UNORDERED"}
    53  			portCap = capabilitytypes.NewCapability(3)
    54  		}, false},
    55  		{"connection version not negotiated", func() {
    56  			suite.coordinator.SetupConnections(path)
    57  
    58  			// modify connA versions
    59  			conn := path.EndpointA.GetConnection()
    60  
    61  			version := connectiontypes.NewVersion("2", []string{"ORDER_ORDERED", "ORDER_UNORDERED"})
    62  			conn.Versions = append(conn.Versions, version)
    63  
    64  			suite.chainA.App().GetIBCKeeper().ConnectionKeeper.SetConnection(
    65  				suite.chainA.GetContext(),
    66  				path.EndpointA.ConnectionID, conn,
    67  			)
    68  			features = []string{"ORDER_ORDERED", "ORDER_UNORDERED"}
    69  			suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
    70  			portCap = suite.chainA.GetPortCapability(ibctesting.MockPort)
    71  		}, false},
    72  		{"connection does not support ORDERED channels", func() {
    73  			suite.coordinator.SetupConnections(path)
    74  
    75  			// modify connA versions to only support UNORDERED channels
    76  			conn := path.EndpointA.GetConnection()
    77  
    78  			version := connectiontypes.NewVersion("1", []string{"ORDER_UNORDERED"})
    79  			conn.Versions = []*connectiontypes.Version{version}
    80  
    81  			suite.chainA.App().GetIBCKeeper().ConnectionKeeper.SetConnection(
    82  				suite.chainA.GetContext(),
    83  				path.EndpointA.ConnectionID, conn,
    84  			)
    85  			// NOTE: Opening UNORDERED channels is still expected to pass but ORDERED channels should fail
    86  			features = []string{"ORDER_UNORDERED"}
    87  			suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
    88  			portCap = suite.chainA.GetPortCapability(ibctesting.MockPort)
    89  		}, true},
    90  	}
    91  
    92  	for _, tc := range testCases {
    93  		tc := tc
    94  		suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
    95  			// run test for all types of ordering
    96  			for _, order := range []types.Order{types.UNORDERED, types.ORDERED} {
    97  				suite.SetupTest() // reset
    98  				path = ibctesting.NewPath(suite.chainA, suite.chainB)
    99  				path.EndpointA.ChannelConfig.Order = order
   100  				path.EndpointB.ChannelConfig.Order = order
   101  
   102  				tc.malleate()
   103  
   104  				counterparty := types.NewCounterparty(ibctesting.MockPort, ibctesting.FirstChannelID)
   105  
   106  				channelID, cap, err := suite.chainA.App().GetIBCKeeper().ChannelKeeper.ChanOpenInit(
   107  					suite.chainA.GetContext(), path.EndpointA.ChannelConfig.Order, []string{path.EndpointA.ConnectionID},
   108  					path.EndpointA.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version,
   109  				)
   110  
   111  				// check if order is supported by channel to determine expected behaviour
   112  				orderSupported := false
   113  				for _, f := range features {
   114  					if f == order.String() {
   115  						orderSupported = true
   116  					}
   117  				}
   118  
   119  				// Testcase must have expectedPass = true AND channel order supported before
   120  				// asserting the channel handshake initiation succeeded
   121  				if tc.expPass && orderSupported {
   122  					suite.Require().NoError(err)
   123  					suite.Require().NotNil(cap)
   124  					suite.Require().Equal(types.FormatChannelIdentifier(0), channelID)
   125  
   126  					chanCap, ok := suite.chainA.App().GetScopedIBCKeeper().GetCapability(
   127  						suite.chainA.GetContext(),
   128  						host.ChannelCapabilityPath(path.EndpointA.ChannelConfig.PortID, channelID),
   129  					)
   130  					suite.Require().True(ok, "could not retrieve channel capability after successful ChanOpenInit")
   131  					suite.Require().Equal(chanCap.String(), cap.String(), "channel capability is not correct")
   132  				} else {
   133  					suite.Require().Error(err)
   134  					suite.Require().Nil(cap)
   135  					suite.Require().Equal("", channelID)
   136  				}
   137  			}
   138  		})
   139  	}
   140  }
   141  
   142  // TestChanOpenTry tests the OpenTry handshake call for channels. It uses message passing
   143  // to enter into the appropriate state and then calls ChanOpenTry directly. The channel
   144  // is being created on chainB. The port capability must be created on chainB before
   145  // ChanOpenTry can succeed.
   146  func (suite *KeeperTestSuite) TestChanOpenTry() {
   147  	var (
   148  		path       *ibctesting.Path
   149  		portCap    *capabilitytypes.Capability
   150  		heightDiff uint64
   151  	)
   152  
   153  	testCases := []testCase{
   154  		{"success", func() {
   155  			suite.coordinator.SetupConnections(path)
   156  			path.SetChannelOrdered()
   157  			path.EndpointA.ChanOpenInit()
   158  
   159  			suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
   160  			portCap = suite.chainB.GetPortCapability(ibctesting.MockPort)
   161  		}, true},
   162  		{"connection doesn't exist", func() {
   163  			path.EndpointA.ConnectionID = ibctesting.FirstConnectionID
   164  			path.EndpointB.ConnectionID = ibctesting.FirstConnectionID
   165  
   166  			// pass capability check
   167  			suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
   168  			portCap = suite.chainB.GetPortCapability(ibctesting.MockPort)
   169  		}, false},
   170  		{"connection is not OPEN", func() {
   171  			suite.coordinator.SetupClients(path)
   172  			// pass capability check
   173  			suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
   174  			portCap = suite.chainB.GetPortCapability(ibctesting.MockPort)
   175  
   176  			err := path.EndpointB.ConnOpenInit()
   177  			suite.Require().NoError(err)
   178  		}, false},
   179  		{"consensus state not found", func() {
   180  			suite.coordinator.SetupConnections(path)
   181  			path.SetChannelOrdered()
   182  			path.EndpointA.ChanOpenInit()
   183  
   184  			suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
   185  			portCap = suite.chainB.GetPortCapability(ibctesting.MockPort)
   186  
   187  			heightDiff = 3 // consensus state doesn't exist at this height
   188  		}, false},
   189  		{"channel verification failed", func() {
   190  			// not creating a channel on chainA will result in an invalid proof of existence
   191  			suite.coordinator.SetupConnections(path)
   192  			portCap = suite.chainB.GetPortCapability(ibctesting.MockPort)
   193  		}, false},
   194  		{"port capability not found", func() {
   195  			suite.coordinator.SetupConnections(path)
   196  			path.SetChannelOrdered()
   197  			path.EndpointA.ChanOpenInit()
   198  
   199  			portCap = capabilitytypes.NewCapability(3)
   200  		}, false},
   201  		{"connection version not negotiated", func() {
   202  			suite.coordinator.SetupConnections(path)
   203  			path.SetChannelOrdered()
   204  			path.EndpointA.ChanOpenInit()
   205  
   206  			// modify connB versions
   207  			conn := path.EndpointB.GetConnection()
   208  
   209  			version := connectiontypes.NewVersion("2", []string{"ORDER_ORDERED", "ORDER_UNORDERED"})
   210  			conn.Versions = append(conn.Versions, version)
   211  
   212  			suite.chainB.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(
   213  				suite.chainB.GetContext(),
   214  				path.EndpointB.ConnectionID, conn,
   215  			)
   216  			suite.chainB.CreatePortCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
   217  			portCap = suite.chainB.GetPortCapability(ibctesting.MockPort)
   218  		}, false},
   219  		{"connection does not support ORDERED channels", func() {
   220  			suite.coordinator.SetupConnections(path)
   221  			path.SetChannelOrdered()
   222  			path.EndpointA.ChanOpenInit()
   223  
   224  			// modify connA versions to only support UNORDERED channels
   225  			conn := path.EndpointA.GetConnection()
   226  
   227  			version := connectiontypes.NewVersion("1", []string{"ORDER_UNORDERED"})
   228  			conn.Versions = []*connectiontypes.Version{version}
   229  
   230  			suite.chainA.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(
   231  				suite.chainA.GetContext(),
   232  				path.EndpointA.ConnectionID, conn,
   233  			)
   234  			suite.chainA.CreatePortCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, ibctesting.MockPort)
   235  			portCap = suite.chainA.GetPortCapability(ibctesting.MockPort)
   236  		}, false},
   237  	}
   238  
   239  	for _, tc := range testCases {
   240  		tc := tc
   241  		suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
   242  			suite.SetupTest() // reset
   243  			heightDiff = 0    // must be explicitly changed in malleate
   244  			path = ibctesting.NewPath(suite.chainA, suite.chainB)
   245  
   246  			tc.malleate()
   247  
   248  			if path.EndpointB.ClientID != "" {
   249  				// ensure client is up to date
   250  				err := path.EndpointB.UpdateClient()
   251  				suite.Require().NoError(err)
   252  			}
   253  
   254  			counterparty := types.NewCounterparty(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)
   255  
   256  			channelKey := host.ChannelKey(counterparty.PortId, counterparty.ChannelId)
   257  			proof, proofHeight := suite.chainA.QueryProof(channelKey)
   258  
   259  			channelID, cap, err := suite.chainB.GetSimApp().GetIBCKeeper().ChannelKeeper.ChanOpenTryV4(
   260  				suite.chainB.GetContext(), types.ORDERED, []string{path.EndpointB.ConnectionID},
   261  				path.EndpointB.ChannelConfig.PortID, portCap, counterparty, path.EndpointA.ChannelConfig.Version,
   262  				proof, malleateHeight(proofHeight, heightDiff),
   263  			)
   264  
   265  			if tc.expPass {
   266  				suite.Require().NoError(err)
   267  				suite.Require().NotNil(cap)
   268  
   269  				chanCap, ok := suite.chainB.GetSimApp().GetScopedIBCKeeper().GetCapability(
   270  					suite.chainB.GetContext(),
   271  					host.ChannelCapabilityPath(path.EndpointB.ChannelConfig.PortID, channelID),
   272  				)
   273  				suite.Require().True(ok, "could not retrieve channel capapbility after successful ChanOpenTry")
   274  				suite.Require().Equal(chanCap.String(), cap.String(), "channel capability is not correct")
   275  			} else {
   276  				suite.Require().Error(err)
   277  			}
   278  		})
   279  	}
   280  }
   281  
   282  // TestChanOpenAck tests the OpenAck handshake call for channels. It uses message passing
   283  // to enter into the appropriate state and then calls ChanOpenAck directly. The handshake
   284  // call is occurring on chainA.
   285  func (suite *KeeperTestSuite) TestChanOpenAck() {
   286  	var (
   287  		path                  *ibctesting.Path
   288  		counterpartyChannelID string
   289  		channelCap            *capabilitytypes.Capability
   290  		heightDiff            uint64
   291  	)
   292  
   293  	testCases := []testCase{
   294  		{"success", func() {
   295  			suite.coordinator.SetupConnections(path)
   296  			path.SetChannelOrdered()
   297  			err := path.EndpointA.ChanOpenInit()
   298  			suite.Require().NoError(err)
   299  
   300  			err = path.EndpointB.ChanOpenTry()
   301  			suite.Require().NoError(err)
   302  
   303  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   304  		}, true},
   305  		{"success with empty stored counterparty channel ID", func() {
   306  			suite.coordinator.SetupConnections(path)
   307  			path.SetChannelOrdered()
   308  
   309  			err := path.EndpointA.ChanOpenInit()
   310  			suite.Require().NoError(err)
   311  
   312  			err = path.EndpointB.ChanOpenTry()
   313  			suite.Require().NoError(err)
   314  
   315  			// set the channel's counterparty channel identifier to empty string
   316  			channel := path.EndpointA.GetChannel()
   317  			channel.Counterparty.ChannelId = ""
   318  
   319  			// use a different channel identifier
   320  			counterpartyChannelID = path.EndpointB.ChannelID
   321  
   322  			suite.chainA.App().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel)
   323  
   324  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   325  		}, true},
   326  		{"channel doesn't exist", func() {}, false},
   327  		{"channel state is not INIT or TRYOPEN", func() {
   328  			// create fully open channels on both chains
   329  			suite.coordinator.Setup(path)
   330  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   331  		}, false},
   332  		{"connection not found", func() {
   333  			suite.coordinator.SetupConnections(path)
   334  			path.SetChannelOrdered()
   335  			err := path.EndpointA.ChanOpenInit()
   336  			suite.Require().NoError(err)
   337  
   338  			err = path.EndpointB.ChanOpenTry()
   339  			suite.Require().NoError(err)
   340  
   341  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   342  
   343  			// set the channel's connection hops to wrong connection ID
   344  			channel := path.EndpointA.GetChannel()
   345  			channel.ConnectionHops[0] = "doesnotexist"
   346  			suite.chainA.App().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel)
   347  			suite.coordinator.CommitBlock(suite.chainA)
   348  			suite.coordinator.CommitBlock(suite.chainB)
   349  		}, false},
   350  		{"connection is not OPEN", func() {
   351  			suite.coordinator.SetupClients(path)
   352  
   353  			err := path.EndpointA.ConnOpenInit()
   354  			suite.Require().NoError(err)
   355  
   356  			// create channel in init
   357  			path.SetChannelOrdered()
   358  
   359  			err = path.EndpointA.ChanOpenInit()
   360  			suite.Require().NoError(err)
   361  
   362  			suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   363  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   364  		}, false},
   365  		{"consensus state not found", func() {
   366  			suite.coordinator.SetupConnections(path)
   367  			path.SetChannelOrdered()
   368  
   369  			err := path.EndpointA.ChanOpenInit()
   370  			suite.Require().NoError(err)
   371  
   372  			err = path.EndpointB.ChanOpenTry()
   373  			suite.Require().NoError(err)
   374  
   375  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   376  
   377  			heightDiff = 3 // consensus state doesn't exist at this height
   378  		}, false},
   379  		{"invalid counterparty channel identifier", func() {
   380  			suite.coordinator.SetupConnections(path)
   381  			path.SetChannelOrdered()
   382  
   383  			err := path.EndpointA.ChanOpenInit()
   384  			suite.Require().NoError(err)
   385  
   386  			err = path.EndpointB.ChanOpenTry()
   387  			suite.Require().NoError(err)
   388  
   389  			counterpartyChannelID = "otheridentifier"
   390  
   391  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   392  		}, false},
   393  		{"channel verification failed", func() {
   394  			// chainB is INIT, chainA in TRYOPEN
   395  			suite.coordinator.SetupConnections(path)
   396  			path.SetChannelOrdered()
   397  
   398  			err := path.EndpointB.ChanOpenInit()
   399  			suite.Require().NoError(err)
   400  
   401  			err = path.EndpointA.ChanOpenTry()
   402  			suite.Require().NoError(err)
   403  
   404  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   405  		}, false},
   406  		{"channel capability not found", func() {
   407  			suite.coordinator.SetupConnections(path)
   408  			path.SetChannelOrdered()
   409  			err := path.EndpointA.ChanOpenInit()
   410  			suite.Require().NoError(err)
   411  
   412  			path.EndpointB.ChanOpenTry()
   413  
   414  			channelCap = capabilitytypes.NewCapability(6)
   415  		}, false},
   416  	}
   417  
   418  	for _, tc := range testCases {
   419  		tc := tc
   420  		suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
   421  			suite.SetupTest()          // reset
   422  			counterpartyChannelID = "" // must be explicitly changed in malleate
   423  			heightDiff = 0             // must be explicitly changed
   424  			path = ibctesting.NewPath(suite.chainA, suite.chainB)
   425  
   426  			tc.malleate()
   427  
   428  			if counterpartyChannelID == "" {
   429  				counterpartyChannelID = ibctesting.FirstChannelID
   430  			}
   431  
   432  			if path.EndpointA.ClientID != "" {
   433  				// ensure client is up to date
   434  				err := path.EndpointA.UpdateClient()
   435  				suite.Require().NoError(err)
   436  			}
   437  
   438  			channelKey := host.ChannelKey(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)
   439  			proof, proofHeight := suite.chainB.QueryProof(channelKey)
   440  
   441  			err := suite.chainA.App().GetIBCKeeper().ChannelKeeper.ChanOpenAck(
   442  				suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channelCap, path.EndpointB.ChannelConfig.Version, counterpartyChannelID,
   443  				proof, malleateHeight(proofHeight, heightDiff),
   444  			)
   445  
   446  			if tc.expPass {
   447  				suite.Require().NoError(err)
   448  			} else {
   449  				suite.Require().Error(err)
   450  			}
   451  		})
   452  	}
   453  }
   454  
   455  // TestChanOpenConfirm tests the OpenAck handshake call for channels. It uses message passing
   456  // to enter into the appropriate state and then calls ChanOpenConfirm directly. The handshake
   457  // call is occurring on chainB.
   458  func (suite *KeeperTestSuite) TestChanOpenConfirm() {
   459  	var (
   460  		path       *ibctesting.Path
   461  		channelCap *capabilitytypes.Capability
   462  		heightDiff uint64
   463  	)
   464  	testCases := []testCase{
   465  		{"success", func() {
   466  			suite.coordinator.SetupConnections(path)
   467  			path.SetChannelOrdered()
   468  
   469  			err := path.EndpointA.ChanOpenInit()
   470  			suite.Require().NoError(err)
   471  
   472  			err = path.EndpointB.ChanOpenTry()
   473  			suite.Require().NoError(err)
   474  
   475  			err = path.EndpointA.ChanOpenAck()
   476  			suite.Require().NoError(err)
   477  
   478  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   479  		}, true},
   480  		{"channel doesn't exist", func() {}, false},
   481  		{"channel state is not TRYOPEN", func() {
   482  			// create fully open channels on both cahins
   483  			suite.coordinator.Setup(path)
   484  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   485  		}, false},
   486  		{"connection not found", func() {
   487  			suite.coordinator.SetupConnections(path)
   488  			path.SetChannelOrdered()
   489  
   490  			err := path.EndpointA.ChanOpenInit()
   491  			suite.Require().NoError(err)
   492  
   493  			err = path.EndpointB.ChanOpenTry()
   494  			suite.Require().NoError(err)
   495  
   496  			err = path.EndpointA.ChanOpenAck()
   497  			suite.Require().NoError(err)
   498  
   499  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   500  
   501  			// set the channel's connection hops to wrong connection ID
   502  			channel := path.EndpointB.GetChannel()
   503  			channel.ConnectionHops[0] = "doesnotexist"
   504  			suite.chainB.App().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel)
   505  			suite.coordinator.CommitBlock(suite.chainB)
   506  		}, false},
   507  		{"connection is not OPEN", func() {
   508  			suite.coordinator.SetupClients(path)
   509  
   510  			err := path.EndpointB.ConnOpenInit()
   511  			suite.Require().NoError(err)
   512  
   513  			suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)
   514  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)
   515  		}, false},
   516  		{"consensus state not found", func() {
   517  			suite.coordinator.SetupConnections(path)
   518  			path.SetChannelOrdered()
   519  
   520  			err := path.EndpointA.ChanOpenInit()
   521  			suite.Require().NoError(err)
   522  
   523  			err = path.EndpointB.ChanOpenTry()
   524  			suite.Require().NoError(err)
   525  
   526  			err = path.EndpointA.ChanOpenAck()
   527  			suite.Require().NoError(err)
   528  
   529  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   530  
   531  			heightDiff = 3
   532  		}, false},
   533  		{"channel verification failed", func() {
   534  			// chainA is INIT, chainB in TRYOPEN
   535  			suite.coordinator.SetupConnections(path)
   536  			path.SetChannelOrdered()
   537  
   538  			err := path.EndpointA.ChanOpenInit()
   539  			suite.Require().NoError(err)
   540  
   541  			err = path.EndpointB.ChanOpenTry()
   542  			suite.Require().NoError(err)
   543  
   544  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   545  		}, false},
   546  		{"channel capability not found", func() {
   547  			suite.coordinator.SetupConnections(path)
   548  			path.SetChannelOrdered()
   549  
   550  			err := path.EndpointA.ChanOpenInit()
   551  			suite.Require().NoError(err)
   552  
   553  			err = path.EndpointB.ChanOpenTry()
   554  			suite.Require().NoError(err)
   555  
   556  			err = path.EndpointA.ChanOpenAck()
   557  			suite.Require().NoError(err)
   558  
   559  			channelCap = capabilitytypes.NewCapability(6)
   560  		}, false},
   561  	}
   562  
   563  	for _, tc := range testCases {
   564  		tc := tc
   565  		suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
   566  			suite.SetupTest() // reset
   567  			heightDiff = 0    // must be explicitly changed
   568  			path = ibctesting.NewPath(suite.chainA, suite.chainB)
   569  
   570  			tc.malleate()
   571  
   572  			if path.EndpointB.ClientID != "" {
   573  				// ensure client is up to date
   574  				err := path.EndpointB.UpdateClient()
   575  				suite.Require().NoError(err)
   576  
   577  			}
   578  
   579  			channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, ibctesting.FirstChannelID)
   580  			proof, proofHeight := suite.chainA.QueryProof(channelKey)
   581  
   582  			err := suite.chainB.App().GetIBCKeeper().ChannelKeeper.ChanOpenConfirm(
   583  				suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID,
   584  				channelCap, proof, malleateHeight(proofHeight, heightDiff),
   585  			)
   586  
   587  			if tc.expPass {
   588  				suite.Require().NoError(err)
   589  			} else {
   590  				suite.Require().Error(err)
   591  			}
   592  		})
   593  	}
   594  }
   595  
   596  // TestChanCloseInit tests the initial closing of a handshake on chainA by calling
   597  // ChanCloseInit. Both chains will use message passing to setup OPEN channels.
   598  func (suite *KeeperTestSuite) TestChanCloseInit() {
   599  	var (
   600  		path       *ibctesting.Path
   601  		channelCap *capabilitytypes.Capability
   602  	)
   603  
   604  	testCases := []testCase{
   605  		{"success", func() {
   606  			suite.coordinator.Setup(path)
   607  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   608  		}, true},
   609  		{"channel doesn't exist", func() {
   610  			// any non-nil values work for connections
   611  			path.EndpointA.ConnectionID = ibctesting.FirstConnectionID
   612  			path.EndpointB.ConnectionID = ibctesting.FirstConnectionID
   613  
   614  			path.EndpointA.ChannelID = ibctesting.FirstChannelID
   615  			path.EndpointB.ChannelID = ibctesting.FirstChannelID
   616  
   617  			// ensure channel capability check passes
   618  			suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   619  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   620  		}, false},
   621  		{"channel state is CLOSED", func() {
   622  			suite.coordinator.Setup(path)
   623  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   624  
   625  			// close channel
   626  			err := path.EndpointA.SetChannelClosed()
   627  			suite.Require().NoError(err)
   628  		}, false},
   629  		{"connection not found", func() {
   630  			suite.coordinator.Setup(path)
   631  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   632  
   633  			// set the channel's connection hops to wrong connection ID
   634  			channel := path.EndpointA.GetChannel()
   635  			channel.ConnectionHops[0] = "doesnotexist"
   636  			suite.chainA.App().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID, channel)
   637  		}, false},
   638  		{"connection is not OPEN", func() {
   639  			suite.coordinator.SetupClients(path)
   640  
   641  			err := path.EndpointA.ConnOpenInit()
   642  			suite.Require().NoError(err)
   643  
   644  			// create channel in init
   645  			path.SetChannelOrdered()
   646  			err = path.EndpointA.ChanOpenInit()
   647  
   648  			// ensure channel capability check passes
   649  			suite.chainA.CreateChannelCapability(suite.chainA.GetSimApp().ScopedIBCMockKeeper, path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   650  			channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID)
   651  		}, false},
   652  		{"channel capability not found", func() {
   653  			suite.coordinator.Setup(path)
   654  			channelCap = capabilitytypes.NewCapability(3)
   655  		}, false},
   656  	}
   657  
   658  	for _, tc := range testCases {
   659  		tc := tc
   660  		suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
   661  			suite.SetupTest() // reset
   662  			path = ibctesting.NewPath(suite.chainA, suite.chainB)
   663  
   664  			tc.malleate()
   665  
   666  			err := suite.chainA.App().GetIBCKeeper().ChannelKeeper.ChanCloseInit(
   667  				suite.chainA.GetContext(), path.EndpointA.ChannelConfig.PortID, ibctesting.FirstChannelID, channelCap,
   668  			)
   669  
   670  			if tc.expPass {
   671  				suite.Require().NoError(err)
   672  			} else {
   673  				suite.Require().Error(err)
   674  			}
   675  		})
   676  	}
   677  }
   678  
   679  // TestChanCloseConfirm tests the confirming closing channel ends by calling ChanCloseConfirm
   680  // on chainB. Both chains will use message passing to setup OPEN channels. ChanCloseInit is
   681  // bypassed on chainA by setting the channel state in the ChannelKeeper.
   682  func (suite *KeeperTestSuite) TestChanCloseConfirm() {
   683  	var (
   684  		path       *ibctesting.Path
   685  		channelCap *capabilitytypes.Capability
   686  		heightDiff uint64
   687  	)
   688  
   689  	testCases := []testCase{
   690  		{"success", func() {
   691  			suite.coordinator.Setup(path)
   692  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   693  
   694  			err := path.EndpointA.SetChannelClosed()
   695  			suite.Require().NoError(err)
   696  		}, true},
   697  		{"channel doesn't exist", func() {
   698  			// any non-nil values work for connections
   699  			path.EndpointA.ChannelID = ibctesting.FirstChannelID
   700  			path.EndpointB.ChannelID = ibctesting.FirstChannelID
   701  
   702  			// ensure channel capability check passes
   703  			suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)
   704  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID)
   705  		}, false},
   706  		{"channel state is CLOSED", func() {
   707  			suite.coordinator.Setup(path)
   708  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   709  
   710  			err := path.EndpointB.SetChannelClosed()
   711  			suite.Require().NoError(err)
   712  		}, false},
   713  		{"connection not found", func() {
   714  			suite.coordinator.Setup(path)
   715  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   716  
   717  			// set the channel's connection hops to wrong connection ID
   718  			channel := path.EndpointB.GetChannel()
   719  			channel.ConnectionHops[0] = "doesnotexist"
   720  			suite.chainB.App().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID, channel)
   721  		}, false},
   722  		{"connection is not OPEN", func() {
   723  			suite.coordinator.SetupClients(path)
   724  
   725  			err := path.EndpointB.ConnOpenInit()
   726  			suite.Require().NoError(err)
   727  
   728  			// create channel in init
   729  			path.SetChannelOrdered()
   730  			err = path.EndpointB.ChanOpenInit()
   731  			suite.Require().NoError(err)
   732  
   733  			// ensure channel capability check passes
   734  			suite.chainB.CreateChannelCapability(suite.chainB.GetSimApp().ScopedIBCMockKeeper, path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   735  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   736  		}, false},
   737  		{"consensus state not found", func() {
   738  			suite.coordinator.Setup(path)
   739  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   740  
   741  			err := path.EndpointA.SetChannelClosed()
   742  			suite.Require().NoError(err)
   743  
   744  			heightDiff = 3
   745  		}, false},
   746  		{"channel verification failed", func() {
   747  			// channel not closed
   748  			suite.coordinator.Setup(path)
   749  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   750  		}, false},
   751  		{"channel capability not found", func() {
   752  			suite.coordinator.Setup(path)
   753  			channelCap = suite.chainB.GetChannelCapability(path.EndpointB.ChannelConfig.PortID, path.EndpointB.ChannelID)
   754  
   755  			err := path.EndpointA.SetChannelClosed()
   756  			suite.Require().NoError(err)
   757  
   758  			channelCap = capabilitytypes.NewCapability(3)
   759  		}, false},
   760  	}
   761  
   762  	for _, tc := range testCases {
   763  		tc := tc
   764  		suite.Run(fmt.Sprintf("Case %s", tc.msg), func() {
   765  			suite.SetupTest() // reset
   766  			heightDiff = 0    // must explicitly be changed
   767  			path = ibctesting.NewPath(suite.chainA, suite.chainB)
   768  
   769  			tc.malleate()
   770  
   771  			channelKey := host.ChannelKey(path.EndpointA.ChannelConfig.PortID, ibctesting.FirstChannelID)
   772  			proof, proofHeight := suite.chainA.QueryProof(channelKey)
   773  
   774  			err := suite.chainB.App().GetIBCKeeper().ChannelKeeper.ChanCloseConfirm(
   775  				suite.chainB.GetContext(), path.EndpointB.ChannelConfig.PortID, ibctesting.FirstChannelID, channelCap,
   776  				proof, malleateHeight(proofHeight, heightDiff),
   777  			)
   778  
   779  			if tc.expPass {
   780  				suite.Require().NoError(err)
   781  			} else {
   782  				suite.Require().Error(err)
   783  			}
   784  		})
   785  	}
   786  }
   787  
   788  func malleateHeight(height exported.Height, diff uint64) exported.Height {
   789  	return clienttypes.NewHeight(height.GetRevisionNumber(), height.GetRevisionHeight()+diff)
   790  }