From c3bb6967d9f14fd557d0022055fcc25993eb2f11 Mon Sep 17 00:00:00 2001 From: Aditya Date: Fri, 21 Feb 2020 09:25:50 -0800 Subject: [PATCH] Merge PR #5666: Use Tendermint lite client verification --- x/ibc/02-client/keeper/client_test.go | 61 +++- x/ibc/02-client/keeper/keeper_test.go | 16 +- x/ibc/03-connection/keeper/handshake.go | 45 ++- x/ibc/03-connection/keeper/handshake_test.go | 207 +++++------ x/ibc/03-connection/keeper/keeper_test.go | 302 +++++++++------- x/ibc/03-connection/keeper/verify.go | 9 +- x/ibc/03-connection/keeper/verify_test.go | 151 ++++---- x/ibc/04-channel/keeper/handshake_test.go | 255 ++++++------- x/ibc/04-channel/keeper/keeper_test.go | 298 ++++++++++----- x/ibc/04-channel/keeper/packet_test.go | 189 +++++----- x/ibc/04-channel/keeper/timeout_test.go | 112 +++--- x/ibc/07-tendermint/client/cli/tx.go | 24 +- x/ibc/07-tendermint/client/rest/rest.go | 12 +- x/ibc/07-tendermint/client/rest/tx.go | 3 +- x/ibc/07-tendermint/misbehaviour.go | 21 +- x/ibc/07-tendermint/misbehaviour_test.go | 12 +- x/ibc/07-tendermint/tendermint_test.go | 7 +- x/ibc/07-tendermint/types/client_state.go | 42 +-- .../07-tendermint/types/client_state_test.go | 56 +-- x/ibc/07-tendermint/types/errors.go | 2 +- x/ibc/07-tendermint/types/header.go | 39 +- x/ibc/07-tendermint/types/header_test.go | 2 +- x/ibc/07-tendermint/types/msgs.go | 29 +- x/ibc/07-tendermint/types/msgs_test.go | 46 +-- x/ibc/07-tendermint/types/test_utils.go | 5 +- x/ibc/07-tendermint/update.go | 24 +- x/ibc/07-tendermint/update_test.go | 148 +++++++- x/ibc/20-transfer/handler_test.go | 307 +++++++++++----- x/ibc/20-transfer/keeper/keeper_test.go | 277 +++++++++----- x/ibc/20-transfer/keeper/relay_test.go | 55 +-- x/ibc/ante/ante_test.go | 342 ++++++++++++------ x/slashing/keeper/keeper.go | 5 + 32 files changed, 1895 insertions(+), 1208 deletions(-) diff --git a/x/ibc/02-client/keeper/client_test.go b/x/ibc/02-client/keeper/client_test.go index dcd7ef911474..adde9062b7d3 100644 --- a/x/ibc/02-client/keeper/client_test.go +++ b/x/ibc/02-client/keeper/client_test.go @@ -3,6 +3,7 @@ package keeper_test import ( "bytes" "fmt" + "time" tmtypes "github.com/tendermint/tendermint/types" @@ -40,12 +41,12 @@ func (suite *KeeperTestSuite) TestCreateClient() { if tc.expPanic { suite.Require().Panics(func() { - clientState, err := ibctmtypes.Initialize(tc.clientID, tc.clientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(tc.clientID, trustingPeriod, ubdPeriod, suite.header) suite.Require().NoError(err, "err on client state initialization") suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) }, "Msg %d didn't panic: %s", i, tc.msg) } else { - clientState, err := ibctmtypes.Initialize(tc.clientID, tc.clientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(tc.clientID, trustingPeriod, ubdPeriod, suite.header) if tc.expPass { suite.Require().NoError(err, "errored on initialization") suite.Require().NotNil(clientState, "valid test case %d failed: %s", i, tc.msg) @@ -65,38 +66,58 @@ func (suite *KeeperTestSuite) TestCreateClient() { } func (suite *KeeperTestSuite) TestUpdateClient() { + // Must create header creation functions since suite.header gets recreated on each test case + createValidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height+1, suite.header.Time.Add(time.Minute), + suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + } + createInvalidUpdateFn := func(s *KeeperTestSuite) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(testClientID, suite.header.Height-3, suite.header.Time.Add(time.Minute), + suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + } + var updateHeader ibctmtypes.Header + cases := []struct { name string malleate func() error expPass bool }{ {"valid update", func() error { - clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) if err != nil { return err } _, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState) + updateHeader = createValidUpdateFn(suite) return err }, true}, {"client type not found", func() error { + updateHeader = createValidUpdateFn(suite) + return nil }, false}, {"client type and header type mismatch", func() error { suite.keeper.SetClientType(suite.ctx, testClientID, invalidClientType) + updateHeader = createValidUpdateFn(suite) + return nil }, false}, {"client state not found", func() error { suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint) + updateHeader = createValidUpdateFn(suite) + return nil }, false}, {"frozen client", func() error { - clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header} suite.keeper.SetClientState(suite.ctx, clientState) suite.keeper.SetClientType(suite.ctx, testClientID, exported.Tendermint) + updateHeader = createValidUpdateFn(suite) + return nil }, false}, {"invalid header", func() error { - clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) if err != nil { return err } @@ -104,7 +125,8 @@ func (suite *KeeperTestSuite) TestUpdateClient() { if err != nil { return err } - suite.header.Height = suite.ctx.BlockHeight() - 1 + updateHeader = createInvalidUpdateFn(suite) + return nil }, false}, } @@ -117,19 +139,24 @@ func (suite *KeeperTestSuite) TestUpdateClient() { err := tc.malleate() suite.Require().NoError(err) - err = suite.keeper.UpdateClient(suite.ctx, testClientID, suite.header) + suite.ctx = suite.ctx.WithBlockTime(updateHeader.Time.Add(time.Minute)) + + err = suite.keeper.UpdateClient(suite.ctx, testClientID, updateHeader) if tc.expPass { + suite.Require().NoError(err, err) + expConsensusState := ibctmtypes.ConsensusState{ - Timestamp: suite.header.Time, - Root: commitment.NewRoot(suite.header.AppHash), - ValidatorSet: suite.header.ValidatorSet, + Height: uint64(updateHeader.Height), + Timestamp: updateHeader.Time, + Root: commitment.NewRoot(updateHeader.AppHash), + ValidatorSet: updateHeader.ValidatorSet, } clientState, found := suite.keeper.GetClientState(suite.ctx, testClientID) suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) - consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, uint64(suite.header.GetHeight())) + consensusState, found := suite.keeper.GetClientConsensusState(suite.ctx, testClientID, uint64(updateHeader.GetHeight())) suite.Require().True(found, "valid test case %d failed: %s", i, tc.name) tmConsState, ok := consensusState.(ibctmtypes.ConsensusState) suite.Require().True(ok, "consensus state is not a tendermint consensus state") @@ -137,7 +164,7 @@ func (suite *KeeperTestSuite) TestUpdateClient() { tmConsState.ValidatorSet.TotalVotingPower() suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(suite.header.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly on case %s", tc.name) + suite.Require().Equal(updateHeader.GetHeight(), clientState.GetLatestHeight(), "client state height not updated correctly on case %s", tc.name) suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated on case %s", tc.name) } else { suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) @@ -181,7 +208,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.ValidatorSet = bothValSet - clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) if err != nil { return err } @@ -201,7 +228,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { }, func() error { suite.consensusState.ValidatorSet = bothValSet - clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) if err != nil { return err } @@ -226,7 +253,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { ClientID: testClientID, }, func() error { - clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header} suite.keeper.SetClientState(suite.ctx, clientState) return nil }, @@ -241,7 +268,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { ClientID: testClientID, }, func() error { - clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LatestHeight: 10} + clientState := ibctmtypes.ClientState{FrozenHeight: 1, ID: testClientID, LastHeader: suite.header} suite.keeper.SetClientState(suite.ctx, clientState) return nil }, @@ -256,7 +283,7 @@ func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() { ClientID: testClientID, }, func() error { - clientState, err := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, err := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) if err != nil { return err } diff --git a/x/ibc/02-client/keeper/keeper_test.go b/x/ibc/02-client/keeper/keeper_test.go index 1cdf296ed6b1..afeca9bdefa2 100644 --- a/x/ibc/02-client/keeper/keeper_test.go +++ b/x/ibc/02-client/keeper/keeper_test.go @@ -56,7 +56,7 @@ func (suite *KeeperTestSuite) SetupTest() { suite.privVal = tmtypes.NewMockPV() validator := tmtypes.NewValidator(suite.privVal.GetPubKey(), 1) suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - suite.header = ibctmtypes.CreateTestHeader(testClientID, testClientHeight+2, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + suite.header = ibctmtypes.CreateTestHeader(testClientID, testClientHeight, now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) suite.consensusState = ibctmtypes.ConsensusState{ Height: testClientHeight, Timestamp: suite.now, @@ -82,7 +82,7 @@ func TestKeeperTestSuite(t *testing.T) { } func (suite *KeeperTestSuite) TestSetClientState() { - clientState := ibctmtypes.NewClientState(testClientID, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now) + clientState := ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, ibctmtypes.Header{}) suite.keeper.SetClientState(suite.ctx, clientState) retrievedState, found := suite.keeper.GetClientState(suite.ctx, testClientID) @@ -113,9 +113,9 @@ func (suite *KeeperTestSuite) TestSetClientConsensusState() { func (suite KeeperTestSuite) TestGetAllClients() { expClients := []exported.ClientState{ - ibctmtypes.NewClientState(testClientID2, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), - ibctmtypes.NewClientState(testClientID3, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), - ibctmtypes.NewClientState(testClientID, testClientID, trustingPeriod, ubdPeriod, testClientHeight, suite.now), + ibctmtypes.NewClientState(testClientID2, trustingPeriod, ubdPeriod, ibctmtypes.Header{}), + ibctmtypes.NewClientState(testClientID3, trustingPeriod, ubdPeriod, ibctmtypes.Header{}), + ibctmtypes.NewClientState(testClientID, trustingPeriod, ubdPeriod, ibctmtypes.Header{}), } for i := range expClients { @@ -155,7 +155,7 @@ func (suite KeeperTestSuite) TestGetConsensusState() { func (suite KeeperTestSuite) TestConsensusStateHelpers() { // initial setup - clientState, _ := ibctmtypes.Initialize(testClientID, testClientID, suite.consensusState, trustingPeriod, ubdPeriod) + clientState, _ := ibctmtypes.Initialize(testClientID, trustingPeriod, ubdPeriod, suite.header) suite.keeper.SetClientState(suite.ctx, clientState) suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight, suite.consensusState) @@ -166,9 +166,11 @@ func (suite KeeperTestSuite) TestConsensusStateHelpers() { ValidatorSet: suite.valSet, } + header := ibctmtypes.CreateTestHeader(testClientID, testClientHeight+5, suite.header.Time.Add(time.Minute), suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + // mock update functionality + clientState.LastHeader = header suite.keeper.SetClientConsensusState(suite.ctx, testClientID, testClientHeight+5, nextState) - clientState.LatestHeight += 5 suite.keeper.SetClientState(suite.ctx, clientState) latest, ok := suite.keeper.GetLatestClientConsensusState(suite.ctx, testClientID) diff --git a/x/ibc/03-connection/keeper/handshake.go b/x/ibc/03-connection/keeper/handshake.go index 9430d8ee2eb4..497c52455e56 100644 --- a/x/ibc/03-connection/keeper/handshake.go +++ b/x/ibc/03-connection/keeper/handshake.go @@ -49,12 +49,12 @@ func (k Keeper) ConnOpenTry( ctx sdk.Context, connectionID string, // desiredIdentifier counterparty types.Counterparty, // counterpartyConnectionIdentifier, counterpartyPrefix and counterpartyClientIdentifier - clientID string, - counterpartyVersions []string, - proofInit commitment.ProofI, - proofConsensus commitment.ProofI, - proofHeight uint64, - consensusHeight uint64, + clientID string, // clientID of chainA + counterpartyVersions []string, // supported versions of chain A + proofInit commitment.ProofI, // proof that chainA stored connectionEnd in state (on ConnOpenInit) + proofConsensus commitment.ProofI, // proof that chainA stored chainB's consensus state at consensus height + proofHeight uint64, // height at which relayer constructs proof of A storing connectionEnd in state + consensusHeight uint64, // latest height of chain B which chain A has stored in its chain B client ) error { if consensusHeight > uint64(ctx.BlockHeight()) { return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "invalid consensus height") @@ -78,6 +78,7 @@ func (k Keeper) ConnOpenTry( // connection defines chain B's ConnectionEnd connection := types.NewConnectionEnd(exported.UNINITIALIZED, clientID, counterparty, []string{version}) + // Check that ChainA committed expectedConnectionEnd to its state if err := k.VerifyConnectionState( ctx, connection, proofHeight, proofInit, counterparty.ConnectionID, expectedConnection, @@ -85,12 +86,16 @@ func (k Keeper) ConnOpenTry( return err } + // Check that ChainA stored the correct ConsensusState of chainB at the given consensusHeight if err := k.VerifyClientConsensusState( ctx, connection, consensusHeight, proofConsensus, expectedConsensusState, ); err != nil { return err } + // If connection already exists for connectionID, ensure that the existing connection's counterparty + // is chainA and connection is on INIT stage + // Check that existing connection version is on desired version of current handshake previousConnection, found := k.GetConnection(ctx, connectionID) if found && !(previousConnection.State == exported.INIT && previousConnection.Counterparty.ConnectionID == counterparty.ConnectionID && @@ -101,6 +106,7 @@ func (k Keeper) ConnOpenTry( return sdkerrors.Wrap(types.ErrInvalidConnection, "cannot relay connection attempt") } + // Set connection state to TRYOPEN and store in chainB state connection.State = exported.TRYOPEN if err := k.addConnectionToClient(ctx, clientID, connectionID); err != nil { return sdkerrors.Wrap(err, "cannot relay connection attempt") @@ -118,21 +124,24 @@ func (k Keeper) ConnOpenTry( func (k Keeper) ConnOpenAck( ctx sdk.Context, connectionID string, - version string, - proofTry commitment.ProofI, - proofConsensus commitment.ProofI, - proofHeight uint64, - consensusHeight uint64, + version string, // version that ChainB chose in ConnOpenTry + proofTry commitment.ProofI, // proof that connectionEnd was added to ChainB state in ConnOpenTry + proofConsensus commitment.ProofI, // proof that chainB has stored ConsensusState of chainA on its client + proofHeight uint64, // height that relayer constructed proofTry + consensusHeight uint64, // latest height of chainA that chainB has stored on its chainA client ) error { + // Check that chainB client hasn't stored invalid height if consensusHeight > uint64(ctx.BlockHeight()) { return sdkerrors.Wrap(ibctypes.ErrInvalidHeight, "invalid consensus height") } + // Retrieve connection connection, found := k.GetConnection(ctx, connectionID) if !found { return sdkerrors.Wrap(types.ErrConnectionNotFound, "cannot relay ACK of open attempt") } + // Check connection on ChainA is on correct state: INIT if connection.State != exported.INIT { return sdkerrors.Wrapf( types.ErrInvalidConnectionState, @@ -140,12 +149,15 @@ func (k Keeper) ConnOpenAck( ) } + // Check that ChainB's proposed version is one of chainA's accepted versions if types.LatestVersion(connection.Versions) != version { return sdkerrors.Wrapf( ibctypes.ErrInvalidVersion, "connection version does't match provided one (%s ≠ %s)", types.LatestVersion(connection.Versions), version, ) } + + // Retrieve chainA's consensus state at consensusheight expectedConsensusState, found := k.clientKeeper.GetSelfConsensusState(ctx, consensusHeight) if !found { return clienttypes.ErrConsensusStateNotFound @@ -155,6 +167,7 @@ func (k Keeper) ConnOpenAck( expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) expectedConnection := types.NewConnectionEnd(exported.TRYOPEN, connection.Counterparty.ClientID, expectedCounterparty, []string{version}) + // Ensure that ChainB stored expected connectionEnd in its state during ConnOpenTry if err := k.VerifyConnectionState( ctx, connection, proofHeight, proofTry, connection.Counterparty.ConnectionID, expectedConnection, @@ -162,12 +175,14 @@ func (k Keeper) ConnOpenAck( return err } + // Ensure that ChainB has stored the correct ConsensusState for chainA at the consensusHeight if err := k.VerifyClientConsensusState( ctx, connection, consensusHeight, proofConsensus, expectedConsensusState, ); err != nil { return err } + // Update connection state to Open connection.State = exported.OPEN connection.Versions = []string{version} k.SetConnection(ctx, connectionID, connection) @@ -182,14 +197,16 @@ func (k Keeper) ConnOpenAck( func (k Keeper) ConnOpenConfirm( ctx sdk.Context, connectionID string, - proofAck commitment.ProofI, - proofHeight uint64, + proofAck commitment.ProofI, // proof that connection opened on ChainA during ConnOpenAck + proofHeight uint64, // height that relayer constructed proofAck ) error { + // Retrieve connection connection, found := k.GetConnection(ctx, connectionID) if !found { return sdkerrors.Wrap(types.ErrConnectionNotFound, "cannot relay ACK of open attempt") } + // Check that connection state on ChainB is on state: TRYOPEN if connection.State != exported.TRYOPEN { return sdkerrors.Wrapf( types.ErrInvalidConnectionState, @@ -201,6 +218,7 @@ func (k Keeper) ConnOpenConfirm( expectedCounterparty := types.NewCounterparty(connection.ClientID, connectionID, prefix) expectedConnection := types.NewConnectionEnd(exported.OPEN, connection.Counterparty.ClientID, expectedCounterparty, connection.Versions) + // Check that connection on ChainA is open if err := k.VerifyConnectionState( ctx, connection, proofHeight, proofAck, connection.Counterparty.ConnectionID, expectedConnection, @@ -208,6 +226,7 @@ func (k Keeper) ConnOpenConfirm( return err } + // Update ChainB's connection to Open connection.State = exported.OPEN k.SetConnection(ctx, connectionID, connection) k.Logger(ctx).Info(fmt.Sprintf("connection %s state updated: TRYOPEN -> OPEN ", connectionID)) diff --git a/x/ibc/03-connection/keeper/handshake_test.go b/x/ibc/03-connection/keeper/handshake_test.go index 133349195c4e..e3586b13b5b9 100644 --- a/x/ibc/03-connection/keeper/handshake_test.go +++ b/x/ibc/03-connection/keeper/handshake_test.go @@ -12,24 +12,28 @@ import ( // TestConnOpenInit - Chain A (ID #1) initializes (INIT state) a connection with // Chain B (ID #2) which is yet UNINITIALIZED func (suite *KeeperTestSuite) TestConnOpenInit() { - testCases := []testCase{ + testCases := []struct { + msg string + malleate func() + expPass bool + }{ {"success", func() { - suite.createClient(testClientID1) + suite.chainA.CreateClient(suite.chainB) }, true}, {"connection already exists", func() { - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) }, false}, {"couldn't add connection to client", func() {}, false}, } - counterparty := connection.NewCounterparty(testClientID2, testConnectionID2, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty := connection.NewCounterparty(testClientIDA, testConnectionIDB, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) for i, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() - err := suite.app.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.ctx, testConnectionID1, testClientID1, counterparty) + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenInit(suite.chainA.GetContext(), testConnectionIDA, testClientIDB, counterparty) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) @@ -44,7 +48,7 @@ func (suite *KeeperTestSuite) TestConnOpenInit() { // connection on Chain A (ID #1) is INIT func (suite *KeeperTestSuite) TestConnOpenTry() { counterparty := connection.NewCounterparty( - testClientID1, testConnectionID1, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + testClientIDB, testConnectionIDA, suite.chainB.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), ) var ( @@ -59,50 +63,50 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { expPass bool }{ {"success", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) // height = 2 - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - proofHeight = suite.ctx.BlockHeight() - suite.createClient(testClientID2) - consensusHeight = suite.ctx.BlockHeight() // height = 3 - suite.updateClient(testClientID1) - suite.updateClient(testClientID2) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + proofHeight = suite.chainA.Header.Height + suite.chainA.CreateClient(suite.chainB) + consensusHeight = suite.chainB.Header.Height + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) }, true}, {"consensus height > latest height", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { consensusHeight = 100 }, false}, - {"self consensus state not found", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - consensusHeight = 100 - suite.ctx = suite.ctx.WithBlockHeight(100) - }, false}, + // {"self consensus state not found", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { + // consensusHeight = 100 + // suite.ctx = suite.ctx.WithBlockHeight(100) + // }, false}, {"connection state verification invalid", ibctypes.InvalidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) - suite.createClient(testClientID2) - consensusHeight = suite.ctx.BlockHeight() - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.UNINITIALIZED) - suite.updateClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + consensusHeight = suite.chainB.Header.Height + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) }, false}, {"consensus state verification invalid", ibctypes.ValidProof{}, ibctypes.InvalidProof{}, func() { - suite.createClient(testClientID1) // height = 2 - suite.createClient(testClientID2) - consensusHeight = suite.ctx.BlockHeight() - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.updateClient(testClientID1) - suite.updateClient(testClientID2) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + consensusHeight = suite.chainB.Header.Height + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) }, false}, {"invalid previous connection", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) // height = 2 - suite.createClient(testClientID2) - consensusHeight = suite.ctx.BlockHeight() - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.UNINITIALIZED) - suite.updateClient(testClientID1) - suite.updateClient(testClientID2) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + consensusHeight = suite.chainB.Header.Height + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) }, false}, {"couldn't add connection to client", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) // height = 2 - consensusHeight = suite.ctx.BlockHeight() - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.UNINITIALIZED) - suite.updateClient(testClientID1) - suite.updateClient(testClientID2) + suite.chainB.CreateClient(suite.chainA) + consensusHeight = suite.chainB.Header.Height + suite.chainA.createConnection(testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) }, false}, } @@ -113,14 +117,14 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { tc.malleate() - // connectionKey := ibctypes.KeyConnection(testConnectionID1) + // connectionKey := ibctypes.KeyConnection(testConnectionIDA) // proofInit, proofHeight := suite.queryProof(connectionKey) - // consensusKey := ibctypes.KeyConsensusState(testClientID1, uint64(proofHeight)) + // consensusKey := ibctypes.KeyConsensusState(testClientIDA, uint64(proofHeight)) // proofConsensus, consensusHeight := suite.queryProof(consensusKey) - err := suite.app.IBCKeeper.ConnectionKeeper.ConnOpenTry( - suite.ctx, testConnectionID2, counterparty, testClientID2, + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenTry( + suite.chainB.GetContext(), testConnectionIDB, counterparty, testClientIDA, connection.GetCompatibleVersions(), tc.proofInit, tc.proofConsensus, uint64(proofHeight), uint64(consensusHeight), ) @@ -153,53 +157,52 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { expPass bool }{ {"success", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID2) - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.TRYOPEN) - proofHeight = suite.ctx.BlockHeight() - consensusHeight = suite.ctx.BlockHeight() - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.updateClient(testClientID1) - suite.updateClient(testClientID2) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + consensusHeight = suite.chainB.Header.Height + proofHeight = suite.chainA.Header.Height + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.updateClient(suite.chainA) + suite.chainA.updateClient(suite.chainB) }, true}, {"consensus height > latest height", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { consensusHeight = 100 }, false}, {"connection not found", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - consensusHeight = suite.ctx.BlockHeight() + consensusHeight = suite.chainB.Header.Height }, false}, {"connection state is not INIT", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.UNINITIALIZED) - suite.updateClient(testClientID1) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) }, false}, {"incompatible IBC versions", "2.0", ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.updateClient(testClientID1) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.INIT) + suite.chainB.updateClient(suite.chainA) }, false}, {"self consensus state not found", version, ibctypes.ValidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) - suite.createClient(testClientID2) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.TRYOPEN) - suite.updateClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainB.updateClient(suite.chainA) consensusHeight = 100 - suite.ctx = suite.ctx.WithBlockHeight(100) }, false}, {"connection state verification failed", version, ibctypes.InvalidProof{}, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) - consensusHeight = suite.ctx.BlockHeight() - suite.createClient(testClientID2) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.UNINITIALIZED) - suite.updateClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) + consensusHeight = suite.chainB.Header.Height + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) }, false}, {"consensus state verification failed", version, ibctypes.ValidProof{}, ibctypes.InvalidProof{}, func() { - suite.createClient(testClientID1) - consensusHeight = suite.ctx.BlockHeight() - suite.createClient(testClientID2) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.UNINITIALIZED) - suite.updateClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) + consensusHeight = suite.chainB.Header.Height + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) + suite.chainB.updateClient(suite.chainA) }, false}, } @@ -210,14 +213,14 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { tc.malleate() - // connectionKey := ibctypes.KeyConnection(testConnectionID2) + // connectionKey := ibctypes.KeyConnection(testConnectionIDB) // proofTry, proofHeight := suite.queryProof(connectionKey) - // consensusKey := ibctypes.KeyConsensusState(testClientID2, uint64(proofHeight)) + // consensusKey := ibctypes.KeyConsensusState(testClientIDB, uint64(proofHeight)) // proofConsensus, consensusHeight := suite.queryProof(consensusKey) - err := suite.app.IBCKeeper.ConnectionKeeper.ConnOpenAck( - suite.ctx, testConnectionID1, tc.version, tc.proofTry, tc.proofConsensus, + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.ConnOpenAck( + suite.chainA.GetContext(), testConnectionIDA, tc.version, tc.proofTry, tc.proofConsensus, uint64(proofHeight), uint64(consensusHeight), ) @@ -233,33 +236,36 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { // TestConnOpenAck - Chain B (ID #2) calls ConnOpenConfirm to confirm that // Chain A (ID #1) state is now OPEN. func (suite *KeeperTestSuite) TestConnOpenConfirm() { - consensusHeight := int64(0) + // consensusHeight := int64(0) + proofHeight := int64(0) testCases := []testCase{ {"success", func() { - suite.createClient(testClientID1) - suite.createClient(testClientID2) - consensusHeight = suite.ctx.BlockHeight() - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.TRYOPEN) - suite.updateClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + proofHeight = suite.chainB.Header.Height + // consensusHeight = suite.chainA.Header.Height + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainB.updateClient(suite.chainA) }, true}, {"connection not found", func() {}, false}, {"chain B's connection state is not TRYOPEN", func() { - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.UNINITIALIZED) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.UNINITIALIZED) }, false}, {"consensus state not found", func() { - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.TRYOPEN) - suite.updateClient(testClientID2) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainA.updateClient(suite.chainB) }, false}, {"connection state verification failed", func() { - suite.createClient(testClientID1) - suite.createClient(testClientID2) - consensusHeight = suite.ctx.BlockHeight() - suite.updateClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.INIT) - suite.createConnection(testConnectionID2, testConnectionID1, testClientID2, testClientID1, exported.TRYOPEN) - suite.updateClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.CreateClient(suite.chainB) + // consensusHeight = suite.chainA.Header.Height + proofHeight = suite.chainB.Header.Height + suite.chainB.updateClient(suite.chainA) + suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.INIT) + suite.chainB.createConnection(testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, exported.TRYOPEN) + suite.chainA.updateClient(suite.chainA) }, false}, } @@ -270,18 +276,17 @@ func (suite *KeeperTestSuite) TestConnOpenConfirm() { tc.malleate() - // connectionKey := ibctypes.KeyConnection(testConnectionID2) + // connectionKey := ibctypes.KeyConnection(testConnectionIDB) // proofAck, proofHeight := suite.queryProof(connectionKey) - proofHeight := consensusHeight - 1 if tc.expPass { - err := suite.app.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( - suite.ctx, testConnectionID2, ibctypes.ValidProof{}, uint64(proofHeight), + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( + suite.chainB.GetContext(), testConnectionIDB, ibctypes.ValidProof{}, uint64(proofHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.app.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( - suite.ctx, testConnectionID2, ibctypes.InvalidProof{}, uint64(proofHeight), + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.ConnOpenConfirm( + suite.chainB.GetContext(), testConnectionIDB, ibctypes.InvalidProof{}, uint64(proofHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } diff --git a/x/ibc/03-connection/keeper/keeper_test.go b/x/ibc/03-connection/keeper/keeper_test.go index c4e7f63e03d1..36bb2ea36472 100644 --- a/x/ibc/03-connection/keeper/keeper_test.go +++ b/x/ibc/03-connection/keeper/keeper_test.go @@ -2,13 +2,11 @@ package keeper_test import ( "fmt" - "math/rand" "testing" "time" "github.com/stretchr/testify/suite" abci "github.com/tendermint/tendermint/abci/types" - tmtypes "github.com/tendermint/tendermint/types" "github.com/cosmos/cosmos-sdk/codec" @@ -30,11 +28,11 @@ const ( storeKey = ibctypes.StoreKey chainID = "gaia" - testClientID1 = "testclientidone" - testConnectionID1 = "connectionidone" + testClientIDA = "testclientida" // chainid for chainA also chainB's clientID for A's liteclient + testConnectionIDA = "connectionidatob" - testClientID2 = "testclientidtwo" - testConnectionID2 = "connectionidtwo" + testClientIDB = "testclientidb" // chainid for chainB also chainA's clientID for B's liteclient + testConnectionIDB = "connectionidbtoa" testClientID3 = "testclientidthree" testConnectionID3 = "connectionidthree" @@ -43,59 +41,30 @@ const ( ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 ) -var testHeight uint64 - type KeeperTestSuite struct { suite.Suite - cdc *codec.Codec - ctx sdk.Context - app *simapp.SimApp - valSet *tmtypes.ValidatorSet - consensusState clientexported.ConsensusState - header ibctmtypes.Header - now time.Time + cdc *codec.Codec + + // ChainA testing fields + chainA *TestChain + + // ChainB testing fields + chainB *TestChain } func (suite *KeeperTestSuite) SetupTest() { - testHeight = 1 - isCheckTx := false - app := simapp.Setup(isCheckTx) - suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) - now2 := suite.now.Add(time.Duration(time.Hour * 1)) - - suite.cdc = app.Codec() - suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{ChainID: chainID, Height: 1}) - suite.app = app - privVal := tmtypes.NewMockPV() - validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) - suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - suite.header = ibctmtypes.CreateTestHeader(chainID, int64(testHeight), now2, suite.valSet, suite.valSet, []tmtypes.PrivValidator{privVal}) - suite.consensusState = ibctmtypes.ConsensusState{ - Height: testHeight, - Timestamp: suite.now, - Root: commitment.NewRoot(suite.header.AppHash), - ValidatorSet: suite.valSet, - } - - var validators staking.Validators - for i := 1; i < 11; i++ { - privVal := tmtypes.NewMockPV() - pk := privVal.GetPubKey() - val := staking.NewValidator(sdk.ValAddress(pk.Address()), pk, staking.Description{}) - val.Status = sdk.Bonded - val.Tokens = sdk.NewInt(rand.Int63()) - validators = append(validators, val) + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) - app.StakingKeeper.SetHistoricalInfo(suite.ctx, int64(i), staking.NewHistoricalInfo(suite.ctx.BlockHeader(), validators)) - } + suite.cdc = suite.chainA.App.Codec() } // nolint: unused func (suite *KeeperTestSuite) queryProof(key []byte) (commitment.Proof, int64) { - res := suite.app.Query(abci.RequestQuery{ + res := suite.chainA.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", storeKey), - Height: suite.app.LastBlockHeight(), + Height: suite.chainA.App.LastBlockHeight(), Data: key, Prove: true, }) @@ -106,27 +75,121 @@ func (suite *KeeperTestSuite) queryProof(key []byte) (commitment.Proof, int64) { return proof, res.Height } +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} -func (suite *KeeperTestSuite) createClient(clientID string) { - suite.app.Commit() - commitID := suite.app.LastCommitID() - suite.now = suite.now.Add(time.Minute) +func (suite *KeeperTestSuite) TestSetAndGetConnection() { + _, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), testConnectionIDA) + suite.Require().False(existed) - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1, Time: suite.now}}) - suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1) - testHeight++ + counterparty := types.NewCounterparty(testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + expConn := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, types.GetCompatibleVersions()) + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDA, expConn) + conn, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetConnection(suite.chainA.GetContext(), testConnectionIDA) + suite.Require().True(existed) + suite.Require().EqualValues(expConn, conn) +} - consensusState := ibctmtypes.ConsensusState{ - Height: testHeight, - Timestamp: suite.now, - Root: commitment.NewRoot(commitID.Hash), - ValidatorSet: suite.valSet, +func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() { + _, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), testClientIDA) + suite.False(existed) + + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetClientConnectionPaths(suite.chainA.GetContext(), testClientIDB, types.GetCompatibleVersions()) + paths, existed := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.chainA.GetContext(), testClientIDB) + suite.True(existed) + suite.EqualValues(types.GetCompatibleVersions(), paths) +} + +func (suite KeeperTestSuite) TestGetAllConnections() { + // Connection (Counterparty): A(C) -> C(B) -> B(A) + counterparty1 := types.NewCounterparty(testClientIDA, testConnectionIDA, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty2 := types.NewCounterparty(testClientIDB, testConnectionIDB, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty3 := types.NewCounterparty(testClientID3, testConnectionID3, suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + + conn1 := types.NewConnectionEnd(exported.INIT, testClientIDA, counterparty3, types.GetCompatibleVersions()) + conn2 := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty1, types.GetCompatibleVersions()) + conn3 := types.NewConnectionEnd(exported.UNINITIALIZED, testClientID3, counterparty2, types.GetCompatibleVersions()) + + expConnections := []types.ConnectionEnd{conn1, conn2, conn3} + + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDA, expConnections[0]) + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionIDB, expConnections[1]) + suite.chainA.App.IBCKeeper.ConnectionKeeper.SetConnection(suite.chainA.GetContext(), testConnectionID3, expConnections[2]) + + connections := suite.chainA.App.IBCKeeper.ConnectionKeeper.GetAllConnections(suite.chainA.GetContext()) + suite.Require().Len(connections, len(expConnections)) + suite.Require().ElementsMatch(expConnections, connections) +} + +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) - clientState, err := ibctmtypes.Initialize(clientID, clientID, consensusState, trustingPeriod, ubdPeriod) - suite.Require().NoError(err) - _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) - suite.Require().NoError(err) + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil // _, _, err := simapp.SignCheckDeliver( // suite.T(), @@ -140,28 +203,53 @@ func (suite *KeeperTestSuite) createClient(clientID string) { // ) } -func (suite *KeeperTestSuite) updateClient(clientID string) { +func (chain *TestChain) updateClient(client *TestChain) { + // Create chain ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + // always commit when updateClient and begin a new block - suite.app.Commit() - commitID := suite.app.LastCommitID() - suite.now = suite.now.Add(time.Minute) + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1, Time: suite.now}}) - suite.ctx = suite.ctx.WithBlockHeight(suite.ctx.BlockHeight() + 1) - testHeight++ + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) consensusState := ibctmtypes.ConsensusState{ - Height: testHeight, - Timestamp: suite.now, + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, Root: commitment.NewRoot(commitID.Hash), - ValidatorSet: suite.valSet, + ValidatorSet: client.Vals, } - suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState( - suite.ctx, clientID, uint64(suite.app.LastBlockHeight()), consensusState, + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, ) - suite.app.IBCKeeper.ClientKeeper.SetClientState( - suite.ctx, ibctmtypes.NewClientState(clientID, clientID, trustingPeriod, ubdPeriod, uint64(suite.app.LastBlockHeight()), suite.now), + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), ) // _, _, err := simapp.SignCheckDeliver( @@ -177,22 +265,23 @@ func (suite *KeeperTestSuite) updateClient(clientID string) { // suite.Require().NoError(err) } -func (suite *KeeperTestSuite) createConnection( +func (chain *TestChain) createConnection( connID, counterpartyConnID, clientID, counterpartyClientID string, state exported.State, ) types.ConnectionEnd { - counterparty := types.NewCounterparty(counterpartyClientID, counterpartyConnID, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty := types.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) connection := types.ConnectionEnd{ State: state, ClientID: clientID, Counterparty: counterparty, Versions: types.GetCompatibleVersions(), } - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, connID, connection) + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) return connection } -func (suite *KeeperTestSuite) createChannel( +func (chain *TestChain) createChannel( portID, channelID, counterpartyPortID, counterpartyChannelID string, state channelexported.State, order channelexported.Order, connectionID string, ) channeltypes.Channel { @@ -200,53 +289,12 @@ func (suite *KeeperTestSuite) createChannel( channel := channeltypes.NewChannel(state, order, counterparty, []string{connectionID}, "1.0", ) - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, portID, channelID, channel) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) return channel } -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) -} - -func (suite *KeeperTestSuite) TestSetAndGetConnection() { - _, existed := suite.app.IBCKeeper.ConnectionKeeper.GetConnection(suite.ctx, testConnectionID1) - suite.Require().False(existed) - - counterparty := types.NewCounterparty(testClientID1, testConnectionID1, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) - expConn := types.NewConnectionEnd(exported.INIT, testClientID1, counterparty, types.GetCompatibleVersions()) - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnectionID1, expConn) - conn, existed := suite.app.IBCKeeper.ConnectionKeeper.GetConnection(suite.ctx, testConnectionID1) - suite.Require().True(existed) - suite.Require().EqualValues(expConn, conn) -} - -func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() { - _, existed := suite.app.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.ctx, testClientID1) - suite.False(existed) - - suite.app.IBCKeeper.ConnectionKeeper.SetClientConnectionPaths(suite.ctx, testClientID1, types.GetCompatibleVersions()) - paths, existed := suite.app.IBCKeeper.ConnectionKeeper.GetClientConnectionPaths(suite.ctx, testClientID1) - suite.True(existed) - suite.EqualValues(types.GetCompatibleVersions(), paths) -} - -func (suite KeeperTestSuite) TestGetAllConnections() { - // Connection (Counterparty): A(C) -> C(B) -> B(A) - counterparty1 := types.NewCounterparty(testClientID1, testConnectionID1, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) - counterparty2 := types.NewCounterparty(testClientID2, testConnectionID2, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) - counterparty3 := types.NewCounterparty(testClientID3, testConnectionID3, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) - - conn1 := types.NewConnectionEnd(exported.INIT, testClientID1, counterparty3, types.GetCompatibleVersions()) - conn2 := types.NewConnectionEnd(exported.INIT, testClientID2, counterparty1, types.GetCompatibleVersions()) - conn3 := types.NewConnectionEnd(exported.UNINITIALIZED, testClientID3, counterparty2, types.GetCompatibleVersions()) - - expConnections := []types.ConnectionEnd{conn1, conn2, conn3} - - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnectionID1, expConnections[0]) - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnectionID2, expConnections[1]) - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnectionID3, expConnections[2]) - - connections := suite.app.IBCKeeper.ConnectionKeeper.GetAllConnections(suite.ctx) - suite.Require().Len(connections, len(expConnections)) - suite.Require().ElementsMatch(expConnections, connections) +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Vals, chain.Signers) } diff --git a/x/ibc/03-connection/keeper/verify.go b/x/ibc/03-connection/keeper/verify.go index e9264746a1d0..4741cb359c3a 100644 --- a/x/ibc/03-connection/keeper/verify.go +++ b/x/ibc/03-connection/keeper/verify.go @@ -19,9 +19,10 @@ func (k Keeper) VerifyClientConsensusState( proof commitment.ProofI, consensusState clientexported.ConsensusState, ) error { - clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) + clientID := connection.GetClientID() + clientState, found := k.clientKeeper.GetClientState(ctx, clientID) if !found { - return sdkerrors.Wrap(clienttypes.ErrClientNotFound, connection.GetClientID()) + return sdkerrors.Wrap(clienttypes.ErrClientNotFound, clientID) } return clientState.VerifyClientConsensusState( @@ -37,7 +38,7 @@ func (k Keeper) VerifyConnectionState( height uint64, proof commitment.ProofI, connectionID string, - connectionEnd exported.ConnectionI, // oposite connection + connectionEnd exported.ConnectionI, // opposite connection ) error { clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) if !found { @@ -46,7 +47,7 @@ func (k Keeper) VerifyConnectionState( // TODO: move to specific clients; blocked by #5502 consensusState, found := k.clientKeeper.GetClientConsensusState( - ctx, connectionEnd.GetClientID(), height, + ctx, connection.GetClientID(), height, ) if !found { return sdkerrors.Wrapf( diff --git a/x/ibc/03-connection/keeper/verify_test.go b/x/ibc/03-connection/keeper/verify_test.go index 536f3f6ea050..2e5f4f77b6db 100644 --- a/x/ibc/03-connection/keeper/verify_test.go +++ b/x/ibc/03-connection/keeper/verify_test.go @@ -20,12 +20,12 @@ const ( func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { counterparty := types.NewCounterparty( - testClientID2, testConnectionID2, - suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), + testClientIDA, testConnectionIDA, + suite.chainA.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), ) connection1 := types.NewConnectionEnd( - exported.UNINITIALIZED, testClientID1, counterparty, + exported.UNINITIALIZED, testClientIDB, counterparty, types.GetCompatibleVersions(), ) @@ -37,29 +37,30 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { expPass bool }{ {"verification success", connection1, ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) + suite.chainA.CreateClient(suite.chainB) }, true}, {"client state not found", connection1, ibctypes.ValidProof{}, func() {}, false}, {"verification failed", connection1, ibctypes.InvalidProof{}, func() { - suite.createClient(testClientID2) + suite.chainA.CreateClient(suite.chainA) }, false}, } + // Create Client of chain B on Chain App + // Check that we can verify B's consensus state on chain A for i, tc := range cases { tc := tc suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() - - proofHeight := suite.ctx.BlockHeight() + proofHeight := uint64(suite.chainB.Header.Height) // TODO: remove mocked types and uncomment - // consensusKey := ibctypes.KeyConsensusState(testClientID1, uint64(suite.app.LastBlockHeight())) + // consensusKey := ibctypes.KeyConsensusState(testClientIDA, uint64(suite.app.LastBlockHeight())) // proof, proofHeight := suite.queryProof(consensusKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyClientConsensusState( - suite.ctx, tc.connection, uint64(proofHeight), tc.proof, suite.consensusState, + err := suite.chainA.App.IBCKeeper.ConnectionKeeper.VerifyClientConsensusState( + suite.chainA.GetContext(), tc.connection, proofHeight, tc.proof, suite.chainB.Header.ConsensusState(), ) if tc.expPass { @@ -72,7 +73,7 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { } func (suite *KeeperTestSuite) TestVerifyConnectionState() { - // connectionKey := ibctypes.KeyConnection(testConnectionID1) + // connectionKey := ibctypes.KeyConnection(testConnectionIDA) cases := []struct { msg string proof commitment.ProofI @@ -80,32 +81,43 @@ func (suite *KeeperTestSuite) TestVerifyConnectionState() { expPass bool }{ {"verification success", ibctypes.ValidProof{}, func() { - suite.createClient(testClientID1) - suite.createClient(testClientID2) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) }, true}, {"client state not found", ibctypes.ValidProof{}, func() {}, false}, {"verification failed", ibctypes.InvalidProof{}, func() { - suite.createClient(testClientID1) - suite.createClient(testClientID2) + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) }, false}, } + // Chains A and B create clients for each other + // A creates connectionEnd for chain B and stores it in state + // Check that B can verify connection is stored after some updates for i, tc := range cases { tc := tc suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() - connection := suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - suite.updateClient(testClientID1) - counterparty := types.NewCounterparty(testClientID1, testConnectionID1, commitment.NewPrefix([]byte("ibc"))) - expectedConnection := types.NewConnectionEnd(exported.INIT, testClientID2, counterparty, []string{"1.0.0"}) - suite.updateClient(testClientID1) - proofHeight := uint64(3) + + // create and store connection on chain A + expectedConnection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, exported.OPEN) + + // // create expected connection + // expectedConnection := types.NewConnectionEnd(exported.INIT, testClientIDB, counterparty, []string{"1.0.0"}) + + // perform a couple updates of chain A on chain B + suite.chainB.updateClient(suite.chainA) + suite.chainB.updateClient(suite.chainA) + proofHeight := uint64(suite.chainA.Header.Height) // proof, proofHeight := suite.queryProof(connectionKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyConnectionState( - suite.ctx, connection, proofHeight, tc.proof, testConnectionID1, expectedConnection, + counterparty := types.NewCounterparty(testClientIDB, testConnectionIDA, commitment.NewPrefix([]byte("ibc"))) + connection := types.NewConnectionEnd(exported.UNINITIALIZED, testClientIDA, counterparty, []string{"1.0.0"}) + // Ensure chain B can verify connection exists in chain A + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyConnectionState( + suite.chainB.GetContext(), connection, proofHeight, tc.proof, testConnectionIDA, expectedConnection, ) if tc.expPass { @@ -127,33 +139,39 @@ func (suite *KeeperTestSuite) TestVerifyChannelState() { expPass bool }{ {"verification success", ibctypes.ValidProof{}, 2, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, true}, {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, {"consensus state not found", ibctypes.ValidProof{}, 100, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, false}, {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.createClient(testClientID2) + suite.chainB.CreateClient(suite.chainB) }, false}, } + // Chain A creates channel for chain B and stores in its state + // Check that chainB can verify channel is stored in chain A for i, tc := range cases { tc := tc suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() - connection := suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - channel := suite.createChannel( + // Create and store channel on chain A + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + channel := suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, - channelexported.OPEN, channelexported.ORDERED, testConnectionID1, + channelexported.OPEN, channelexported.ORDERED, testConnectionIDA, ) - suite.updateClient(testClientID1) + // Update chainA client on chainB + suite.chainB.updateClient(suite.chainA) + + // Check that Chain B can verify channel is stored on chainA // proof, proofHeight := suite.queryProof(channelKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyChannelState( - suite.ctx, connection, tc.proofHeight, tc.proof, testPort1, + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyChannelState( + suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, testChannel1, channel, ) @@ -178,30 +196,37 @@ func (suite *KeeperTestSuite) TestVerifyPacketCommitment() { expPass bool }{ {"verification success", ibctypes.ValidProof{}, 2, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, true}, {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, {"consensus state not found", ibctypes.ValidProof{}, 100, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, false}, {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.createClient(testClientID2) + suite.chainB.CreateClient(suite.chainA) }, false}, } + // ChainA sets packet commitment on channel with chainB in its state + // Check that ChainB can verify the PacketCommitment for i, tc := range cases { tc := tc suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset tc.malleate() - connection := suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 1, commitmentBz) - suite.updateClient(testClientID1) + // Set PacketCommitment on chainA + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainA.GetContext(), testPort1, testChannel1, 1, commitmentBz) + + // Update ChainA client on chainB + suite.chainB.updateClient(suite.chainA) + + // Check that ChainB can verify PacketCommitment stored in chainA // proof, proofHeight := suite.queryProof(commitmentKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyPacketCommitment( - suite.ctx, connection, tc.proofHeight, tc.proof, testPort1, + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketCommitment( + suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, testChannel1, 1, commitmentBz, ) @@ -226,14 +251,14 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { expPass bool }{ {"verification success", ibctypes.ValidProof{}, 2, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, true}, {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, {"consensus state not found", ibctypes.ValidProof{}, 100, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, false}, {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.createClient(testClientID2) + suite.chainB.CreateClient(suite.chainB) }, false}, } @@ -243,13 +268,13 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgement() { suite.SetupTest() // reset tc.malleate() - connection := suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.ctx, testPort1, testChannel1, 1, ack) - suite.updateClient(testClientID1) + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.chainA.GetContext(), testPort1, testChannel1, 1, ack) + suite.chainB.updateClient(suite.chainA) // proof, proofHeight := suite.queryProof(packetAckKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgement( - suite.ctx, connection, tc.proofHeight, tc.proof, testPort1, + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgement( + suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, testChannel1, 1, ack, ) @@ -273,14 +298,14 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() { expPass bool }{ {"verification success", ibctypes.ValidProof{}, 2, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, true}, {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, {"consensus state not found", ibctypes.ValidProof{}, 100, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, false}, {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.createClient(testClientID2) + suite.chainB.CreateClient(suite.chainB) }, false}, } @@ -290,13 +315,13 @@ func (suite *KeeperTestSuite) TestVerifyPacketAcknowledgementAbsence() { suite.SetupTest() // reset tc.malleate() - connection := suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - suite.updateClient(testClientID1) + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainB.updateClient(suite.chainA) // proof, proofHeight := suite.queryProof(packetAckKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgementAbsence( - suite.ctx, connection, tc.proofHeight, tc.proof, testPort1, + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyPacketAcknowledgementAbsence( + suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, testChannel1, 1, ) @@ -320,14 +345,14 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { expPass bool }{ {"verification success", ibctypes.ValidProof{}, 2, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, true}, {"client state not found", ibctypes.ValidProof{}, 2, func() {}, false}, {"consensus state not found", ibctypes.ValidProof{}, 100, func() { - suite.createClient(testClientID1) + suite.chainB.CreateClient(suite.chainA) }, false}, {"verification failed", ibctypes.InvalidProof{}, 2, func() { - suite.createClient(testClientID2) + suite.chainB.CreateClient(suite.chainB) }, false}, } @@ -337,13 +362,13 @@ func (suite *KeeperTestSuite) TestVerifyNextSequenceRecv() { suite.SetupTest() // reset tc.malleate() - connection := suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, exported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort1, testChannel1, 1) - suite.updateClient(testClientID1) + connection := suite.chainA.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, exported.OPEN) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort1, testChannel1, 1) + suite.chainB.updateClient(suite.chainA) // proof, proofHeight := suite.queryProof(nextSeqRcvKey) - err := suite.app.IBCKeeper.ConnectionKeeper.VerifyNextSequenceRecv( - suite.ctx, connection, tc.proofHeight, tc.proof, testPort1, + err := suite.chainB.App.IBCKeeper.ConnectionKeeper.VerifyNextSequenceRecv( + suite.chainB.GetContext(), connection, tc.proofHeight, tc.proof, testPort1, testChannel1, 1, ) diff --git a/x/ibc/04-channel/keeper/handshake_test.go b/x/ibc/04-channel/keeper/handshake_test.go index 59c42ca40d9f..2b5257b8e61b 100644 --- a/x/ibc/04-channel/keeper/handshake_test.go +++ b/x/ibc/04-channel/keeper/handshake_test.go @@ -13,21 +13,21 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { testCases := []testCase{ {"success", func() { - suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, connectionexported.INIT, ) }, true}, {"channel already exists", func() { - suite.createChannel( + suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.INIT, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"connection doesn't exist", func() {}, false}, {"connection is UNINITIALIZED", func() { - suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDB, testClientIDA, connectionexported.UNINITIALIZED, ) }, false}, @@ -38,8 +38,8 @@ func (suite *KeeperTestSuite) TestChanOpenInit() { suite.SetupTest() // reset tc.malleate() - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenInit( - suite.ctx, exported.ORDERED, []string{testConnectionID1}, + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenInit( + suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDA}, testPort1, testChannel1, counterparty, testChannelVersion, ) @@ -57,35 +57,35 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { testCases := []testCase{ {"success", func() { - suite.createClient(testClientID2) - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + suite.chainA.CreateClient(suite.chainB) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) }, true}, {"previous channel with invalid state", func() { - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.UNINITIALIZED, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"connection doesn't exist", func() {}, false}, {"connection is not OPEN", func() { - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.INIT, ) }, false}, {"consensus state not found", func() { - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) }, false}, {"channel verification failed", func() { - suite.createClient(testClientID2) - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + suite.chainA.CreateClient(suite.chainB) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) }, false}, @@ -97,18 +97,20 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { tc.malleate() + proofHeight := suite.chainB.Header.Height + if tc.expPass { - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenTry( - suite.ctx, exported.ORDERED, []string{testConnectionID2}, + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenTry( + suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDB}, testPort2, testChannel2, counterparty, testChannelVersion, testChannelVersion, - validProof{}, uint64(testHeight), + validProof{}, uint64(proofHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenTry( - suite.ctx, exported.ORDERED, []string{testConnectionID2}, + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenTry( + suite.chainA.GetContext(), exported.ORDERED, []string{testConnectionIDB}, testPort2, testChannel2, counterparty, testChannelVersion, testChannelVersion, - invalidProof{}, uint64(testHeight), + invalidProof{}, uint64(proofHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -119,58 +121,58 @@ func (suite *KeeperTestSuite) TestChanOpenTry() { func (suite *KeeperTestSuite) TestChanOpenAck() { testCases := []testCase{ {"success", func() { - suite.createClient(testClientID1) - _ = suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is not INIT or TRYOPEN", func() { - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.UNINITIALIZED, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"connection not found", func() { - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"connection is not OPEN", func() { - _ = suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.TRYOPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"consensus state not found", func() { - _ = suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"channel verification failed", func() { - suite.createClient(testClientID1) - _ = suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.TRYOPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, } @@ -181,16 +183,17 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { tc.malleate() + proofHeight := suite.chainA.Header.Height if tc.expPass { - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenAck( - suite.ctx, testPort1, testChannel1, testChannelVersion, - validProof{}, uint64(testHeight), + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenAck( + suite.chainB.GetContext(), testPort1, testChannel1, testChannelVersion, + validProof{}, uint64(proofHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenAck( - suite.ctx, testPort1, testChannel1, testChannelVersion, - invalidProof{}, uint64(testHeight), + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanOpenAck( + suite.chainB.GetContext(), testPort1, testChannel1, testChannelVersion, + invalidProof{}, uint64(proofHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -201,58 +204,58 @@ func (suite *KeeperTestSuite) TestChanOpenAck() { func (suite *KeeperTestSuite) TestChanOpenConfirm() { testCases := []testCase{ {"success", func() { - suite.createClient(testClientID2) - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + suite.chainA.CreateClient(suite.chainB) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is not TRYOPEN", func() { - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.UNINITIALIZED, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"connection not found", func() { - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"connection is not OPEN", func() { - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.TRYOPEN, ) - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"consensus state not found", func() { - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"channel verification failed", func() { - suite.createClient(testClientID2) - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + suite.chainA.CreateClient(suite.chainB) + _ = suite.chainA.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDB, testClientIDA, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.TRYOPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, } @@ -263,16 +266,17 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { tc.malleate() + proofHeight := suite.chainB.Header.Height if tc.expPass { - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenConfirm( - suite.ctx, testPort2, testChannel2, - validProof{}, uint64(testHeight), + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( + suite.chainA.GetContext(), testPort2, testChannel2, + validProof{}, uint64(proofHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.app.IBCKeeper.ChannelKeeper.ChanOpenConfirm( - suite.ctx, testPort2, testChannel2, - invalidProof{}, uint64(testHeight), + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanOpenConfirm( + suite.chainA.GetContext(), testPort2, testChannel2, + invalidProof{}, uint64(proofHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } @@ -283,37 +287,37 @@ func (suite *KeeperTestSuite) TestChanOpenConfirm() { func (suite *KeeperTestSuite) TestChanCloseInit() { testCases := []testCase{ {"success", func() { - suite.createClient(testClientID1) - _ = suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is CLOSED", func() { - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"connection not found", func() { - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"connection is not OPEN", func() { - _ = suite.createConnection( - testConnectionID1, testConnectionID2, testClientID1, testClientID2, + _ = suite.chainA.createConnection( + testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.TRYOPEN, ) - _ = suite.createChannel( + _ = suite.chainA.createChannel( testPort1, testChannel1, testPort2, testChannel2, exported.UNINITIALIZED, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, } @@ -323,8 +327,8 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { suite.SetupTest() // reset tc.malleate() - err := suite.app.IBCKeeper.ChannelKeeper.ChanCloseInit( - suite.ctx, testPort1, testChannel1, + err := suite.chainA.App.IBCKeeper.ChannelKeeper.ChanCloseInit( + suite.chainA.GetContext(), testPort1, testChannel1, ) if tc.expPass { @@ -339,58 +343,58 @@ func (suite *KeeperTestSuite) TestChanCloseInit() { func (suite *KeeperTestSuite) TestChanCloseConfirm() { testCases := []testCase{ {"success", func() { - suite.createClient(testClientID2) - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, true}, {"channel doesn't exist", func() {}, false}, {"channel state is CLOSED", func() { - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"connection not found", func() { - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, - exported.ORDERED, testConnectionID1, + exported.ORDERED, testConnectionIDA, ) }, false}, {"connection is not OPEN", func() { - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, connectionexported.TRYOPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"consensus state not found", func() { - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, {"channel verification failed", func() { - suite.createClient(testClientID2) - _ = suite.createConnection( - testConnectionID2, testConnectionID1, testClientID2, testClientID1, + suite.chainB.CreateClient(suite.chainA) + _ = suite.chainB.createConnection( + testConnectionIDB, testConnectionIDA, testClientIDA, testClientIDB, connectionexported.OPEN, ) - _ = suite.createChannel( + _ = suite.chainB.createChannel( testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, - exported.ORDERED, testConnectionID2, + exported.ORDERED, testConnectionIDB, ) }, false}, } @@ -401,16 +405,17 @@ func (suite *KeeperTestSuite) TestChanCloseConfirm() { tc.malleate() + proofHeight := suite.chainA.Header.Height if tc.expPass { - err := suite.app.IBCKeeper.ChannelKeeper.ChanCloseConfirm( - suite.ctx, testPort2, testChannel2, - validProof{}, uint64(testHeight), + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanCloseConfirm( + suite.chainB.GetContext(), testPort2, testChannel2, + validProof{}, uint64(proofHeight), ) suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) } else { - err := suite.app.IBCKeeper.ChannelKeeper.ChanCloseConfirm( - suite.ctx, testPort2, testChannel2, - invalidProof{}, uint64(testHeight), + err := suite.chainB.App.IBCKeeper.ChannelKeeper.ChanCloseConfirm( + suite.chainB.GetContext(), testPort2, testChannel2, + invalidProof{}, uint64(proofHeight), ) suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg) } diff --git a/x/ibc/04-channel/keeper/keeper_test.go b/x/ibc/04-channel/keeper/keeper_test.go index 688893e1b5da..e3c42527f015 100644 --- a/x/ibc/04-channel/keeper/keeper_test.go +++ b/x/ibc/04-channel/keeper/keeper_test.go @@ -19,6 +19,7 @@ import ( "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + "github.com/cosmos/cosmos-sdk/x/staking" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" @@ -28,11 +29,11 @@ import ( const ( testClientType = clientexported.Tendermint - testClientID1 = "testclientidone" - testConnectionID1 = "connectionidone" + testClientIDA = "testclientida" + testConnectionIDA = "connectionidatob" - testClientID2 = "testclientidtwo" - testConnectionID2 = "connectionidtwo" + testClientIDB = "testclientidb" + testConnectionIDB = "connectionidbtoa" testPort1 = "firstport" testPort2 = "secondport" @@ -54,28 +55,22 @@ const ( type KeeperTestSuite struct { suite.Suite - cdc *codec.Codec - ctx sdk.Context - app *simapp.SimApp - valSet *tmtypes.ValidatorSet + cdc *codec.Codec + + chainA *TestChain + chainB *TestChain } func (suite *KeeperTestSuite) SetupTest() { - isCheckTx := false - app := simapp.Setup(isCheckTx) - - suite.cdc = app.Codec() - suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) - suite.app = app - - privVal := tmtypes.NewMockPV() + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) - validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) - suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + suite.cdc = suite.chainA.App.Codec() } func (suite *KeeperTestSuite) TestSetChannel() { - _, found := suite.app.IBCKeeper.ChannelKeeper.GetChannel(suite.ctx, testPort1, testChannel1) + ctx := suite.chainB.GetContext() + _, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1) suite.False(found) channel := types.Channel{ @@ -85,12 +80,12 @@ func (suite *KeeperTestSuite) TestSetChannel() { PortID: testPort2, ChannelID: testChannel2, }, - ConnectionHops: []string{testConnectionID1}, + ConnectionHops: []string{testConnectionIDA}, Version: testChannelVersion, } - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, testPort1, testChannel1, channel) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, channel) - storedChannel, found := suite.app.IBCKeeper.ChannelKeeper.GetChannel(suite.ctx, testPort1, testChannel1) + storedChannel, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannel(ctx, testPort1, testChannel1) suite.True(found) suite.Equal(channel, storedChannel) } @@ -105,7 +100,7 @@ func (suite KeeperTestSuite) TestGetAllChannels() { State: exported.INIT, Ordering: testChannelOrder, Counterparty: counterparty3, - ConnectionHops: []string{testConnectionID1}, + ConnectionHops: []string{testConnectionIDA}, Version: testChannelVersion, } @@ -113,7 +108,7 @@ func (suite KeeperTestSuite) TestGetAllChannels() { State: exported.INIT, Ordering: testChannelOrder, Counterparty: counterparty1, - ConnectionHops: []string{testConnectionID1}, + ConnectionHops: []string{testConnectionIDA}, Version: testChannelVersion, } @@ -121,76 +116,81 @@ func (suite KeeperTestSuite) TestGetAllChannels() { State: exported.CLOSED, Ordering: testChannelOrder, Counterparty: counterparty2, - ConnectionHops: []string{testConnectionID1}, + ConnectionHops: []string{testConnectionIDA}, Version: testChannelVersion, } expChannels := []types.Channel{channel1, channel2, channel3} - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, testPort1, testChannel1, expChannels[0]) - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, testPort2, testChannel2, expChannels[1]) - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, testPort3, testChannel3, expChannels[2]) + ctx := suite.chainB.GetContext() + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort1, testChannel1, expChannels[0]) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort2, testChannel2, expChannels[1]) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, testPort3, testChannel3, expChannels[2]) - channels := suite.app.IBCKeeper.ChannelKeeper.GetAllChannels(suite.ctx) + channels := suite.chainB.App.IBCKeeper.ChannelKeeper.GetAllChannels(ctx) suite.Require().Len(channels, len(expChannels)) suite.Require().Equal(expChannels, channels) } func (suite *KeeperTestSuite) TestSetChannelCapability() { - _, found := suite.app.IBCKeeper.ChannelKeeper.GetChannelCapability(suite.ctx, testPort1, testChannel1) + ctx := suite.chainB.GetContext() + _, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannelCapability(ctx, testPort1, testChannel1) suite.False(found) channelCap := "test-channel-capability" - suite.app.IBCKeeper.ChannelKeeper.SetChannelCapability(suite.ctx, testPort1, testChannel1, channelCap) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetChannelCapability(ctx, testPort1, testChannel1, channelCap) - storedChannelCap, found := suite.app.IBCKeeper.ChannelKeeper.GetChannelCapability(suite.ctx, testPort1, testChannel1) + storedChannelCap, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetChannelCapability(ctx, testPort1, testChannel1) suite.True(found) suite.Equal(channelCap, storedChannelCap) } func (suite *KeeperTestSuite) TestSetSequence() { - _, found := suite.app.IBCKeeper.ChannelKeeper.GetNextSequenceSend(suite.ctx, testPort1, testChannel1) + ctx := suite.chainB.GetContext() + _, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1) suite.False(found) - _, found = suite.app.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(suite.ctx, testPort1, testChannel1) + _, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceRecv(ctx, testPort1, testChannel1) suite.False(found) nextSeqSend, nextSeqRecv := uint64(10), uint64(10) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, nextSeqSend) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort1, testChannel1, nextSeqRecv) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, testPort1, testChannel1, nextSeqSend) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(ctx, testPort1, testChannel1, nextSeqRecv) - storedNextSeqSend, found := suite.app.IBCKeeper.ChannelKeeper.GetNextSequenceSend(suite.ctx, testPort1, testChannel1) + storedNextSeqSend, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1) suite.True(found) suite.Equal(nextSeqSend, storedNextSeqSend) - storedNextSeqRecv, found := suite.app.IBCKeeper.ChannelKeeper.GetNextSequenceSend(suite.ctx, testPort1, testChannel1) + storedNextSeqRecv, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetNextSequenceSend(ctx, testPort1, testChannel1) suite.True(found) suite.Equal(nextSeqRecv, storedNextSeqRecv) } func (suite *KeeperTestSuite) TestPackageCommitment() { + ctx := suite.chainB.GetContext() seq := uint64(10) - storedCommitment := suite.app.IBCKeeper.ChannelKeeper.GetPacketCommitment(suite.ctx, testPort1, testChannel1, seq) + storedCommitment := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq) suite.Equal([]byte(nil), storedCommitment) commitment := []byte("commitment") - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, seq, commitment) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(ctx, testPort1, testChannel1, seq, commitment) - storedCommitment = suite.app.IBCKeeper.ChannelKeeper.GetPacketCommitment(suite.ctx, testPort1, testChannel1, seq) + storedCommitment = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketCommitment(ctx, testPort1, testChannel1, seq) suite.Equal(commitment, storedCommitment) } func (suite *KeeperTestSuite) TestSetPacketAcknowledgement() { + ctx := suite.chainB.GetContext() seq := uint64(10) - storedAckHash, found := suite.app.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(suite.ctx, testPort1, testChannel1, seq) + storedAckHash, found := suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctx, testPort1, testChannel1, seq) suite.False(found) suite.Nil(storedAckHash) ackHash := []byte("ackhash") - suite.app.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(suite.ctx, testPort1, testChannel1, seq, ackHash) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketAcknowledgement(ctx, testPort1, testChannel1, seq, ackHash) - storedAckHash, found = suite.app.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(suite.ctx, testPort1, testChannel1, seq) + storedAckHash, found = suite.chainB.App.IBCKeeper.ChannelKeeper.GetPacketAcknowledgement(ctx, testPort1, testChannel1, seq) suite.True(found) suite.Equal(ackHash, storedAckHash) } @@ -199,67 +199,189 @@ func TestKeeperTestSuite(t *testing.T) { suite.Run(t, new(KeeperTestSuite)) } -func (suite *KeeperTestSuite) commitNBlocks(n int) { +func commitNBlocks(chain *TestChain, n int) { for i := 0; i < n; i++ { - suite.app.Commit() - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{Height: suite.app.LastBlockHeight()}) + chain.App.Commit() + chain.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: chain.App.LastBlockHeight() + 1}}) } } -func (suite *KeeperTestSuite) createClient(clientID string) { - suite.commitNBlocks(1) +// nolint: unused +func (suite *KeeperTestSuite) queryProof(key []byte) (commitment.Proof, int64) { + res := suite.chainB.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), + Height: suite.chainB.App.LastBlockHeight(), + Data: key, + Prove: true, + }) - commitID := suite.app.LastCommitID() - consensusState := ibctmtypes.ConsensusState{ - Height: testHeight, - Root: commitment.NewRoot(commitID.Hash), - ValidatorSet: suite.valSet, + proof := commitment.Proof{ + Proof: res.Proof, } - clientState, err := ibctmtypes.Initialize(clientID, clientID, consensusState, trustingPeriod, ubdPeriod) - suite.Require().NoError(err) - _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) - suite.Require().NoError(err) + return proof, res.Height } -// nolint: unused -func (suite *KeeperTestSuite) updateClient() { - // always commit and begin a new block on updateClient - suite.app.Commit() - commitID := suite.app.LastCommitID() +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() - height := suite.app.LastBlockHeight() + 1 - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{Height: suite.app.LastBlockHeight()}) + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) - state := ibctmtypes.ConsensusState{ - Root: commitment.NewRoot(commitID.Hash), + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitment.NewRoot(commitID.Hash), + ValidatorSet: client.Vals, } - suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClientID1, uint64(height-1), state) - csi, _ := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, testClientID1) - cs, _ := csi.(ibctmtypes.ClientState) - cs.LatestHeight = uint64(height - 1) - suite.app.IBCKeeper.ClientKeeper.SetClientState(suite.ctx, cs) + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) } -func (suite *KeeperTestSuite) createConnection( +func (chain *TestChain) createConnection( connID, counterpartyConnID, clientID, counterpartyClientID string, state connectionexported.State, ) connectiontypes.ConnectionEnd { - counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) connection := connectiontypes.ConnectionEnd{ State: state, ClientID: clientID, Counterparty: counterparty, Versions: connectiontypes.GetCompatibleVersions(), } - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, connID, connection) + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) return connection } -func (suite *KeeperTestSuite) createChannel( +func (chain *TestChain) createChannel( portID, channelID, counterpartyPortID, counterpartyChannelID string, state exported.State, order exported.Order, connectionID string, ) types.Channel { @@ -267,24 +389,14 @@ func (suite *KeeperTestSuite) createChannel( channel := types.NewChannel(state, order, counterparty, []string{connectionID}, "1.0", ) - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, portID, channelID, channel) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) return channel } -// nolint: unused -func (suite *KeeperTestSuite) queryProof(key []byte) (commitment.Proof, int64) { - res := suite.app.Query(abci.RequestQuery{ - Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), - Height: suite.app.LastBlockHeight(), - Data: key, - Prove: true, - }) - - proof := commitment.Proof{ - Proof: res.Proof, - } - - return proof, res.Height +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Vals, chain.Signers) } // Mocked types diff --git a/x/ibc/04-channel/keeper/packet_test.go b/x/ibc/04-channel/keeper/packet_test.go index 950bf320776b..e65932a09a82 100644 --- a/x/ibc/04-channel/keeper/packet_test.go +++ b/x/ibc/04-channel/keeper/packet_test.go @@ -6,6 +6,7 @@ import ( connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" + transfertypes "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -17,10 +18,10 @@ func (suite *KeeperTestSuite) TestSendPacket() { testCases := []testCase{ {"success", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 1) }, true}, {"packet basic validation failed", func() { packet = types.NewPacket(mockFailPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) @@ -30,49 +31,49 @@ func (suite *KeeperTestSuite) TestSendPacket() { }, false}, {"channel closed", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) }, false}, {"packet dest port ≠ channel counterparty port", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, testPort3, counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet dest channel ID ≠ channel counterparty channel ID", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), testChannel3) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection is UNINITIALIZED", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.UNINITIALIZED) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.UNINITIALIZED) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"client state not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"timeout height passed", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.commitNBlocks(10) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + commitNBlocks(suite.chainB, 10) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"next sequence send not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"next sequence wrong", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 5) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 5) }, false}, } @@ -82,7 +83,7 @@ func (suite *KeeperTestSuite) TestSendPacket() { suite.SetupTest() // reset tc.malleate() - err := suite.app.IBCKeeper.ChannelKeeper.SendPacket(suite.ctx, packet) + err := suite.chainB.App.IBCKeeper.ChannelKeeper.SendPacket(suite.chainB.GetContext(), packet) if tc.expPass { suite.Require().NoError(err) @@ -100,46 +101,46 @@ func (suite *KeeperTestSuite) TestRecvPacket() { testCases := []testCase{ {"success", func() { - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainB.GetContext(), testPort1, testChannel1, 1) packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.updateClient() + suite.chainB.updateClient(suite.chainA) }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.INIT, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.INIT, exported.ORDERED, testConnectionIDA) }, false}, {"packet source port ≠ channel counterparty port", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort3, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort2, testChannel2, testPort3, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet source channel ID ≠ channel counterparty channel ID", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel3, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not OPEN", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.INIT) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.INIT) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"timeout passed", func() { - suite.commitNBlocks(10) + commitNBlocks(suite.chainB, 10) packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"validation failed", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, } @@ -148,12 +149,14 @@ func (suite *KeeperTestSuite) TestRecvPacket() { suite.SetupTest() // reset tc.malleate() + proofHeight := uint64(suite.chainA.Header.Height) + ctx := suite.chainB.GetContext() var err error if tc.expPass { - packet, err = suite.app.IBCKeeper.ChannelKeeper.RecvPacket(suite.ctx, packet, ibctypes.ValidProof{}, uint64(suite.ctx.BlockHeader().Height)) + packet, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, ibctypes.ValidProof{}, proofHeight) suite.Require().NoError(err) } else { - packet, err = suite.app.IBCKeeper.ChannelKeeper.RecvPacket(suite.ctx, packet, ibctypes.InvalidProof{}, uint64(suite.ctx.BlockHeader().Height)) + packet, err = suite.chainB.App.IBCKeeper.ChannelKeeper.RecvPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight) suite.Require().Error(err) } }) @@ -168,27 +171,27 @@ func (suite *KeeperTestSuite) TestPacketExecuted() { testCases := []testCase{ {"success: UNORDERED", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort2, testChannel2, 1) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, 1) }, true}, {"success: ORDERED", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort2, testChannel2, 1) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, 1) }, true}, {"channel not found", func() {}, false}, {"channel not OPEN", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, exported.ORDERED, testConnectionID1) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.CLOSED, exported.ORDERED, testConnectionIDA) }, false}, {"next sequence receive not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet sequence ≠ next sequence receive", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort2, testChannel2, 5) + suite.chainA.createChannel(testPort2, testChannel2, testPort1, testChannel1, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainA.GetContext(), testPort2, testChannel2, 5) }, false}, } @@ -198,7 +201,7 @@ func (suite *KeeperTestSuite) TestPacketExecuted() { suite.SetupTest() // reset tc.malleate() - err := suite.app.IBCKeeper.ChannelKeeper.PacketExecuted(suite.ctx, packet, mockSuccessPacket{}) + err := suite.chainA.App.IBCKeeper.ChannelKeeper.PacketExecuted(suite.chainA.GetContext(), packet, mockSuccessPacket{}) if tc.expPass { suite.Require().NoError(err) @@ -218,43 +221,43 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { testCases := []testCase{ {"success", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) }, false}, {"packet source port ≠ channel counterparty port", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet source channel ID ≠ channel counterparty channel ID", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not OPEN", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.INIT) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.INIT) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet hasn't been sent", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet ack verification failed", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) }, false}, } @@ -264,12 +267,14 @@ func (suite *KeeperTestSuite) TestAcknowledgePacket() { suite.SetupTest() // reset tc.malleate() + ctx := suite.chainB.GetContext() + proofHeight := uint64(suite.chainA.Header.Height) if tc.expPass { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.AcknowledgePacket(suite.ctx, packet, ack, ibctypes.ValidProof{}, uint64(suite.ctx.BlockHeader().Height)) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, ibctypes.ValidProof{}, proofHeight) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.AcknowledgePacket(suite.ctx, packet, ack, ibctypes.InvalidProof{}, uint64(suite.ctx.BlockHeader().Height)) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.AcknowledgePacket(ctx, packet, ack, ibctypes.InvalidProof{}, proofHeight) suite.Require().Error(err) suite.Require().Nil(packetOut) } @@ -290,57 +295,57 @@ func (suite *KeeperTestSuite) TestCleanupPacket() { {"success", func() { nextSeqRecv = 10 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainB.CreateClient(suite.chainA) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) }, false}, {"packet source port ≠ channel counterparty port", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet source channel ID ≠ channel counterparty channel ID", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not OPEN", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.INIT) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.INIT) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet already received ", func() { packet = types.NewPacket(mockSuccessPacket{}, 10, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet hasn't been sent", func() { nextSeqRecv = 10 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"next seq receive verification failed", func() { nextSeqRecv = 10 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) }, false}, {"packet ack verification failed", func() { nextSeqRecv = 10 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 1, types.CommitPacket(packet.Data)) }, false}, } @@ -350,12 +355,14 @@ func (suite *KeeperTestSuite) TestCleanupPacket() { suite.SetupTest() // reset tc.malleate() + ctx := suite.chainB.GetContext() + proofHeight := uint64(suite.chainA.Header.Height) if tc.expPass { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.CleanupPacket(suite.ctx, packet, ibctypes.ValidProof{}, uint64(suite.ctx.BlockHeader().Height), nextSeqRecv, ack) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, ibctypes.ValidProof{}, proofHeight, nextSeqRecv, ack) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.CleanupPacket(suite.ctx, packet, ibctypes.InvalidProof{}, uint64(suite.ctx.BlockHeader().Height), nextSeqRecv, ack) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.CleanupPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight, nextSeqRecv, ack) suite.Require().Error(err) suite.Require().Nil(packetOut) } diff --git a/x/ibc/04-channel/keeper/timeout_test.go b/x/ibc/04-channel/keeper/timeout_test.go index be60e39f1e75..8991b7a5952f 100644 --- a/x/ibc/04-channel/keeper/timeout_test.go +++ b/x/ibc/04-channel/keeper/timeout_test.go @@ -21,65 +21,65 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { testCases := []testCase{ {"success", func() { nextSeqRecv = 1 - proofHeight = 1 packet = types.NewPacket(newMockTimeoutPacket(1), 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.CreateClient(suite.chainA) + proofHeight = uint64(suite.chainA.Header.Height) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) }, true}, {"channel not found", func() {}, false}, {"channel not open", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.CLOSED, exported.ORDERED, testConnectionIDA) }, false}, {"packet source port ≠ channel counterparty port", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet source channel ID ≠ channel counterparty channel ID", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"timeout", func() { proofHeight = 1 packet = types.NewPacket(mockSuccessPacket{}, 10, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet already received ", func() { nextSeqRecv = 2 proofHeight = 100 packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet hasn't been sent", func() { nextSeqRecv = 1 proofHeight = 100 packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"next seq receive verification failed", func() { nextSeqRecv = 1 - proofHeight = 100 + proofHeight = uint64(suite.chainA.Header.Height) packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) }, false}, {"packet ack verification failed", func() { nextSeqRecv = 1 proofHeight = 100 packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) }, false}, } @@ -88,12 +88,13 @@ func (suite *KeeperTestSuite) TestTimeoutPacket() { suite.SetupTest() // reset tc.malleate() + ctx := suite.chainB.GetContext() if tc.expPass { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.TimeoutPacket(suite.ctx, packet, ibctypes.ValidProof{}, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, ibctypes.ValidProof{}, proofHeight, nextSeqRecv) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.TimeoutPacket(suite.ctx, packet, ibctypes.InvalidProof{}, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutPacket(ctx, packet, ibctypes.InvalidProof{}, proofHeight, nextSeqRecv) suite.Require().Error(err) suite.Require().Nil(packetOut) } @@ -107,7 +108,7 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { testCases := []testCase{ {"success ORDERED", func() { packet = types.NewPacket(newMockTimeoutPacket(3), 1, testPort1, testChannel1, testPort2, testChannel2) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, true}, {"channel not found", func() {}, false}, } @@ -118,7 +119,7 @@ func (suite *KeeperTestSuite) TestTimeoutExecuted() { suite.SetupTest() // reset tc.malleate() - err := suite.app.IBCKeeper.ChannelKeeper.TimeoutExecuted(suite.ctx, packet) + err := suite.chainA.App.IBCKeeper.ChannelKeeper.TimeoutExecuted(suite.chainA.GetContext(), packet) if tc.expPass { suite.Require().NoError(err) @@ -142,55 +143,59 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { testCases := []testCase{ {"success", func() { packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort1, testChannel1, nextSeqRecv) + suite.chainB.CreateClient(suite.chainA) + proofHeight = uint64(suite.chainA.Header.Height) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, true}, {"channel not found", func() {}, false}, {"packet dest port ≠ channel counterparty port", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort3, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet dest channel ID ≠ channel counterparty channel ID", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel3, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"connection not found", func() { packet = types.NewPacket(mockSuccessPacket{}, 1, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"packet hasn't been sent", func() { packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) }, false}, {"channel verification failed", func() { packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort1, testChannel1, nextSeqRecv) + suite.chainB.CreateClient(suite.chainA) + proofHeight = uint64(suite.chainA.Header.Height) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, false}, {"next seq receive verification failed", func() { proofClosed = ibctypes.ValidProof{} packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort1, testChannel1, nextSeqRecv) + suite.chainB.CreateClient(suite.chainA) + proofHeight = uint64(suite.chainA.Header.Height) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.ORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, false}, {"packet ack verification failed", func() { proofClosed = ibctypes.ValidProof{} packet = types.NewPacket(mockSuccessPacket{}, 2, testPort1, testChannel1, counterparty.GetPortID(), counterparty.GetChannelID()) - suite.createClient(testClientID1) - suite.createConnection(testConnectionID1, testConnectionID2, testClientID1, testClientID2, connectionexported.OPEN) - suite.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionID1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, testPort1, testChannel1, nextSeqRecv) + suite.chainB.CreateClient(suite.chainA) + proofHeight = uint64(suite.chainA.Header.Height) + suite.chainB.createConnection(testConnectionIDA, testConnectionIDB, testClientIDA, testClientIDB, connectionexported.OPEN) + suite.chainB.createChannel(testPort1, testChannel1, testPort2, testChannel2, exported.OPEN, exported.UNORDERED, testConnectionIDA) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), testPort1, testChannel1, 2, types.CommitPacket(packet.Data)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.chainB.GetContext(), testPort1, testChannel1, nextSeqRecv) }, false}, } @@ -200,12 +205,13 @@ func (suite *KeeperTestSuite) TestTimeoutOnClose() { suite.SetupTest() // reset tc.malleate() + ctx := suite.chainB.GetContext() if tc.expPass { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.TimeoutOnClose(suite.ctx, packet, ibctypes.ValidProof{}, ibctypes.ValidProof{}, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, ibctypes.ValidProof{}, ibctypes.ValidProof{}, proofHeight, nextSeqRecv) suite.Require().NoError(err) suite.Require().NotNil(packetOut) } else { - packetOut, err := suite.app.IBCKeeper.ChannelKeeper.TimeoutOnClose(suite.ctx, packet, proof, proofClosed, proofHeight, nextSeqRecv) + packetOut, err := suite.chainB.App.IBCKeeper.ChannelKeeper.TimeoutOnClose(ctx, packet, proof, proofClosed, proofHeight, nextSeqRecv) suite.Require().Error(err) suite.Require().Nil(packetOut) } diff --git a/x/ibc/07-tendermint/client/cli/tx.go b/x/ibc/07-tendermint/client/cli/tx.go index 101a266ae125..f5da6ad3b8d2 100644 --- a/x/ibc/07-tendermint/client/cli/tx.go +++ b/x/ibc/07-tendermint/client/cli/tx.go @@ -16,8 +16,8 @@ import ( "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/version" - authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" authclient "github.com/cosmos/cosmos-sdk/x/auth/client" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" "github.com/cosmos/cosmos-sdk/x/evidence" evidenceexported "github.com/cosmos/cosmos-sdk/x/evidence/exported" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" @@ -27,7 +27,7 @@ import ( // in https://github.com/cosmos/ics/tree/master/spec/ics-002-client-semantics#create func GetCmdCreateClient(cdc *codec.Codec) *cobra.Command { cmd := &cobra.Command{ - Use: "create [client-id] [chain-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period]", + Use: "create [client-id] [path/to/consensus_state.json] [trusting_period] [unbonding_period]", Short: "create new client with a consensus state", Long: strings.TrimSpace(fmt.Sprintf(`create new client with a specified identifier and consensus state: @@ -42,34 +42,30 @@ $ %s tx ibc client create [client-id] [path/to/consensus_state.json] [trusting_p cliCtx := context.NewCLIContextWithInput(inBuf).WithCodec(cdc).WithBroadcastMode(flags.BroadcastBlock) clientID := args[0] - chainID := args[1] - var state ibctmtypes.ConsensusState - if err := cdc.UnmarshalJSON([]byte(args[2]), &state); err != nil { + var header ibctmtypes.Header + if err := cdc.UnmarshalJSON([]byte(args[1]), &header); err != nil { // check for file path if JSON input is not provided - contents, err := ioutil.ReadFile(args[2]) + contents, err := ioutil.ReadFile(args[1]) if err != nil { return errors.New("neither JSON input nor path to .json file were provided") } - if err := cdc.UnmarshalJSON(contents, &state); err != nil { - return errors.Wrap(err, "error unmarshalling consensus state file") + if err := cdc.UnmarshalJSON(contents, &header); err != nil { + return errors.Wrap(err, "error unmarshalling consensus header file") } } - trustingPeriod, err := time.ParseDuration(args[3]) + trustingPeriod, err := time.ParseDuration(args[2]) if err != nil { return err } - ubdPeriod, err := time.ParseDuration(args[4]) + ubdPeriod, err := time.ParseDuration(args[3]) if err != nil { return err } - msg := ibctmtypes.NewMsgCreateClient( - clientID, chainID, state, - trustingPeriod, ubdPeriod, cliCtx.GetFromAddress(), - ) + msg := ibctmtypes.NewMsgCreateClient(clientID, header, trustingPeriod, ubdPeriod, cliCtx.GetFromAddress()) if err := msg.ValidateBasic(); err != nil { return err diff --git a/x/ibc/07-tendermint/client/rest/rest.go b/x/ibc/07-tendermint/client/rest/rest.go index c483329e14b2..6a5f50dea877 100644 --- a/x/ibc/07-tendermint/client/rest/rest.go +++ b/x/ibc/07-tendermint/client/rest/rest.go @@ -24,12 +24,12 @@ func RegisterRoutes(cliCtx context.CLIContext, r *mux.Router, queryRoute string) // CreateClientReq defines the properties of a create client request's body. type CreateClientReq struct { - BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` - ClientID string `json:"client_id" yaml:"client_id"` - ChainID string `json:"chain_id" yaml:"chain_id"` - ConsensusState ibctmtypes.ConsensusState `json:"consensus_state" yaml:"consensus_state"` - TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` - UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` + BaseReq rest.BaseReq `json:"base_req" yaml:"base_req"` + ClientID string `json:"client_id" yaml:"client_id"` + ChainID string `json:"chain_id" yaml:"chain_id"` + Header ibctmtypes.Header `json:"consensus_state" yaml:"consensus_state"` + TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` + UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` } // UpdateClientReq defines the properties of a update client request's body. diff --git a/x/ibc/07-tendermint/client/rest/tx.go b/x/ibc/07-tendermint/client/rest/tx.go index 378bedcf9636..d21be2e912bd 100644 --- a/x/ibc/07-tendermint/client/rest/tx.go +++ b/x/ibc/07-tendermint/client/rest/tx.go @@ -52,8 +52,7 @@ func createClientHandlerFn(cliCtx context.CLIContext) http.HandlerFunc { // create the message msg := ibctmtypes.NewMsgCreateClient( req.ClientID, - req.ChainID, - req.ConsensusState, + req.Header, req.TrustingPeriod, req.UnbondingPeriod, fromAddr, ) diff --git a/x/ibc/07-tendermint/misbehaviour.go b/x/ibc/07-tendermint/misbehaviour.go index 990412f78c9d..df6009a14164 100644 --- a/x/ibc/07-tendermint/misbehaviour.go +++ b/x/ibc/07-tendermint/misbehaviour.go @@ -10,6 +10,7 @@ import ( clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + lite "github.com/tendermint/tendermint/lite2" ) // CheckMisbehaviourAndUpdateState determines whether or not two conflicting @@ -78,19 +79,21 @@ func checkMisbehaviour( return errors.New("unbonding period since last consensus state timestamp is over") } - // Evidence is within the trusting period. ValidatorSet must have 2/3 similarity with trusted FromValidatorSet - // check that the validator sets on both headers are valid given the last trusted validatorset - // less than or equal to evidence height - if err := consensusState.ValidatorSet.VerifyFutureCommit( - evidence.Header1.ValidatorSet, evidence.ChainID, - evidence.Header1.Commit.BlockID, evidence.Header1.Height, evidence.Header1.Commit, + // TODO: Evidence must be within trusting period + // Blocked on https://github.com/cosmos/ics/issues/379 + + // - ValidatorSet must have 2/3 similarity with trusted FromValidatorSet + // - ValidatorSets on both headers are valid given the last trusted ValidatorSet + if err := consensusState.ValidatorSet.VerifyCommitTrusting( + evidence.ChainID, evidence.Header1.Commit.BlockID, evidence.Header1.Height, + evidence.Header1.Commit, lite.DefaultTrustLevel, ); err != nil { return fmt.Errorf("validator set in header 1 has too much change from last known validator set: %v", err) } - if err := consensusState.ValidatorSet.VerifyFutureCommit( - evidence.Header2.ValidatorSet, evidence.ChainID, - evidence.Header2.Commit.BlockID, evidence.Header2.Height, evidence.Header2.Commit, + if err := consensusState.ValidatorSet.VerifyCommitTrusting( + evidence.ChainID, evidence.Header2.Commit.BlockID, evidence.Header2.Height, + evidence.Header2.Commit, lite.DefaultTrustLevel, ); err != nil { return fmt.Errorf("validator set in header 2 has too much change from last known validator set: %v", err) } diff --git a/x/ibc/07-tendermint/misbehaviour_test.go b/x/ibc/07-tendermint/misbehaviour_test.go index ca72b5cc78d1..4387af1cf7b1 100644 --- a/x/ibc/07-tendermint/misbehaviour_test.go +++ b/x/ibc/07-tendermint/misbehaviour_test.go @@ -40,7 +40,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }{ { "valid misbehavior evidence", - ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, ibctmtypes.Evidence{ Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, suite.valSet, bothSigners), @@ -53,7 +53,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "valid misbehavior at height greater than last consensusState", - ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, ibctmtypes.Evidence{ Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, suite.valSet, bothSigners), @@ -66,7 +66,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "consensus state's valset hash different from evidence should still pass", - ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ibctmtypes.ConsensusState{Timestamp: suite.now, Height: height - 1, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: suite.valSet}, ibctmtypes.Evidence{ Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, suite.valSet, bothSigners), @@ -79,7 +79,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "first valset has too much change", - ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, ibctmtypes.Evidence{ Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, bothValSet, altSigners), @@ -92,7 +92,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "second valset has too much change", - ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, ibctmtypes.Evidence{ Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, bothValSet, bothValSet, bothSigners), @@ -105,7 +105,7 @@ func (suite *TendermintTestSuite) TestCheckMisbehaviour() { }, { "both valsets have too much change", - ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ibctmtypes.ConsensusState{Timestamp: suite.now, Root: commitment.NewRoot(tmhash.Sum([]byte("app_hash"))), ValidatorSet: bothValSet}, ibctmtypes.Evidence{ Header1: ibctmtypes.CreateTestHeader(chainID, height, suite.now, altValSet, altValSet, altSigners), diff --git a/x/ibc/07-tendermint/tendermint_test.go b/x/ibc/07-tendermint/tendermint_test.go index 9c846c50fb3a..c8c465cdc7f8 100644 --- a/x/ibc/07-tendermint/tendermint_test.go +++ b/x/ibc/07-tendermint/tendermint_test.go @@ -38,13 +38,18 @@ func (suite *TendermintTestSuite) SetupTest() { ibctmtypes.RegisterCodec(suite.cdc) commitment.RegisterCodec(suite.cdc) + // now is the time of the current chain, must be after the updating header + // mocks ctx.BlockTime() suite.now = time.Date(2020, 1, 3, 0, 0, 0, 0, time.UTC) suite.clientTime = time.Date(2020, 1, 1, 0, 0, 0, 0, time.UTC) + // Header time is intended to be time for any new header used for updates suite.headerTime = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) suite.privVal = tmtypes.NewMockPV() val := tmtypes.NewValidator(suite.privVal.GetPubKey(), 10) suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{val}) - suite.header = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) + // Suite header is intended to be header passed in for initial ClientState + // Thus it should have same height and time as ClientState + suite.header = ibctmtypes.CreateTestHeader(chainID, height, suite.clientTime, suite.valSet, suite.valSet, []tmtypes.PrivValidator{suite.privVal}) } func TestTendermintTestSuite(t *testing.T) { diff --git a/x/ibc/07-tendermint/types/client_state.go b/x/ibc/07-tendermint/types/client_state.go index e681d8f7199f..1d343608b078 100644 --- a/x/ibc/07-tendermint/types/client_state.go +++ b/x/ibc/07-tendermint/types/client_state.go @@ -23,61 +23,50 @@ var _ clientexported.ClientState = ClientState{} type ClientState struct { // Client ID ID string `json:"id" yaml:"id"` - // Chain ID for Tendermint chain, not guaranteed to be unique - ChainID string `json:"chain_id" yaml:"chain_id"` // Duration of the period since the LastestTimestamp during which the // submitted headers are valid for upgrade TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` // Duration of the staking unbonding period UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` - // Latest block height - LatestHeight uint64 `json:"latest_height" yaml:"latest_height"` - // Latest block time - LatestTimestamp time.Time `json:"latest_time" yaml:"latest_time"` // Block height when the client was frozen due to a misbehaviour FrozenHeight uint64 `json:"frozen_height" yaml:"frozen_height"` + // Last Header that was stored by client + LastHeader Header } // InitializeFromMsg creates a tendermint client state from a CreateClientMsg func InitializeFromMsg( msg MsgCreateClient, ) (ClientState, error) { - return Initialize(msg.GetClientID(), msg.ChainID, msg.GetConsensusState(), msg.TrustingPeriod, msg.UnbondingPeriod) + return Initialize(msg.GetClientID(), msg.TrustingPeriod, msg.UnbondingPeriod, msg.Header) } // Initialize creates a client state and validates its contents, checking that // the provided consensus state is from the same client type. func Initialize( - id string, chainID string, consensusState clientexported.ConsensusState, trustingPeriod, ubdPeriod time.Duration, + id string, trustingPeriod, ubdPeriod time.Duration, + header Header, ) (ClientState, error) { - tmConsState, ok := consensusState.(ConsensusState) - if !ok { - return ClientState{}, errors.New("consensus state is not from Tendermint") - } - latestHeight := tmConsState.GetHeight() - if trustingPeriod >= ubdPeriod { return ClientState{}, errors.New("trusting period should be < unbonding period") } clientState := NewClientState( - id, chainID, trustingPeriod, ubdPeriod, latestHeight, tmConsState.Timestamp, + id, trustingPeriod, ubdPeriod, header, ) return clientState, nil } // NewClientState creates a new ClientState instance func NewClientState( - id string, chainID string, trustingPeriod, ubdPeriod time.Duration, - latestHeight uint64, latestTimestamp time.Time, + id string, trustingPeriod, ubdPeriod time.Duration, + header Header, ) ClientState { return ClientState{ ID: id, - ChainID: chainID, TrustingPeriod: trustingPeriod, UnbondingPeriod: ubdPeriod, - LatestHeight: latestHeight, - LatestTimestamp: latestTimestamp, + LastHeader: header, FrozenHeight: 0, } } @@ -87,6 +76,11 @@ func (cs ClientState) GetID() string { return cs.ID } +// GetChainID returns the chain-id from the last header +func (cs ClientState) GetChainID() string { + return cs.LastHeader.ChainID +} + // ClientType is tendermint. func (cs ClientState) ClientType() clientexported.ClientType { return clientexported.Tendermint @@ -94,12 +88,12 @@ func (cs ClientState) ClientType() clientexported.ClientType { // GetLatestHeight returns latest block height. func (cs ClientState) GetLatestHeight() uint64 { - return cs.LatestHeight + return uint64(cs.LastHeader.Height) } // GetLatestTimestamp returns latest block time. func (cs ClientState) GetLatestTimestamp() time.Time { - return cs.LatestTimestamp + return cs.LastHeader.Time } // IsFrozen returns true if the frozen height has been set. @@ -323,10 +317,10 @@ func validateVerificationArgs( proof commitment.ProofI, consensusState clientexported.ConsensusState, ) error { - if cs.LatestHeight < height { + if cs.GetLatestHeight() < height { return sdkerrors.Wrap( ibctypes.ErrInvalidHeight, - fmt.Sprintf("client state (%s) height < proof height (%d < %d)", cs.ID, cs.LatestHeight, height), + fmt.Sprintf("client state (%s) height < proof height (%d < %d)", cs.ID, cs.GetLatestHeight(), height), ) } diff --git a/x/ibc/07-tendermint/types/client_state_test.go b/x/ibc/07-tendermint/types/client_state_test.go index cbb4c9c9e301..5f392be235e5 100644 --- a/x/ibc/07-tendermint/types/client_state_test.go +++ b/x/ibc/07-tendermint/types/client_state_test.go @@ -36,7 +36,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -45,7 +45,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -54,7 +54,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -63,7 +63,7 @@ func (suite *TendermintTestSuite) TestVerifyClientConsensusState() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, @@ -114,7 +114,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), connection: conn, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -124,7 +124,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), connection: conn, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -134,7 +134,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, connection: conn, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -144,7 +144,7 @@ func (suite *TendermintTestSuite) TestVerifyConnectionState() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), connection: conn, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -196,7 +196,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), channel: ch, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -206,7 +206,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), channel: ch, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -216,7 +216,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, channel: ch, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -226,7 +226,7 @@ func (suite *TendermintTestSuite) TestVerifyChannelState() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), channel: ch, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -275,7 +275,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), commitment: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -285,7 +285,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), commitment: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -295,7 +295,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, commitment: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -305,7 +305,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketCommitment() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), commitment: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -354,7 +354,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ack: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -364,7 +364,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ack: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -374,7 +374,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, ack: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -384,7 +384,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgement() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), ack: []byte{}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), @@ -432,7 +432,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -441,7 +441,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -450,7 +450,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -459,7 +459,7 @@ func (suite *TendermintTestSuite) TestVerifyPacketAcknowledgementAbsence() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, @@ -506,7 +506,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { // }, { name: "ApplyPrefix failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -515,7 +515,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { }, { name: "latest client height < height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height-1, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -524,7 +524,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { }, { name: "client is frozen", - clientState: ibctmtypes.ClientState{ID: chainID, LatestHeight: height, FrozenHeight: height - 1}, + clientState: ibctmtypes.ClientState{ID: chainID, LastHeader: suite.header, FrozenHeight: height - 1}, consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), }, @@ -533,7 +533,7 @@ func (suite *TendermintTestSuite) TestVerifyNextSeqRecv() { }, { name: "proof verification failed", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.now), + clientState: ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header), consensusState: ibctmtypes.ConsensusState{ Root: commitment.NewRoot(suite.header.AppHash), ValidatorSet: suite.valSet, diff --git a/x/ibc/07-tendermint/types/errors.go b/x/ibc/07-tendermint/types/errors.go index 1f2bcd48174b..58c97a0ebe4b 100644 --- a/x/ibc/07-tendermint/types/errors.go +++ b/x/ibc/07-tendermint/types/errors.go @@ -11,5 +11,5 @@ const ( var ( ErrInvalidTrustingPeriod = sdkerrors.Register(SubModuleName, 1, "invalid trusting period") ErrInvalidUnbondingPeriod = sdkerrors.Register(SubModuleName, 2, "invalid unbonding period") - ErrInvalidChainID = sdkerrors.Register(SubModuleName, 3, "invalid chain ID") + ErrInvalidHeader = sdkerrors.Register(SubModuleName, 3, "invalid header") ) diff --git a/x/ibc/07-tendermint/types/header.go b/x/ibc/07-tendermint/types/header.go index bc426a24ac5b..ddc5e01f458a 100644 --- a/x/ibc/07-tendermint/types/header.go +++ b/x/ibc/07-tendermint/types/header.go @@ -1,6 +1,8 @@ package types import ( + "bytes" + abci "github.com/tendermint/tendermint/abci/types" tmtypes "github.com/tendermint/tendermint/types" @@ -16,6 +18,7 @@ var _ clientexported.Header = Header{} type Header struct { tmtypes.SignedHeader // contains the commitment root ValidatorSet *tmtypes.ValidatorSet `json:"validator_set" yaml:"validator_set"` + NextValidatorSet *tmtypes.ValidatorSet `json:"next_validator_set" yaml:"next_validator_set"` } // ClientType defines that the Header is a Tendermint consensus algorithm @@ -26,6 +29,7 @@ func (h Header) ClientType() clientexported.ClientType { // ConsensusState returns the consensus state associated with the header func (h Header) ConsensusState() ConsensusState { return ConsensusState{ + Height: uint64(h.Height), Timestamp: h.Time, Root: commitment.NewRoot(h.AppHash), ValidatorSet: h.ValidatorSet, @@ -48,35 +52,20 @@ func (h Header) ValidateBasic(chainID string) error { if h.ValidatorSet == nil { return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set is nil") } + if h.NextValidatorSet == nil { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "next validator set is nil") + } + if !bytes.Equal(h.ValidatorsHash, h.ValidatorSet.Hash()) { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "validator set does not match hash") + } + if !bytes.Equal(h.NextValidatorsHash, h.NextValidatorSet.Hash()) { + return sdkerrors.Wrap(clienttypes.ErrInvalidHeader, "next validator set does not match hash") + } return nil } // ToABCIHeader parses the header to an ABCI header type. // NOTE: only for testing use. func (h Header) ToABCIHeader() abci.Header { - return abci.Header{ - Version: abci.Version{ - App: h.Version.App.Uint64(), - Block: h.Version.Block.Uint64(), - }, - ChainID: h.ChainID, - Height: h.Height, - Time: h.Time, - LastBlockId: abci.BlockID{ - Hash: h.LastBlockID.Hash, - PartsHeader: abci.PartSetHeader{ - Total: int32(h.LastBlockID.PartsHeader.Total), - Hash: h.LastBlockID.PartsHeader.Hash, - }, - }, - LastCommitHash: h.LastCommitHash, - DataHash: h.DataHash, - ValidatorsHash: h.ValidatorsHash, - NextValidatorsHash: h.NextValidatorsHash, - ConsensusHash: h.ConsensusHash, - AppHash: h.AppHash, - LastResultsHash: h.LastResultsHash, - EvidenceHash: h.EvidenceHash, - ProposerAddress: h.ProposerAddress, - } + return tmtypes.TM2PB.Header(h.SignedHeader.Header) } diff --git a/x/ibc/07-tendermint/types/header_test.go b/x/ibc/07-tendermint/types/header_test.go index c5c004028a7f..7c1fc7748d29 100644 --- a/x/ibc/07-tendermint/types/header_test.go +++ b/x/ibc/07-tendermint/types/header_test.go @@ -14,7 +14,7 @@ func (suite *TendermintTestSuite) TestHeaderValidateBasic() { }{ {"valid header", suite.header, chainID, true}, {"signed header basic validation failed", suite.header, "chainID", false}, - {"validator set nil", ibctmtypes.Header{suite.header.SignedHeader, nil}, chainID, false}, + {"validator set nil", ibctmtypes.Header{suite.header.SignedHeader, nil, nil}, chainID, false}, } suite.Require().Equal(clientexported.Tendermint, suite.header.ClientType()) diff --git a/x/ibc/07-tendermint/types/msgs.go b/x/ibc/07-tendermint/types/msgs.go index cc065a6ec308..82a27f458a3d 100644 --- a/x/ibc/07-tendermint/types/msgs.go +++ b/x/ibc/07-tendermint/types/msgs.go @@ -1,13 +1,13 @@ package types import ( - "strings" "time" sdk "github.com/cosmos/cosmos-sdk/types" sdkerrors "github.com/cosmos/cosmos-sdk/types/errors" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" + commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" ) @@ -25,8 +25,7 @@ var _ clientexported.MsgUpdateClient = MsgUpdateClient{} // MsgCreateClient defines a message to create an IBC client type MsgCreateClient struct { ClientID string `json:"client_id" yaml:"client_id"` - ChainID string `json:"chain_id" yaml:"chain_id"` - ConsensusState ConsensusState `json:"consensus_state" yaml:"consensus_state"` + Header Header `json:"header" yaml:"header"` TrustingPeriod time.Duration `json:"trusting_period" yaml:"trusting_period"` UnbondingPeriod time.Duration `json:"unbonding_period" yaml:"unbonding_period"` Signer sdk.AccAddress `json:"address" yaml:"address"` @@ -34,13 +33,12 @@ type MsgCreateClient struct { // NewMsgCreateClient creates a new MsgCreateClient instance func NewMsgCreateClient( - id string, chainID string, consensusState ConsensusState, + id string, header Header, trustingPeriod, unbondingPeriod time.Duration, signer sdk.AccAddress, ) MsgCreateClient { return MsgCreateClient{ ClientID: id, - ChainID: chainID, - ConsensusState: consensusState, + Header: header, TrustingPeriod: trustingPeriod, UnbondingPeriod: unbondingPeriod, Signer: signer, @@ -59,12 +57,6 @@ func (msg MsgCreateClient) Type() string { // ValidateBasic implements sdk.Msg func (msg MsgCreateClient) ValidateBasic() error { - if strings.TrimSpace(msg.ChainID) == "" { - return sdkerrors.Wrap(ErrInvalidChainID, "cannot have empty chain-id") - } - if err := msg.ConsensusState.ValidateBasic(); err != nil { - return err - } if msg.TrustingPeriod == 0 { return sdkerrors.Wrap(ErrInvalidTrustingPeriod, "duration cannot be 0") } @@ -74,6 +66,10 @@ func (msg MsgCreateClient) ValidateBasic() error { if msg.Signer.Empty() { return sdkerrors.ErrInvalidAddress } + // ValidateBasic of provided header with self-attested chain-id + if msg.Header.ValidateBasic(msg.Header.ChainID) != nil { + return sdkerrors.Wrap(ErrInvalidHeader, "header failed validatebasic with its own chain-id") + } return host.DefaultClientIdentifierValidator(msg.ClientID) } @@ -99,7 +95,14 @@ func (msg MsgCreateClient) GetClientType() string { // GetConsensusState implements clientexported.MsgCreateClient func (msg MsgCreateClient) GetConsensusState() clientexported.ConsensusState { - return msg.ConsensusState + // Construct initial consensus state from provided Header + root := commitment.NewRoot(msg.Header.AppHash) + return ConsensusState{ + Timestamp: msg.Header.Time, + Root: root, + Height: uint64(msg.Header.Height), + ValidatorSet: msg.Header.ValidatorSet, + } } // MsgUpdateClient defines a message to update an IBC client diff --git a/x/ibc/07-tendermint/types/msgs_test.go b/x/ibc/07-tendermint/types/msgs_test.go index 6ea7eac33828..d00561d99d26 100644 --- a/x/ibc/07-tendermint/types/msgs_test.go +++ b/x/ibc/07-tendermint/types/msgs_test.go @@ -1,61 +1,43 @@ package types_test import ( - "testing" - "time" - - "github.com/stretchr/testify/require" - "github.com/tendermint/tendermint/crypto/secp256k1" - tmtypes "github.com/tendermint/tendermint/types" sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" - commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ) -func TestMsgCreateClientValidateBasic(t *testing.T) { - validator := tmtypes.NewValidator(tmtypes.NewMockPV().GetPubKey(), 1) - valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - - now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) - cs := ibctmtypes.ConsensusState{ - Height: height, - Timestamp: now, - Root: commitment.NewRoot([]byte("root")), - ValidatorSet: valSet, - } +func (suite *TendermintTestSuite) TestMsgCreateClientValidateBasic() { privKey := secp256k1.GenPrivKey() signer := sdk.AccAddress(privKey.PubKey().Address()) - chainID := "gaia" cases := []struct { msg ibctmtypes.MsgCreateClient expPass bool errMsg string }{ - {ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, chainID, cs, trustingPeriod, ubdPeriod, signer), true, "success msg should pass"}, - {ibctmtypes.NewMsgCreateClient("BADCHAIN", chainID, cs, trustingPeriod, ubdPeriod, signer), false, "invalid client id passed"}, - {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, trustingPeriod, ubdPeriod, signer), false, "unregistered client type passed"}, - {ibctmtypes.NewMsgCreateClient("goodchain", chainID, ibctmtypes.ConsensusState{}, trustingPeriod, ubdPeriod, signer), false, "invalid Consensus State in msg passed"}, - {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, 0, ubdPeriod, signer), false, "zero trusting period passed"}, - {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, trustingPeriod, 0, signer), false, "zero unbonding period passed"}, - {ibctmtypes.NewMsgCreateClient("goodchain", chainID, cs, trustingPeriod, ubdPeriod, nil), false, "Empty address passed"}, - {ibctmtypes.NewMsgCreateClient("goodchain", "", cs, trustingPeriod, ubdPeriod, nil), false, "Empty chain ID"}, + {ibctmtypes.NewMsgCreateClient(exported.ClientTypeTendermint, suite.header, trustingPeriod, ubdPeriod, signer), true, "success msg should pass"}, + {ibctmtypes.NewMsgCreateClient("BADCHAIN", suite.header, trustingPeriod, ubdPeriod, signer), false, "invalid client id passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, signer), false, "unregistered client type passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, signer), false, "invalid Consensus State in msg passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, 0, ubdPeriod, signer), false, "zero trusting period passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, 0, signer), false, "zero unbonding period passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, nil), false, "Empty address passed"}, + {ibctmtypes.NewMsgCreateClient("goodchain", suite.header, trustingPeriod, ubdPeriod, nil), false, "Empty chain ID"}, } for i, tc := range cases { err := tc.msg.ValidateBasic() if tc.expPass { - require.NoError(t, err, "Msg %d failed: %v", i, err) + suite.Require().NoError(err, "Msg %d failed: %v", i, err) } else { - require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) } } } -func TestMsgUpdateClient(t *testing.T) { +func (suite *TendermintTestSuite) TestMsgUpdateClient() { privKey := secp256k1.GenPrivKey() signer := sdk.AccAddress(privKey.PubKey().Address()) @@ -72,9 +54,9 @@ func TestMsgUpdateClient(t *testing.T) { for i, tc := range cases { err := tc.msg.ValidateBasic() if tc.expPass { - require.NoError(t, err, "Msg %d failed: %v", i, err) + suite.Require().NoError(err, "Msg %d failed: %v", i, err) } else { - require.Error(t, err, "Invalid Msg %d passed: %s", i, tc.errMsg) + suite.Require().Error(err, "Invalid Msg %d passed: %s", i, tc.errMsg) } } } diff --git a/x/ibc/07-tendermint/types/test_utils.go b/x/ibc/07-tendermint/types/test_utils.go index bd538bc4871b..85642d29a466 100644 --- a/x/ibc/07-tendermint/types/test_utils.go +++ b/x/ibc/07-tendermint/types/test_utils.go @@ -54,7 +54,8 @@ func CreateTestHeader(chainID string, height int64, timestamp time.Time, valSet } return Header{ - SignedHeader: signedHeader, - ValidatorSet: valSet, + SignedHeader: signedHeader, + ValidatorSet: valSet, + NextValidatorSet: nextValSet, } } diff --git a/x/ibc/07-tendermint/update.go b/x/ibc/07-tendermint/update.go index b9bfebca401c..9f21eb7d8ce2 100644 --- a/x/ibc/07-tendermint/update.go +++ b/x/ibc/07-tendermint/update.go @@ -9,6 +9,7 @@ import ( clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types" "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + lite "github.com/tendermint/tendermint/lite2" ) // CheckValidityAndUpdateState checks if the provided header is valid and updates @@ -53,7 +54,7 @@ func checkValidity( clientState types.ClientState, header types.Header, currentTimestamp time.Time, ) error { // assert trusting period has not yet passed - if currentTimestamp.Sub(clientState.LatestTimestamp) >= clientState.TrustingPeriod { + if currentTimestamp.Sub(clientState.GetLatestTimestamp()) >= clientState.TrustingPeriod { return errors.New("trusting period since last client timestamp already passed") } @@ -65,35 +66,32 @@ func checkValidity( ) } - // assert header timestamp is past current timestamp - if header.Time.Unix() <= clientState.LatestTimestamp.Unix() { + // assert header timestamp is past latest clientstate timestamp + if header.Time.Unix() <= clientState.GetLatestTimestamp().Unix() { return sdkerrors.Wrapf( clienttypes.ErrInvalidHeader, "header blocktime ≤ latest client state block time (%s ≤ %s)", - header.Time.String(), clientState.LatestTimestamp.String(), + header.Time.String(), clientState.GetLatestTimestamp().String(), ) } // assert header height is newer than any we know - if header.GetHeight() <= clientState.LatestHeight { + if header.GetHeight() <= clientState.GetLatestHeight() { return sdkerrors.Wrapf( clienttypes.ErrInvalidHeader, - "header height ≤ latest client state height (%d ≤ %d)", header.GetHeight(), clientState.LatestHeight, + "header height ≤ latest client state height (%d ≤ %d)", header.GetHeight(), clientState.GetLatestHeight(), ) } - // basic consistency check - if err := header.ValidateBasic(clientState.ChainID); err != nil { - return err - } - - return header.ValidatorSet.VerifyCommit(header.ChainID, header.Commit.BlockID, header.Height, header.Commit) + return lite.Verify(clientState.GetChainID(), &clientState.LastHeader.SignedHeader, clientState.LastHeader.NextValidatorSet, + &header.SignedHeader, header.ValidatorSet, clientState.TrustingPeriod, currentTimestamp, lite.DefaultTrustLevel) } // update the consensus state from a new header func update(clientState types.ClientState, header types.Header) (types.ClientState, types.ConsensusState) { - clientState.LatestHeight = header.GetHeight() + clientState.LastHeader = header consensusState := types.ConsensusState{ + Height: uint64(header.Height), Timestamp: header.Time, Root: commitment.NewRoot(header.AppHash), ValidatorSet: header.ValidatorSet, diff --git a/x/ibc/07-tendermint/update_test.go b/x/ibc/07-tendermint/update_test.go index 5c465c398335..025c480aa4f0 100644 --- a/x/ibc/07-tendermint/update_test.go +++ b/x/ibc/07-tendermint/update_test.go @@ -1,48 +1,162 @@ package tendermint_test import ( + "bytes" + "time" + tendermint "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" + tmtypes "github.com/tendermint/tendermint/types" ) func (suite *TendermintTestSuite) TestCheckValidity() { - testCases := []struct { - name string + var ( clientState ibctmtypes.ClientState - expPass bool + newHeader ibctmtypes.Header + currentTime time.Time + ) + + // Setup different validators and signers for testing different types of updates + altPrivVal := tmtypes.NewMockPV() + altVal := tmtypes.NewValidator(altPrivVal.GetPubKey(), height) + + // Create bothValSet with both suite validator and altVal. Would be valid update + bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal)) + // Create alternative validator set with only altVal, invalid update (too much change in valSet) + altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal}) + + signers := []tmtypes.PrivValidator{suite.privVal} + // Create signer array and ensure it is in same order as bothValSet + var bothSigners []tmtypes.PrivValidator + if bytes.Compare(altPrivVal.GetPubKey().Address(), suite.privVal.GetPubKey().Address()) == -1 { + bothSigners = []tmtypes.PrivValidator{altPrivVal, suite.privVal} + } else { + bothSigners = []tmtypes.PrivValidator{suite.privVal, altPrivVal} + } + + altSigners := []tmtypes.PrivValidator{altPrivVal} + + testCases := []struct { + name string + setup func() + expPass bool }{ { - name: "successful update", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height, suite.clientTime), - expPass: true, + name: "successful update with next height and same validator set", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, suite.valSet, signers) + currentTime = suite.now + }, + expPass: true, + }, + { + name: "successful update with next height and different validator set", + setup: func() { + oldHeader := ibctmtypes.CreateTestHeader(chainID, height, suite.clientTime, suite.valSet, bothValSet, signers) + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, oldHeader) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, bothValSet, bothValSet, bothSigners) + currentTime = suite.now + }, + expPass: true, + }, + { + name: "successful update with future height and same validator set", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+5, suite.headerTime, bothValSet, bothValSet, bothSigners) + currentTime = suite.now + }, + expPass: true, + }, + { + name: "unsuccessful update with next height: update header mismatches nextValSetHash", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, bothValSet, bothValSet, bothSigners) + currentTime = suite.now + }, + expPass: false, + }, + { + name: "unsuccessful update with future height: too much change in validator set", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+5, suite.headerTime, altValSet, altValSet, altSigners) + currentTime = suite.now + }, + expPass: false, + }, + { + name: "unsuccessful update: trusting period has passed since last client timestamp", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, suite.valSet, signers) + // make current time pass trusting period from last timestamp on clientstate + currentTime = suite.now.Add(ubdPeriod) + }, + expPass: false, + }, + { + name: "unsuccessful update: header timestamp is past current timestamp", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.now.Add(time.Minute), suite.valSet, suite.valSet, signers) + currentTime = suite.now + }, + expPass: false, }, { - name: "header basic validation failed", - clientState: ibctmtypes.NewClientState(chainID, "cosmoshub", trustingPeriod, ubdPeriod, height, suite.clientTime), - expPass: false, + name: "unsuccessful update: header timestamp is not past last client timestamp", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.clientTime, suite.valSet, suite.valSet, signers) + currentTime = suite.now + }, + expPass: false, }, { - name: "header height < latest client height", - clientState: ibctmtypes.NewClientState(chainID, chainID, trustingPeriod, ubdPeriod, height+1, suite.clientTime), - expPass: false, + name: "header basic validation failed", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + newHeader = ibctmtypes.CreateTestHeader(chainID, height+1, suite.headerTime, suite.valSet, suite.valSet, signers) + // cause new header to fail validatebasic by changing commit height to mismatch header height + newHeader.SignedHeader.Commit.Height = height - 1 + currentTime = suite.now + }, + expPass: false, + }, + { + name: "header height < latest client height", + setup: func() { + clientState = ibctmtypes.NewClientState(chainID, trustingPeriod, ubdPeriod, suite.header) + // Make new header at height less than latest client state + newHeader = ibctmtypes.CreateTestHeader(chainID, height-1, suite.headerTime, suite.valSet, suite.valSet, signers) + currentTime = suite.now + }, + + expPass: false, }, } for i, tc := range testCases { tc := tc + // setup test + tc.setup() expectedConsensus := ibctmtypes.ConsensusState{ - Timestamp: suite.headerTime, - Root: commitment.NewRoot(suite.header.AppHash), - ValidatorSet: suite.header.ValidatorSet, + Height: uint64(newHeader.Height), + Timestamp: newHeader.Time, + Root: commitment.NewRoot(newHeader.AppHash), + ValidatorSet: newHeader.ValidatorSet, } - clientState, consensusState, err := tendermint.CheckValidityAndUpdateState(tc.clientState, suite.header, suite.now) + clientState, consensusState, err := tendermint.CheckValidityAndUpdateState(clientState, newHeader, currentTime) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name) - suite.Require().Equal(suite.header.GetHeight(), clientState.GetLatestHeight(), "valid test case %d failed: %s", i, tc.name) + suite.Require().Equal(newHeader.GetHeight(), clientState.GetLatestHeight(), "valid test case %d failed: %s", i, tc.name) suite.Require().Equal(expectedConsensus, consensusState, "valid test case %d failed: %s", i, tc.name) } else { suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name) diff --git a/x/ibc/20-transfer/handler_test.go b/x/ibc/20-transfer/handler_test.go index 64af632ffd03..98f9c8a1acc8 100644 --- a/x/ibc/20-transfer/handler_test.go +++ b/x/ibc/20-transfer/handler_test.go @@ -13,22 +13,25 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" transfer "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/staking" "github.com/cosmos/cosmos-sdk/x/supply" ) // define constants used for testing const ( testChainID = "test-chain-id" - testClient = "test-client" + testClientIDA = "testclientida" + testClientIDB = "testclientidb" testClientType = clientexported.Tendermint testConnection = "testconnection" @@ -57,95 +60,21 @@ var ( type HandlerTestSuite struct { suite.Suite - cdc *codec.Codec - ctx sdk.Context - app *simapp.SimApp - valSet *tmtypes.ValidatorSet -} - -func (suite *HandlerTestSuite) SetupTest() { - isCheckTx := false - app := simapp.Setup(isCheckTx) - - suite.cdc = app.Codec() - suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) - suite.app = app - - privVal := tmtypes.NewMockPV() - - validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) - suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - - suite.createClient() - suite.createConnection(connectionexported.OPEN) -} - -func (suite *HandlerTestSuite) createClient() { - suite.app.Commit() - commitID := suite.app.LastCommitID() - - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - - consensusState := ibctmtypes.ConsensusState{ - Root: commitment.NewRoot(commitID.Hash), - ValidatorSet: suite.valSet, - } - - clientState, err := ibctmtypes.Initialize(testClient, testClient, consensusState, trustingPeriod, ubdPeriod) - suite.NoError(err) - _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) - suite.NoError(err) -} - -func (suite *HandlerTestSuite) updateClient() { - // always commit and begin a new block on updateClient - suite.app.Commit() - commitID := suite.app.LastCommitID() - - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - - state := ibctmtypes.ConsensusState{ - Root: commitment.NewRoot(commitID.Hash), - } + cdc *codec.Codec - suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClient, 1, state) + chainA *TestChain + chainB *TestChain } -func (suite *HandlerTestSuite) createConnection(state connectionexported.State) { - connection := connection.ConnectionEnd{ - State: state, - ClientID: testClient, - Counterparty: connection.Counterparty{ - ClientID: testClient, - ConnectionID: testConnection, - Prefix: suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), - }, - Versions: connection.GetCompatibleVersions(), - } - - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnection, connection) -} - -func (suite *HandlerTestSuite) createChannel( - portID, channnelID, connnnectionID, counterpartyPortID, counterpartyChannelID string, state channelexported.State) { - ch := channel.Channel{ - State: state, - Ordering: testChannelOrder, - Counterparty: channel.Counterparty{ - PortID: counterpartyPortID, - ChannelID: counterpartyChannelID, - }, - ConnectionHops: []string{connnnectionID}, - Version: testChannelVersion, - } +func (suite *HandlerTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, portID, channnelID, ch) + suite.cdc = suite.chainA.App.Codec() } func (suite *HandlerTestSuite) queryProof(key []byte) (proof commitment.Proof, height int64) { - res := suite.app.Query(abci.RequestQuery{ + res := suite.chainA.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), Data: key, Prove: true, @@ -162,26 +91,31 @@ func (suite *HandlerTestSuite) queryProof(key []byte) (proof commitment.Proof, h func (suite *HandlerTestSuite) TestHandleMsgTransfer() { source := true - handler := transfer.NewHandler(suite.app.TransferKeeper) + handler := transfer.NewHandler(suite.chainA.App.TransferKeeper) + ctx := suite.chainA.GetContext() msg := transfer.NewMsgTransfer(testPort1, testChannel1, 10, testCoins, testAddr1, testAddr2, source) - res, err := handler(suite.ctx, msg) + res, err := handler(ctx, msg) suite.Require().Error(err) suite.Require().Nil(res, "%+v", res) // channel does not exist - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) - res, err = handler(suite.ctx, msg) + // Setup channel from A to B + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + + res, err = handler(ctx, msg) suite.Require().Error(err) suite.Require().Nil(res, "%+v", res) // next send sequence not found nextSeqSend := uint64(1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, nextSeqSend) - res, err = handler(suite.ctx, msg) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, testPort1, testChannel1, nextSeqSend) + res, err = handler(ctx, msg) suite.Require().Error(err) suite.Require().Nil(res, "%+v", res) // sender has insufficient coins - _ = suite.app.BankKeeper.SetBalances(suite.ctx, testAddr1, testCoins) - res, err = handler(suite.ctx, msg) + _ = suite.chainA.App.BankKeeper.SetBalances(ctx, testAddr1, testCoins) + res, err = handler(ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res, "%+v", res) // successfully executed @@ -189,17 +123,17 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { source = false msg = transfer.NewMsgTransfer(testPort1, testChannel1, 10, testPrefixedCoins2, testAddr1, testAddr2, source) - _ = suite.app.BankKeeper.SetBalances(suite.ctx, testAddr1, testPrefixedCoins2) + _ = suite.chainA.App.BankKeeper.SetBalances(ctx, testAddr1, testPrefixedCoins2) - res, err = handler(suite.ctx, msg) + res, err = handler(ctx, msg) suite.Require().Error(err) suite.Require().Nil(res, "%+v", res) // incorrect denom prefix msg = transfer.NewMsgTransfer(testPort1, testChannel1, 10, testPrefixedCoins1, testAddr1, testAddr2, source) - suite.app.SupplyKeeper.SetSupply(suite.ctx, supply.NewSupply(testPrefixedCoins1)) - _ = suite.app.BankKeeper.SetBalances(suite.ctx, testAddr1, testPrefixedCoins1) + suite.chainA.App.SupplyKeeper.SetSupply(ctx, supply.NewSupply(testPrefixedCoins1)) + _ = suite.chainA.App.BankKeeper.SetBalances(ctx, testAddr1, testPrefixedCoins1) - res, err = handler(suite.ctx, msg) + res, err = handler(ctx, msg) suite.Require().NoError(err) suite.Require().NotNil(res, "%+v", res) // successfully executed } @@ -207,3 +141,180 @@ func (suite *HandlerTestSuite) TestHandleMsgTransfer() { func TestHandlerTestSuite(t *testing.T) { suite.Run(t, new(HandlerTestSuite)) } + +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitment.NewRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order exported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Vals, chain.Signers) +} diff --git a/x/ibc/20-transfer/keeper/keeper_test.go b/x/ibc/20-transfer/keeper/keeper_test.go index 082aa2b12f0b..dfb75aa17438 100644 --- a/x/ibc/20-transfer/keeper/keeper_test.go +++ b/x/ibc/20-transfer/keeper/keeper_test.go @@ -14,23 +14,26 @@ import ( "github.com/cosmos/cosmos-sdk/simapp" sdk "github.com/cosmos/cosmos-sdk/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" - channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" + channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" ibctypes "github.com/cosmos/cosmos-sdk/x/ibc/types" + "github.com/cosmos/cosmos-sdk/x/staking" ) // define constants used for testing const ( testChainID = "test-chain-id" - testClient = "test-client" + testClientIDA = "testclientIDA" + testClientIDB = "testClientIDb" testClientType = clientexported.Tendermint - testConnection = "testconnection" + testConnection = "testconnectionatob" testPort1 = "bank" testPort2 = "testportid" testChannel1 = "firstchannel" @@ -56,120 +59,224 @@ var ( type KeeperTestSuite struct { suite.Suite - cdc *codec.Codec - ctx sdk.Context - app *simapp.SimApp - valSet *tmtypes.ValidatorSet + cdc *codec.Codec + + chainA *TestChain + chainB *TestChain } func (suite *KeeperTestSuite) SetupTest() { - isCheckTx := false - app := simapp.Setup(isCheckTx) + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) - suite.cdc = app.Codec() - suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) - suite.app = app + suite.cdc = suite.chainA.App.Codec() +} - privVal := tmtypes.NewMockPV() +// nolint: unused +func (suite *KeeperTestSuite) queryProof(key []byte) (proof commitment.Proof, height int64) { + res := suite.chainA.App.Query(abci.RequestQuery{ + Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), + Data: key, + Prove: true, + }) - validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) - suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + height = res.Height + proof = commitment.Proof{ + Proof: res.Proof, + } - suite.createClient() - suite.createConnection(connectionexported.OPEN) + return } -func (suite *KeeperTestSuite) createClient() { - suite.app.Commit() - commitID := suite.app.LastCommitID() - - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) +func (suite *KeeperTestSuite) TestGetTransferAccount() { + expectedMaccName := types.GetModuleAccountName() + expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(expectedMaccName))) - consensusState := ibctmtypes.ConsensusState{ - Root: commitment.NewRoot(commitID.Hash), - ValidatorSet: suite.valSet, - } + macc := suite.chainA.App.TransferKeeper.GetTransferAccount(suite.chainA.GetContext()) - clientState, err := ibctmtypes.Initialize(testClient, testClient, consensusState, trustingPeriod, ubdPeriod) - suite.NoError(err) - _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) - suite.NoError(err) + suite.NotNil(macc) + suite.Equal(expectedMaccName, macc.GetName()) + suite.Equal(expectedMaccAddr, macc.GetAddress()) } -// nolint: unused -func (suite *KeeperTestSuite) updateClient() { - // always commit and begin a new block on updateClient - suite.app.Commit() - commitID := suite.app.LastCommitID() +func TestKeeperTestSuite(t *testing.T) { + suite.Run(t, new(KeeperTestSuite)) +} - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} - state := ibctmtypes.ConsensusState{ - Root: commitment.NewRoot(commitID.Hash), +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, } +} - suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClient, 1, state) +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) } -func (suite *KeeperTestSuite) createConnection(state connectionexported.State) { - connection := connection.ConnectionEnd{ - State: state, - ClientID: testClient, - Counterparty: connection.Counterparty{ - ClientID: testClient, - ConnectionID: testConnection, - Prefix: suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, }, - Versions: connection.GetCompatibleVersions(), + Valset: validators, } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnection, connection) -} + // Create target ctx + ctxTarget := chain.GetContext() -func (suite *KeeperTestSuite) createChannel(portID string, chanID string, connID string, counterpartyPort string, counterpartyChan string, state channelexported.State) { - ch := channel.Channel{ - State: state, - Ordering: testChannelOrder, - Counterparty: channel.Counterparty{ - PortID: counterpartyPort, - ChannelID: counterpartyChan, - }, - ConnectionHops: []string{connID}, - Version: testChannelVersion, + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err } - - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, portID, chanID, ch) + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) } // nolint: unused -func (suite *KeeperTestSuite) queryProof(key []byte) (proof commitment.Proof, height int64) { - res := suite.app.Query(abci.RequestQuery{ - Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), - Data: key, - Prove: true, - }) +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } - height = res.Height - proof = commitment.Proof{ - Proof: res.Proof, + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) - return -} + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height), + Timestamp: client.Header.Time, + Root: commitment.NewRoot(commitID.Hash), + ValidatorSet: client.Vals, + } -func (suite *KeeperTestSuite) TestGetTransferAccount() { - expectedMaccName := types.GetModuleAccountName() - expectedMaccAddr := sdk.AccAddress(crypto.AddressHash([]byte(expectedMaccName))) + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.app.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} - macc := suite.app.TransferKeeper.GetTransferAccount(suite.ctx) +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} - suite.NotNil(macc) - suite.Equal(expectedMaccName, macc.GetName()) - suite.Equal(expectedMaccAddr, macc.GetAddress()) +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order exported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel } -func TestKeeperTestSuite(t *testing.T) { - suite.Run(t, new(KeeperTestSuite)) +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Vals, chain.Signers) } diff --git a/x/ibc/20-transfer/keeper/relay_test.go b/x/ibc/20-transfer/keeper/relay_test.go index 38a0cff55d90..101ec8698ce9 100644 --- a/x/ibc/20-transfer/keeper/relay_test.go +++ b/x/ibc/20-transfer/keeper/relay_test.go @@ -4,6 +4,7 @@ import ( "fmt" sdk "github.com/cosmos/cosmos-sdk/types" + connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" "github.com/cosmos/cosmos-sdk/x/ibc/20-transfer/types" @@ -21,43 +22,55 @@ func (suite *KeeperTestSuite) TestSendTransfer() { }{ {"successful transfer from source chain", testCoins, func() { - suite.app.BankKeeper.AddCoins(suite.ctx, testAddr1, testCoins) - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), testAddr1, testCoins) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) }, true, true}, {"successful transfer from source chain with denom prefix", testCoins2, func() { - _, err := suite.app.BankKeeper.AddCoins(suite.ctx, testAddr1, testCoins) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), testAddr1, testCoins) suite.Require().NoError(err) - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) }, true, true}, {"successful transfer from external chain", testCoins, func() { - suite.app.SupplyKeeper.SetSupply(suite.ctx, supply.NewSupply(prefixCoins)) - _, err := suite.app.BankKeeper.AddCoins(suite.ctx, testAddr1, prefixCoins) + suite.chainA.App.SupplyKeeper.SetSupply(suite.chainA.GetContext(), supply.NewSupply(prefixCoins)) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), testAddr1, prefixCoins) suite.Require().NoError(err) - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) }, false, true}, {"source channel not found", testCoins, func() {}, true, false}, {"next seq send not found", testCoins, func() { - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) }, true, false}, // createOutgoingPacket tests // - source chain {"send coins failed", testCoins, func() { - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) }, true, false}, // - receiving chain {"send from module account failed", testCoins, func() { - suite.createChannel(testPort1, testChannel1, testConnection, testPort2, testChannel2, channelexported.OPEN) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, testPort1, testChannel1, 1) + suite.chainA.CreateClient(suite.chainB) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainA.createChannel(testPort1, testChannel1, testPort2, testChannel2, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), testPort1, testChannel1, 1) }, false, false}, } @@ -68,8 +81,8 @@ func (suite *KeeperTestSuite) TestSendTransfer() { tc.malleate() - err := suite.app.TransferKeeper.SendTransfer( - suite.ctx, testPort1, testChannel1, 100, tc.amount, testAddr1, testAddr2, tc.isSourceChain, + err := suite.chainA.App.TransferKeeper.SendTransfer( + suite.chainA.GetContext(), testPort1, testChannel1, 100, tc.amount, testAddr1, testAddr2, tc.isSourceChain, ) if tc.expPass { @@ -114,7 +127,7 @@ func (suite *KeeperTestSuite) TestReceiveTransfer() { data.Source = false data.Amount = prefixCoins escrow := types.GetEscrowAddress(testPort2, testChannel2) - _, err := suite.app.BankKeeper.AddCoins(suite.ctx, escrow, testCoins) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, testCoins) suite.Require().NoError(err) }, true}, } @@ -127,7 +140,7 @@ func (suite *KeeperTestSuite) TestReceiveTransfer() { suite.SetupTest() // reset tc.malleate() - err := suite.app.TransferKeeper.ReceiveTransfer(suite.ctx, packet, data) + err := suite.chainA.App.TransferKeeper.ReceiveTransfer(suite.chainA.GetContext(), packet, data) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) @@ -149,7 +162,7 @@ func (suite *KeeperTestSuite) TestTimeoutTransfer() { {"successful timeout from source chain", func() { escrow := types.GetEscrowAddress(testPort2, testChannel2) - _, err := suite.app.BankKeeper.AddCoins(suite.ctx, escrow, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(100)))) + _, err := suite.chainA.App.BankKeeper.AddCoins(suite.chainA.GetContext(), escrow, sdk.NewCoins(sdk.NewCoin("atom", sdk.NewInt(100)))) suite.Require().NoError(err) }, true}, {"successful timeout from external chain", @@ -181,7 +194,7 @@ func (suite *KeeperTestSuite) TestTimeoutTransfer() { suite.SetupTest() // reset tc.malleate() - err := suite.app.TransferKeeper.TimeoutTransfer(suite.ctx, packet, data) + err := suite.chainA.App.TransferKeeper.TimeoutTransfer(suite.chainA.GetContext(), packet, data) if tc.expPass { suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg) diff --git a/x/ibc/ante/ante_test.go b/x/ibc/ante/ante_test.go index 6148a01f8c33..535157c7ad6c 100644 --- a/x/ibc/ante/ante_test.go +++ b/x/ibc/ante/ante_test.go @@ -14,12 +14,14 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported" - connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" connectionexported "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/exported" + connectiontypes "github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types" channel "github.com/cosmos/cosmos-sdk/x/ibc/04-channel" + "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channelexported "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/exported" channeltypes "github.com/cosmos/cosmos-sdk/x/ibc/04-channel/types" ibctmtypes "github.com/cosmos/cosmos-sdk/x/ibc/07-tendermint/types" + "github.com/cosmos/cosmos-sdk/x/staking" commitment "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment" "github.com/cosmos/cosmos-sdk/x/ibc/ante" @@ -29,13 +31,16 @@ import ( // define constants used for testing const ( testChainID = "test-chain-id" - testClient = "test-client" + testClientIDA = "testclientida" + testClientIDB = "testclientidb" testClientType = clientexported.Tendermint testConnection = "testconnection" testChannelVersion = "1.0" + height = 10 + trustingPeriod time.Duration = time.Hour * 24 * 7 * 2 ubdPeriod time.Duration = time.Hour * 24 * 7 * 3 ) @@ -44,105 +49,27 @@ const ( type HandlerTestSuite struct { suite.Suite - cdc *codec.Codec - ctx sdk.Context - app *simapp.SimApp - valSet *tmtypes.ValidatorSet - now time.Time -} - -func (suite *HandlerTestSuite) SetupTest() { - isCheckTx := false - app := simapp.Setup(isCheckTx) - suite.now = time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) - - suite.cdc = app.Codec() - suite.ctx = app.BaseApp.NewContext(isCheckTx, abci.Header{}) - suite.app = app - - privVal := tmtypes.NewMockPV() - - validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) - suite.valSet = tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) - - suite.createClient() - suite.createConnection(connectionexported.OPEN) -} - -func (suite *HandlerTestSuite) createClient() { - suite.app.Commit() - commitID := suite.app.LastCommitID() - now2 := suite.now.Add(time.Hour) + cdc *codec.Codec - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.app.LastBlockHeight() + 1, Time: now2}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - - consensusState := ibctmtypes.ConsensusState{ - Timestamp: suite.now, - Root: commitment.NewRoot(commitID.Hash), - ValidatorSet: suite.valSet, - } - - clientState, err := ibctmtypes.Initialize(testClient, testClient, consensusState, trustingPeriod, ubdPeriod) - suite.NoError(err) - _, err = suite.app.IBCKeeper.ClientKeeper.CreateClient(suite.ctx, clientState, consensusState) - suite.NoError(err) + chainA *TestChain + chainB *TestChain } -func (suite *HandlerTestSuite) updateClient() { - // always commit and begin a new block on updateClient - suite.app.Commit() - commitID := suite.app.LastCommitID() - - height := suite.app.LastBlockHeight() + 1 - suite.now = suite.now.Add(time.Minute) - - suite.app.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: height, Time: suite.now}}) - suite.ctx = suite.app.BaseApp.NewContext(false, abci.Header{}) - - state := ibctmtypes.ConsensusState{ - Root: commitment.NewRoot(commitID.Hash), - } - - suite.app.IBCKeeper.ClientKeeper.SetClientConsensusState(suite.ctx, testClient, uint64(height-1), state) - csi, _ := suite.app.IBCKeeper.ClientKeeper.GetClientState(suite.ctx, testClient) - cs, _ := csi.(ibctmtypes.ClientState) - cs.LatestHeight = uint64(height - 1) - suite.app.IBCKeeper.ClientKeeper.SetClientState(suite.ctx, cs) -} - -func (suite *HandlerTestSuite) createConnection(state connectionexported.State) { - connection := connection.ConnectionEnd{ - State: state, - ClientID: testClient, - Counterparty: connection.Counterparty{ - ClientID: testClient, - ConnectionID: testConnection, - Prefix: suite.app.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix(), - }, - Versions: connection.GetCompatibleVersions(), - } - - suite.app.IBCKeeper.ConnectionKeeper.SetConnection(suite.ctx, testConnection, connection) -} +func (suite *HandlerTestSuite) SetupTest() { + suite.chainA = NewTestChain(testClientIDA) + suite.chainB = NewTestChain(testClientIDB) -func (suite *HandlerTestSuite) createChannel(portID string, chanID string, connID string, counterpartyPort string, counterpartyChan string, state channelexported.State, order channelexported.Order) { - ch := channel.Channel{ - State: state, - Ordering: order, - Counterparty: channel.Counterparty{ - PortID: counterpartyPort, - ChannelID: counterpartyChan, - }, - ConnectionHops: []string{connID}, - Version: testChannelVersion, - } + suite.cdc = suite.chainA.App.Codec() - suite.app.IBCKeeper.ChannelKeeper.SetChannel(suite.ctx, portID, chanID, ch) + // create client and connection during setups + suite.chainA.CreateClient(suite.chainB) + suite.chainB.CreateClient(suite.chainA) + suite.chainA.createConnection(testConnection, testConnection, testClientIDB, testClientIDA, connectionexported.OPEN) + suite.chainB.createConnection(testConnection, testConnection, testClientIDA, testClientIDB, connectionexported.OPEN) } -func (suite *HandlerTestSuite) queryProof(key string) (proof commitment.Proof, height int64) { - res := suite.app.Query(abci.RequestQuery{ +func queryProof(chain *TestChain, key string) (proof commitment.Proof, height int64) { + res := chain.App.Query(abci.RequestQuery{ Path: fmt.Sprintf("store/%s/key", ibctypes.StoreKey), Data: []byte(key), Prove: true, @@ -164,39 +91,44 @@ func (suite *HandlerTestSuite) newTx(msg sdk.Msg) sdk.Tx { func (suite *HandlerTestSuite) TestHandleMsgPacketOrdered() { handler := sdk.ChainAnteDecorators(ante.NewProofVerificationDecorator( - suite.app.IBCKeeper.ClientKeeper, - suite.app.IBCKeeper.ChannelKeeper, + suite.chainA.App.IBCKeeper.ClientKeeper, + suite.chainA.App.IBCKeeper.ChannelKeeper, )) packet := channel.NewPacket(newPacket(12345), 1, portid, chanid, cpportid, cpchanid) - cctx, _ := suite.ctx.CacheContext() - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, packet.SourcePort, packet.SourceChannel, 1) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, packet.SourcePort, packet.SourceChannel, packet.Sequence, channeltypes.CommitPacket(packet.Data)) + ctx := suite.chainA.GetContext() + cctx, _ := ctx.CacheContext() + // suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(ctx, packet.SourcePort, packet.SourceChannel, 1) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), packet.SourcePort, packet.SourceChannel, packet.Sequence, channeltypes.CommitPacket(packet.Data)) msg := channel.NewMsgPacket(packet, nil, 0, addr1) _, err := handler(cctx, suite.newTx(msg), false) suite.Error(err, "%+v", err) // channel does not exist - cctx, _ = suite.ctx.CacheContext() - suite.createChannel(cpportid, cpchanid, testConnection, portid, chanid, channelexported.OPEN, channelexported.ORDERED) + suite.chainA.createChannel(cpportid, cpchanid, portid, chanid, channelexported.OPEN, channelexported.ORDERED, testConnection) + suite.chainB.createChannel(portid, chanid, cpportid, cpchanid, channelexported.OPEN, channelexported.ORDERED, testConnection) + ctx = suite.chainA.GetContext() packetCommitmentPath := ibctypes.PacketCommitmentPath(packet.SourcePort, packet.SourceChannel, packet.Sequence) - proof, proofHeight := suite.queryProof(packetCommitmentPath) + proof, proofHeight := queryProof(suite.chainB, packetCommitmentPath) msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) _, err = handler(cctx, suite.newTx(msg), false) suite.Error(err, "%+v", err) // invalid proof - suite.updateClient() + suite.chainA.updateClient(suite.chainB) + // // commit chainA to flush to IAVL so we can get proof + // suite.chainA.App.Commit() + // suite.chainA.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: suite.chainA.App.LastBlockHeight() + 1, Time: suite.chainA.Header.Time}}) + // ctx = suite.chainA.GetContext() - proof, proofHeight = suite.queryProof(packetCommitmentPath) + proof, proofHeight = queryProof(suite.chainB, packetCommitmentPath) msg = channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(suite.ctx, cpportid, cpchanid, 1) - cctx, write := suite.ctx.CacheContext() for i := 0; i < 10; i++ { - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(cctx, cpportid, cpchanid, uint64(i)) + cctx, write := suite.chainA.GetContext().CacheContext() + suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceRecv(cctx, cpportid, cpchanid, uint64(i)) _, err := handler(cctx, suite.newTx(msg), false) if err == nil { - err = suite.app.IBCKeeper.ChannelKeeper.PacketExecuted(cctx, packet, packet.Data) + err = suite.chainA.App.IBCKeeper.ChannelKeeper.PacketExecuted(cctx, packet, packet.Data) } if i == 1 { suite.NoError(err, "%d", i) // successfully executed @@ -209,8 +141,8 @@ func (suite *HandlerTestSuite) TestHandleMsgPacketOrdered() { func (suite *HandlerTestSuite) TestHandleMsgPacketUnordered() { handler := sdk.ChainAnteDecorators(ante.NewProofVerificationDecorator( - suite.app.IBCKeeper.ClientKeeper, - suite.app.IBCKeeper.ChannelKeeper, + suite.chainA.App.IBCKeeper.ClientKeeper, + suite.chainA.App.IBCKeeper.ChannelKeeper, )) // Not testing nonexist channel, invalid proof, nextseqsend, they are already tested in TestHandleMsgPacketOrdered @@ -218,20 +150,20 @@ func (suite *HandlerTestSuite) TestHandleMsgPacketUnordered() { var packet channeltypes.Packet for i := 0; i < 5; i++ { packet = channel.NewPacket(newPacket(uint64(i)), uint64(i), portid, chanid, cpportid, cpchanid) - suite.app.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.ctx, packet.SourcePort, packet.SourceChannel, uint64(i), channeltypes.CommitPacket(packet.Data)) + suite.chainB.App.IBCKeeper.ChannelKeeper.SetPacketCommitment(suite.chainB.GetContext(), packet.SourcePort, packet.SourceChannel, uint64(i), channeltypes.CommitPacket(packet.Data)) } - suite.app.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.ctx, packet.SourcePort, packet.SourceChannel, uint64(10)) + // suite.chainA.App.IBCKeeper.ChannelKeeper.SetNextSequenceSend(suite.chainA.GetContext(), packet.SourcePort, packet.SourceChannel, uint64(10)) - suite.createChannel(cpportid, cpchanid, testConnection, portid, chanid, channelexported.OPEN, channelexported.UNORDERED) + suite.chainA.createChannel(cpportid, cpchanid, portid, chanid, channelexported.OPEN, channelexported.UNORDERED, testConnection) - suite.updateClient() + suite.chainA.updateClient(suite.chainB) for i := 10; i >= 0; i-- { - cctx, write := suite.ctx.CacheContext() + cctx, write := suite.chainA.GetContext().CacheContext() packet = channel.NewPacket(newPacket(uint64(i)), uint64(i), portid, chanid, cpportid, cpchanid) packetCommitmentPath := ibctypes.PacketCommitmentPath(packet.SourcePort, packet.SourceChannel, uint64(i)) - proof, proofHeight := suite.queryProof(packetCommitmentPath) + proof, proofHeight := queryProof(suite.chainB, packetCommitmentPath) msg := channel.NewMsgPacket(packet, proof, uint64(proofHeight), addr1) _, err := handler(cctx, suite.newTx(msg), false) if i < 5 { @@ -242,10 +174,188 @@ func (suite *HandlerTestSuite) TestHandleMsgPacketUnordered() { } } } + func TestHandlerTestSuite(t *testing.T) { suite.Run(t, new(HandlerTestSuite)) } +type TestChain struct { + ClientID string + App *simapp.SimApp + Header ibctmtypes.Header + Vals *tmtypes.ValidatorSet + Signers []tmtypes.PrivValidator +} + +func NewTestChain(clientID string) *TestChain { + privVal := tmtypes.NewMockPV() + validator := tmtypes.NewValidator(privVal.GetPubKey(), 1) + valSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{validator}) + signers := []tmtypes.PrivValidator{privVal} + now := time.Date(2020, 1, 2, 0, 0, 0, 0, time.UTC) + + header := ibctmtypes.CreateTestHeader(clientID, 1, now, valSet, valSet, signers) + + return &TestChain{ + ClientID: clientID, + App: simapp.Setup(false), + Header: header, + Vals: valSet, + Signers: signers, + } +} + +// Creates simple context for testing purposes +func (chain *TestChain) GetContext() sdk.Context { + return chain.App.BaseApp.NewContext(false, abci.Header{ChainID: chain.Header.ChainID, Height: chain.Header.Height}) +} + +// createClient will create a client for clientChain on targetChain +func (chain *TestChain) CreateClient(client *TestChain) error { + client.Header = nextHeader(client) + // Commit and create a new block on appTarget to get a fresh CommitID + client.App.Commit() + commitID := client.App.LastCommitID() + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) // get one voting power + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + // Create target ctx + ctxTarget := chain.GetContext() + + // create client + clientState, err := ibctmtypes.Initialize(client.ClientID, trustingPeriod, ubdPeriod, client.Header) + if err != nil { + return err + } + _, err = chain.App.IBCKeeper.ClientKeeper.CreateClient(ctxTarget, clientState, client.Header.ConsensusState()) + if err != nil { + return err + } + return nil + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.chainA.App.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgCreateClient(clientID, clientexported.ClientTypeTendermint, consState, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) +} + +func (chain *TestChain) updateClient(client *TestChain) { + // Create target ctx + ctxTarget := chain.GetContext() + + // if clientState does not already exist, return without updating + _, found := chain.App.IBCKeeper.ClientKeeper.GetClientState( + ctxTarget, client.ClientID, + ) + if !found { + return + } + + // always commit when updateClient and begin a new block + client.App.Commit() + commitID := client.App.LastCommitID() + + client.Header = nextHeader(client) + client.App.BeginBlock(abci.RequestBeginBlock{Header: abci.Header{Height: client.Header.Height, Time: client.Header.Time}}) + + // Set HistoricalInfo on client chain after Commit + ctxClient := client.GetContext() + validator := staking.NewValidator( + sdk.ValAddress(client.Vals.Validators[0].Address), client.Vals.Validators[0].PubKey, staking.Description{}, + ) + validator.Status = sdk.Bonded + validator.Tokens = sdk.NewInt(1000000) + validators := []staking.Validator{validator} + histInfo := staking.HistoricalInfo{ + Header: abci.Header{ + AppHash: commitID.Hash, + }, + Valset: validators, + } + client.App.StakingKeeper.SetHistoricalInfo(ctxClient, client.Header.Height, histInfo) + + consensusState := ibctmtypes.ConsensusState{ + Height: uint64(client.Header.Height) - 1, + Timestamp: client.Header.Time, + Root: commitment.NewRoot(commitID.Hash), + ValidatorSet: client.Vals, + } + + chain.App.IBCKeeper.ClientKeeper.SetClientConsensusState( + ctxTarget, client.ClientID, uint64(client.Header.Height-1), consensusState, + ) + chain.App.IBCKeeper.ClientKeeper.SetClientState( + ctxTarget, ibctmtypes.NewClientState(client.ClientID, trustingPeriod, ubdPeriod, client.Header), + ) + + // _, _, err := simapp.SignCheckDeliver( + // suite.T(), + // suite.cdc, + // suite.chainA.App.BaseApp, + // ctx.BlockHeader(), + // []sdk.Msg{clienttypes.NewMsgUpdateClient(clientID, suite.header, accountAddress)}, + // []uint64{baseAccount.GetAccountNumber()}, + // []uint64{baseAccount.GetSequence()}, + // true, true, accountPrivKey, + // ) + // suite.Require().NoError(err) +} + +func (chain *TestChain) createConnection( + connID, counterpartyConnID, clientID, counterpartyClientID string, + state connectionexported.State, +) connectiontypes.ConnectionEnd { + counterparty := connectiontypes.NewCounterparty(counterpartyClientID, counterpartyConnID, chain.App.IBCKeeper.ConnectionKeeper.GetCommitmentPrefix()) + connection := connectiontypes.ConnectionEnd{ + State: state, + ClientID: clientID, + Counterparty: counterparty, + Versions: connectiontypes.GetCompatibleVersions(), + } + ctx := chain.GetContext() + chain.App.IBCKeeper.ConnectionKeeper.SetConnection(ctx, connID, connection) + return connection +} + +func (chain *TestChain) createChannel( + portID, channelID, counterpartyPortID, counterpartyChannelID string, + state channelexported.State, order exported.Order, connectionID string, +) channeltypes.Channel { + counterparty := channeltypes.NewCounterparty(counterpartyPortID, counterpartyChannelID) + channel := channeltypes.NewChannel(state, order, counterparty, + []string{connectionID}, "1.0", + ) + ctx := chain.GetContext() + chain.App.IBCKeeper.ChannelKeeper.SetChannel(ctx, portID, channelID, channel) + return channel +} + +func nextHeader(chain *TestChain) ibctmtypes.Header { + return ibctmtypes.CreateTestHeader(chain.Header.ChainID, chain.Header.Height+1, + chain.Header.Time.Add(time.Minute), chain.Vals, chain.Vals, chain.Signers) +} + var _ channelexported.PacketDataI = packetT{} type packetT struct { diff --git a/x/slashing/keeper/keeper.go b/x/slashing/keeper/keeper.go index 3616a7cd3dab..3d9baac23cf6 100644 --- a/x/slashing/keeper/keeper.go +++ b/x/slashing/keeper/keeper.go @@ -23,6 +23,11 @@ type Keeper struct { // NewKeeper creates a slashing keeper func NewKeeper(cdc codec.Marshaler, key sdk.StoreKey, sk types.StakingKeeper, paramspace types.ParamSubspace) Keeper { + // set KeyTable if it has not already been set + if !paramspace.HasKeyTable() { + paramspace = paramspace.WithKeyTable(types.ParamKeyTable()) + } + return Keeper{ storeKey: key, cdc: cdc,