diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 847bdee6968..51939164938 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -508,7 +508,9 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - trustedHeight := path.EndpointA.GetClientState().(*ibctm.ClientState).LatestHeight + tmClientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + trustedHeight := tmClientState.LatestHeight header, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index fd120c12b54..739d735ea54 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -570,7 +570,9 @@ func (suite *KeeperTestSuite) TestIBCSoftwareUpgrade() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - upgradedClientState = path.EndpointA.GetClientState().(*ibctm.ClientState).ZeroCustomFields() + tmClientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + upgradedClientState = tmClientState.ZeroCustomFields() // use height 1000 to distinguish from old plan plan = upgradetypes.Plan{ diff --git a/modules/light-clients/07-tendermint/light_client_module_test.go b/modules/light-clients/07-tendermint/light_client_module_test.go index 6a30ec13785..77c446e5a70 100644 --- a/modules/light-clients/07-tendermint/light_client_module_test.go +++ b/modules/light-clients/07-tendermint/light_client_module_test.go @@ -5,6 +5,7 @@ import ( "fmt" "time" + errorsmod "cosmossdk.io/errors" upgradetypes "cosmossdk.io/x/upgrade/types" codectypes "github.com/cosmos/cosmos-sdk/codec/types" @@ -27,157 +28,6 @@ var ( solomachineClientID = clienttypes.FormatClientIdentifier(exported.Solomachine, 0) ) -func (suite *TendermintTestSuite) TestStatus() { - var ( - path *ibctesting.Path - clientState *ibctm.ClientState - ) - - testCases := []struct { - name string - malleate func() - expStatus exported.Status - }{ - { - "client is active", - func() {}, - exported.Active, - }, - { - "client is frozen", - func() { - clientState.FrozenHeight = clienttypes.NewHeight(0, 1) - path.EndpointA.SetClientState(clientState) - }, - exported.Frozen, - }, - { - "client status without consensus state", - func() { - var ok bool - clientState.LatestHeight, ok = clientState.LatestHeight.Increment().(clienttypes.Height) - suite.Require().True(ok) - path.EndpointA.SetClientState(clientState) - }, - exported.Expired, - }, - { - "client status is expired", - func() { - suite.coordinator.IncrementTimeBy(clientState.TrustingPeriod) - }, - exported.Expired, - }, - { - "client state not found", - func() { - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - store.Delete(host.ClientStateKey()) - }, - exported.Unknown, - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() - - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupClients() - - lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) - suite.Require().True(found) - - var ok bool - clientState, ok = path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - - tc.malleate() - - status := lightClientModule.Status(suite.chainA.GetContext(), path.EndpointA.ClientID) - suite.Require().Equal(tc.expStatus, status) - }) - - } -} - -func (suite *TendermintTestSuite) TestGetTimestampAtHeight() { - var ( - path *ibctesting.Path - height exported.Height - ) - expectedTimestamp := time.Unix(1, 0) - - testCases := []struct { - name string - malleate func() - expErr error - }{ - { - "success", - func() {}, - nil, - }, - { - "failure: client state not found for height", - func() { - store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - store.Delete(host.ClientStateKey()) - }, - clienttypes.ErrClientNotFound, - }, - { - "failure: consensus state not found for height", - func() { - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - height = clientState.LatestHeight.Increment() - }, - clienttypes.ErrConsensusStateNotFound, - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() - - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupClients() - - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - height = clientState.LatestHeight - - // grab consensusState from store and update with a predefined timestamp - consensusState := path.EndpointA.GetConsensusState(height) - tmConsensusState, ok := consensusState.(*ibctm.ConsensusState) - suite.Require().True(ok) - - tmConsensusState.Timestamp = expectedTimestamp - path.EndpointA.SetConsensusState(tmConsensusState, height) - - lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) - suite.Require().True(found) - - tc.malleate() - - timestamp, err := lightClientModule.TimestampAtHeight(suite.chainA.GetContext(), path.EndpointA.ClientID, height) - - expPass := tc.expErr == nil - if expPass { - suite.Require().NoError(err) - - expectedTimestamp := uint64(expectedTimestamp.UnixNano()) - suite.Require().Equal(expectedTimestamp, timestamp) - } else { - suite.Require().ErrorIs(err, tc.expErr) - } - }) - } -} - func (suite *TendermintTestSuite) TestInitialize() { var consensusState exported.ConsensusState var clientState exported.ClientState @@ -267,11 +117,8 @@ func (suite *TendermintTestSuite) TestInitialize() { } } -func (suite *TendermintTestSuite) TestRecoverClient() { - var ( - subjectClientID, substituteClientID string - subjectClientState exported.ClientState - ) +func (suite *TendermintTestSuite) TestVerifyClientMessage() { + var path *ibctesting.Path testCases := []struct { name string @@ -280,35 +127,14 @@ func (suite *TendermintTestSuite) TestRecoverClient() { }{ { "success", - func() { - }, + func() {}, nil, }, { - "cannot parse malformed substitute client ID", - func() { - substituteClientID = ibctesting.InvalidID - }, - host.ErrInvalidID, - }, - { - "substitute client ID does not contain 07-tendermint prefix", - func() { - substituteClientID = solomachineClientID - }, - clienttypes.ErrInvalidClientType, - }, - { - "cannot find subject client state", - func() { - subjectClientID = tmClientID - }, - clienttypes.ErrClientNotFound, - }, - { - "cannot find substitute client state", + "failure: client state not found", func() { - substituteClientID = tmClientID + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) }, clienttypes.ErrClientNotFound, }, @@ -317,54 +143,128 @@ func (suite *TendermintTestSuite) TestRecoverClient() { for _, tc := range testCases { tc := tc suite.Run(tc.name, func() { - suite.SetupTest() // reset - ctx := suite.chainA.GetContext() + suite.SetupTest() - subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) - subjectPath.SetupClients() - subjectClientID = subjectPath.EndpointA.ClientID - subjectClientState = suite.chainA.GetClientState(subjectClientID) + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() - substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) - substitutePath.SetupClients() - substituteClientID = substitutePath.EndpointA.ClientID + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) - tmClientState, ok := subjectClientState.(*ibctm.ClientState) + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) suite.Require().True(ok) - tmClientState.FrozenHeight = tmClientState.LatestHeight - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(ctx, subjectPath.EndpointA.ClientID, tmClientState) - - lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(subjectClientID) - suite.Require().True(found) + header, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) + suite.Require().NoError(err) tc.malleate() - err := lightClientModule.RecoverClient(ctx, subjectClientID, substituteClientID) + err = lightClientModule.VerifyClientMessage(suite.chainA.GetContext(), path.EndpointA.ClientID, header) expPass := tc.expErr == nil if expPass { suite.Require().NoError(err) - - // assert that status of subject client is now Active - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, subjectClientID) - tmClientState, ok := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - suite.Require().Equal(exported.Active, tmClientState.Status(ctx, clientStore, suite.chainA.App.AppCodec())) } else { - suite.Require().Error(err) suite.Require().ErrorIs(err, tc.expErr) } }) } } -func (suite *TendermintTestSuite) TestVerifyUpgradeAndUpdateState() { +func (suite *TendermintTestSuite) TestCheckForMisbehaviourPanicsOnClientStateNotFound() { + suite.SetupTest() + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) + suite.Require().True(ok) + header, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) + suite.Require().NoError(err) + + // delete client state + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) + + suite.Require().PanicsWithError(errorsmod.Wrap(clienttypes.ErrClientNotFound, path.EndpointA.ClientID).Error(), + func() { + lightClientModule.CheckForMisbehaviour(suite.chainA.GetContext(), path.EndpointA.ClientID, header) + }, + ) +} + +func (suite *TendermintTestSuite) TestUpdateStateOnMisbehaviourPanicsOnClientStateNotFound() { + suite.SetupTest() + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) + suite.Require().True(ok) + header, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) + suite.Require().NoError(err) + + // delete client state + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) + + suite.Require().PanicsWithError( + errorsmod.Wrap(clienttypes.ErrClientNotFound, path.EndpointA.ClientID).Error(), + func() { + lightClientModule.UpdateStateOnMisbehaviour(suite.chainA.GetContext(), path.EndpointA.ClientID, header) + }, + ) +} + +func (suite *TendermintTestSuite) TestUpdateStatePanicsOnClientStateNotFound() { + suite.SetupTest() + + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + + // ensure counterparty state is committed + suite.coordinator.CommitBlock(suite.chainB) + trustedHeight, ok := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) + suite.Require().True(ok) + header, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) + suite.Require().NoError(err) + + // delete client state + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) + + suite.Require().PanicsWithError( + errorsmod.Wrap(clienttypes.ErrClientNotFound, path.EndpointA.ClientID).Error(), + func() { + lightClientModule.UpdateState(suite.chainA.GetContext(), path.EndpointA.ClientID, header) + }, + ) +} + +func (suite *TendermintTestSuite) TestVerifyMembership() { var ( - clientID string - path *ibctesting.Path - upgradedClientState exported.ClientState - upgradedClientStateAny, upgradedConsensusStateAny *codectypes.Any - upgradedClientStateProof, upgradedConsensusStateProof []byte + testingpath *ibctesting.Path + delayTimePeriod uint64 + delayBlockPeriod uint64 + err error + proofHeight exported.Height + proof []byte + path exported.Path + value []byte ) testCases := []struct { @@ -373,178 +273,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgradeAndUpdateState() { expErr error }{ { - "success", - func() { - // upgrade height is at next block - upgradeHeight := clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) - - // zero custom fields and store in upgrade store - zeroedUpgradedClient := upgradedClientState.(*ibctm.ClientState).ZeroCustomFields() - zeroedUpgradedClientAny, err := codectypes.NewAnyWithValue(zeroedUpgradedClient) - suite.Require().NoError(err) - - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(zeroedUpgradedClientAny)) - suite.Require().NoError(err) - - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsensusStateAny)) - suite.Require().NoError(err) - - // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) - err = path.EndpointA.UpdateClient() - suite.Require().NoError(err) - - upgradedClientStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) - }, - nil, - }, - { - "cannot find client state", - func() { - clientID = tmClientID - }, - clienttypes.ErrClientNotFound, - }, - { - "upgraded client state is not for tendermint client state", - func() { - upgradedClientStateAny = &codectypes.Any{ - Value: []byte("invalid client state bytes"), - } - }, - clienttypes.ErrInvalidClient, - }, - { - "upgraded consensus state is not tendermint consensus state", - func() { - upgradedConsensusStateAny = &codectypes.Any{ - Value: []byte("invalid consensus state bytes"), - } - }, - clienttypes.ErrInvalidConsensus, - }, - { - "upgraded client state height is not greater than current height", - func() { - // upgrade height is at next block - upgradeHeight := clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) - - // zero custom fields and store in upgrade store - zeroedUpgradedClient := upgradedClientState.(*ibctm.ClientState).ZeroCustomFields() - zeroedUpgradedClientAny, err := codectypes.NewAnyWithValue(zeroedUpgradedClient) - suite.Require().NoError(err) - - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(zeroedUpgradedClientAny)) - suite.Require().NoError(err) - - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsensusStateAny)) - suite.Require().NoError(err) - - // change upgraded client state height to be lower than current client state height - tmClient, ok := upgradedClientState.(*ibctm.ClientState) - suite.Require().True(ok) - - newLatestheight, ok := path.EndpointA.GetClientLatestHeight().Decrement() - suite.Require().True(ok) - - tmClient.LatestHeight, ok = newLatestheight.(clienttypes.Height) - suite.Require().True(ok) - upgradedClientStateAny, err = codectypes.NewAnyWithValue(tmClient) - suite.Require().NoError(err) - - suite.coordinator.CommitBlock(suite.chainB) - err = path.EndpointA.UpdateClient() - suite.Require().NoError(err) - - upgradedClientStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) - }, - ibcerrors.ErrInvalidHeight, - }, - } - - for _, tc := range testCases { - tc := tc - suite.Run(tc.name, func() { - suite.SetupTest() // reset - - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupClients() - - clientID = path.EndpointA.ClientID - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - revisionNumber := clienttypes.ParseChainID(clientState.ChainId) - - newUnbondindPeriod := ubdPeriod + trustingPeriod - newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) - suite.Require().NoError(err) - - upgradedClientState = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, newUnbondindPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), upgradePath) - upgradedClientStateAny, err = codectypes.NewAnyWithValue(upgradedClientState) - suite.Require().NoError(err) - - nextValsHash := sha256.Sum256([]byte("new-nextValsHash")) - upgradedConsensusState := ibctm.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("new-hash")), nextValsHash[:]) - - upgradedConsensusStateAny, err = codectypes.NewAnyWithValue(upgradedConsensusState) - suite.Require().NoError(err) - - tc.malleate() - - lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(clientID) - suite.Require().True(found) - - err = lightClientModule.VerifyUpgradeAndUpdateState( - suite.chainA.GetContext(), - clientID, - upgradedClientStateAny.Value, - upgradedConsensusStateAny.Value, - upgradedClientStateProof, - upgradedConsensusStateProof, - ) - - expPass := tc.expErr == nil - if expPass { - suite.Require().NoError(err) - - expClientState := path.EndpointA.GetClientState() - expClientStateBz := suite.chainA.Codec.MustMarshal(expClientState) - suite.Require().Equal(upgradedClientStateAny.Value, expClientStateBz) - - expConsensusState := ibctm.NewConsensusState(upgradedConsensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte(ibctm.SentinelRoot)), upgradedConsensusState.NextValidatorsHash) - expConsensusStateBz := suite.chainA.Codec.MustMarshal(expConsensusState) - - consensusStateBz := suite.chainA.Codec.MustMarshal(path.EndpointA.GetConsensusState(path.EndpointA.GetClientLatestHeight())) - suite.Require().Equal(expConsensusStateBz, consensusStateBz) - } else { - suite.Require().Error(err) - suite.Require().ErrorIs(err, tc.expErr) - } - }) - } -} - -func (suite *TendermintTestSuite) TestVerifyMembership() { - var ( - testingpath *ibctesting.Path - delayTimePeriod uint64 - delayBlockPeriod uint64 - err error - proofHeight exported.Height - proof []byte - path exported.Path - value []byte - ) - - testCases := []struct { - name string - malleate func() - expErr error - }{ - { - "successful ClientState verification", + "successful ClientState verification", func() { // default proof construction uses ClientState }, @@ -740,7 +469,7 @@ func (suite *TendermintTestSuite) TestVerifyMembership() { commitmenttypes.ErrInvalidMerkleProof, }, { - "client state not found for height", + "client state not found", func() { store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), testingpath.EndpointA.ClientID) store.Delete(host.ClientStateKey()) @@ -969,7 +698,7 @@ func (suite *TendermintTestSuite) TestVerifyNonMembership() { commitmenttypes.ErrInvalidMerkleProof, }, { - "client state not found for height", + "client state not found", func() { store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), testingpath.EndpointA.ClientID) store.Delete(host.ClientStateKey()) @@ -1020,3 +749,458 @@ func (suite *TendermintTestSuite) TestVerifyNonMembership() { }) } } + +func (suite *TendermintTestSuite) TestStatus() { + var ( + path *ibctesting.Path + clientState *ibctm.ClientState + ) + + testCases := []struct { + name string + malleate func() + expStatus exported.Status + }{ + { + "client is active", + func() {}, + exported.Active, + }, + { + "client is frozen", + func() { + clientState.FrozenHeight = clienttypes.NewHeight(0, 1) + path.EndpointA.SetClientState(clientState) + }, + exported.Frozen, + }, + { + "client status without consensus state", + func() { + newLatestHeight, ok := clientState.LatestHeight.Increment().(clienttypes.Height) + suite.Require().True(ok) + clientState.LatestHeight = newLatestHeight + path.EndpointA.SetClientState(clientState) + }, + exported.Expired, + }, + { + "client status is expired", + func() { + suite.coordinator.IncrementTimeBy(clientState.TrustingPeriod) + }, + exported.Expired, + }, + { + "client state not found", + func() { + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) + }, + exported.Unknown, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + + var ok bool + clientState, ok = path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + + tc.malleate() + + status := lightClientModule.Status(suite.chainA.GetContext(), path.EndpointA.ClientID) + suite.Require().Equal(tc.expStatus, status) + }) + + } +} + +func (suite *TendermintTestSuite) TestLatestHeight() { + var ( + path *ibctesting.Path + height exported.Height + ) + + testCases := []struct { + name string + malleate func() + expHeight exported.Height + }{ + { + "success", + func() {}, + clienttypes.Height{RevisionNumber: 0x1, RevisionHeight: 0x4}, + }, + { + "client state not found", + func() { + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) + }, + clienttypes.ZeroHeight(), + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + + tc.malleate() + + height = lightClientModule.LatestHeight(suite.chainA.GetContext(), path.EndpointA.ClientID) + suite.Require().Equal(tc.expHeight, height) + }) + } +} + +func (suite *TendermintTestSuite) TestGetTimestampAtHeight() { + var ( + path *ibctesting.Path + height exported.Height + ) + expectedTimestamp := time.Unix(1, 0) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() {}, + nil, + }, + { + "failure: client state not found", + func() { + store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + store.Delete(host.ClientStateKey()) + }, + clienttypes.ErrClientNotFound, + }, + { + "failure: consensus state not found for height", + func() { + clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + height = clientState.LatestHeight.Increment() + }, + clienttypes.ErrConsensusStateNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + height = clientState.LatestHeight + + // grab consensusState from store and update with a predefined timestamp + consensusState := path.EndpointA.GetConsensusState(height) + tmConsensusState, ok := consensusState.(*ibctm.ConsensusState) + suite.Require().True(ok) + + tmConsensusState.Timestamp = expectedTimestamp + path.EndpointA.SetConsensusState(tmConsensusState, height) + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + + tc.malleate() + + timestamp, err := lightClientModule.TimestampAtHeight(suite.chainA.GetContext(), path.EndpointA.ClientID, height) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + expectedTimestamp := uint64(expectedTimestamp.UnixNano()) + suite.Require().Equal(expectedTimestamp, timestamp) + } else { + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} + +func (suite *TendermintTestSuite) TestRecoverClient() { + var ( + subjectClientID, substituteClientID string + subjectClientState exported.ClientState + ) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() { + }, + nil, + }, + { + "cannot parse malformed substitute client ID", + func() { + substituteClientID = ibctesting.InvalidID + }, + host.ErrInvalidID, + }, + { + "substitute client ID does not contain 07-tendermint prefix", + func() { + substituteClientID = solomachineClientID + }, + clienttypes.ErrInvalidClientType, + }, + { + "cannot find subject client state", + func() { + subjectClientID = tmClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "cannot find substitute client state", + func() { + substituteClientID = tmClientID + }, + clienttypes.ErrClientNotFound, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + ctx := suite.chainA.GetContext() + + subjectPath := ibctesting.NewPath(suite.chainA, suite.chainB) + subjectPath.SetupClients() + subjectClientID = subjectPath.EndpointA.ClientID + subjectClientState = suite.chainA.GetClientState(subjectClientID) + + substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) + substitutePath.SetupClients() + substituteClientID = substitutePath.EndpointA.ClientID + + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.FrozenHeight = tmClientState.LatestHeight + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(ctx, subjectPath.EndpointA.ClientID, tmClientState) + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(subjectClientID) + suite.Require().True(found) + + tc.malleate() + + err := lightClientModule.RecoverClient(ctx, subjectClientID, substituteClientID) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + // assert that status of subject client is now Active + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, subjectClientID) + tmClientState, ok := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + suite.Require().Equal(exported.Active, tmClientState.Status(ctx, clientStore, suite.chainA.App.AppCodec())) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} + +func (suite *TendermintTestSuite) TestVerifyUpgradeAndUpdateState() { + var ( + clientID string + path *ibctesting.Path + upgradedClientState exported.ClientState + upgradedClientStateAny, upgradedConsensusStateAny *codectypes.Any + upgradedClientStateProof, upgradedConsensusStateProof []byte + ) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() { + // upgrade height is at next block + upgradeHeight := clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + + // zero custom fields and store in upgrade store + zeroedUpgradedClient := upgradedClientState.(*ibctm.ClientState).ZeroCustomFields() + zeroedUpgradedClientAny, err := codectypes.NewAnyWithValue(zeroedUpgradedClient) + suite.Require().NoError(err) + + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(zeroedUpgradedClientAny)) + suite.Require().NoError(err) + + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsensusStateAny)) + suite.Require().NoError(err) + + // commit upgrade store changes and update clients + suite.coordinator.CommitBlock(suite.chainB) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + upgradedClientStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) + }, + nil, + }, + { + "cannot find client state", + func() { + clientID = tmClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "upgraded client state is not for tendermint client state", + func() { + upgradedClientStateAny = &codectypes.Any{ + Value: []byte("invalid client state bytes"), + } + }, + clienttypes.ErrInvalidClient, + }, + { + "upgraded consensus state is not tendermint consensus state", + func() { + upgradedConsensusStateAny = &codectypes.Any{ + Value: []byte("invalid consensus state bytes"), + } + }, + clienttypes.ErrInvalidConsensus, + }, + { + "upgraded client state height is not greater than current height", + func() { + // upgrade height is at next block + upgradeHeight := clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) + + // zero custom fields and store in upgrade store + zeroedUpgradedClient := upgradedClientState.(*ibctm.ClientState).ZeroCustomFields() + zeroedUpgradedClientAny, err := codectypes.NewAnyWithValue(zeroedUpgradedClient) + suite.Require().NoError(err) + + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(zeroedUpgradedClientAny)) + suite.Require().NoError(err) + + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsensusStateAny)) + suite.Require().NoError(err) + + // change upgraded client state height to be lower than current client state height + tmClient, ok := upgradedClientState.(*ibctm.ClientState) + suite.Require().True(ok) + + newLatestheight, ok := path.EndpointA.GetClientLatestHeight().Decrement() + suite.Require().True(ok) + + tmClient.LatestHeight, ok = newLatestheight.(clienttypes.Height) + suite.Require().True(ok) + upgradedClientStateAny, err = codectypes.NewAnyWithValue(tmClient) + suite.Require().NoError(err) + + suite.coordinator.CommitBlock(suite.chainB) + err = path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + upgradedClientStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), path.EndpointA.GetClientLatestHeight().GetRevisionHeight()) + }, + ibcerrors.ErrInvalidHeight, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() + + clientID = path.EndpointA.ClientID + clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(ok) + revisionNumber := clienttypes.ParseChainID(clientState.ChainId) + + newUnbondindPeriod := ubdPeriod + trustingPeriod + newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) + suite.Require().NoError(err) + + upgradedClientState = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, newUnbondindPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), upgradePath) + upgradedClientStateAny, err = codectypes.NewAnyWithValue(upgradedClientState) + suite.Require().NoError(err) + + nextValsHash := sha256.Sum256([]byte("new-nextValsHash")) + upgradedConsensusState := ibctm.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("new-hash")), nextValsHash[:]) + + upgradedConsensusStateAny, err = codectypes.NewAnyWithValue(upgradedConsensusState) + suite.Require().NoError(err) + + tc.malleate() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(clientID) + suite.Require().True(found) + + err = lightClientModule.VerifyUpgradeAndUpdateState( + suite.chainA.GetContext(), + clientID, + upgradedClientStateAny.Value, + upgradedConsensusStateAny.Value, + upgradedClientStateProof, + upgradedConsensusStateProof, + ) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + expClientState := path.EndpointA.GetClientState() + expClientStateBz := suite.chainA.Codec.MustMarshal(expClientState) + suite.Require().Equal(upgradedClientStateAny.Value, expClientStateBz) + + expConsensusState := ibctm.NewConsensusState(upgradedConsensusState.Timestamp, commitmenttypes.NewMerkleRoot([]byte(ibctm.SentinelRoot)), upgradedConsensusState.NextValidatorsHash) + expConsensusStateBz := suite.chainA.Codec.MustMarshal(expConsensusState) + + consensusStateBz := suite.chainA.Codec.MustMarshal(path.EndpointA.GetConsensusState(path.EndpointA.GetClientLatestHeight())) + suite.Require().Equal(expConsensusStateBz, consensusStateBz) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} diff --git a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go index f44dd836688..074cb8f65f5 100644 --- a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go +++ b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go @@ -368,13 +368,12 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err := path.EndpointA.CreateClient() suite.Require().NoError(err) - tc.malleate() + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + tc.malleate() - err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, misbehaviour) + err = lightClientModule.VerifyClientMessage(suite.chainA.GetContext(), path.EndpointA.ClientID, misbehaviour) if tc.expPass { suite.Require().NoError(err) @@ -678,13 +677,12 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err := path.EndpointA.CreateClient() suite.Require().NoError(err) - tc.malleate() + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + tc.malleate() - err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, misbehaviour) + err = lightClientModule.VerifyClientMessage(suite.chainA.GetContext(), path.EndpointA.ClientID, misbehaviour) if tc.expPass { suite.Require().NoError(err) diff --git a/modules/light-clients/07-tendermint/update_test.go b/modules/light-clients/07-tendermint/update_test.go index 178ffa6195b..b0e46db7d6f 100644 --- a/modules/light-clients/07-tendermint/update_test.go +++ b/modules/light-clients/07-tendermint/update_test.go @@ -307,14 +307,12 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { header, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) - tc.malleate() - - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + tc.malleate() - err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, header) + err = lightClientModule.VerifyClientMessage(suite.chainA.GetContext(), path.EndpointA.ClientID, header) if tc.expPass { suite.Require().NoError(err, tc.name) @@ -524,14 +522,15 @@ func (suite *TendermintTestSuite) TestUpdateState() { clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + tc.malleate() - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) if tc.expPass { - consensusHeights = clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) + consensusHeights = lightClientModule.UpdateState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientMessage) header, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) @@ -548,7 +547,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { suite.Require().Equal(expConsensusState, updatedConsensusState) } else { - consensusHeights = clientState.UpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, clientMessage) + consensusHeights = lightClientModule.UpdateState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientMessage) suite.Require().Empty(consensusHeights) consensusState, found := suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()))) @@ -895,16 +894,14 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) - tc.malleate() + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) - clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) + tc.malleate() - foundMisbehaviour := clientState.CheckForMisbehaviour( + foundMisbehaviour := lightClientModule.CheckForMisbehaviour( suite.chainA.GetContext(), - suite.chainA.App.AppCodec(), - clientStore, // pass in clientID prefixed clientStore + path.EndpointA.ClientID, clientMessage, ) @@ -943,13 +940,14 @@ func (suite *TendermintTestSuite) TestUpdateStateOnMisbehaviour() { err := path.EndpointA.CreateClient() suite.Require().NoError(err) + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.Route(path.EndpointA.ClientID) + suite.Require().True(found) + tc.malleate() - clientState, ok := path.EndpointA.GetClientState().(*ibctm.ClientState) - suite.Require().True(ok) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) - clientState.UpdateStateOnMisbehaviour(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, nil) + lightClientModule.UpdateStateOnMisbehaviour(suite.chainA.GetContext(), path.EndpointA.ClientID, nil) if tc.expPass { clientStateBz := clientStore.Get(host.ClientStateKey()) diff --git a/modules/light-clients/07-tendermint/upgrade_test.go b/modules/light-clients/07-tendermint/upgrade_test.go index cf71574c377..2f71d0ee29f 100644 --- a/modules/light-clients/07-tendermint/upgrade_test.go +++ b/modules/light-clients/07-tendermint/upgrade_test.go @@ -1,11 +1,14 @@ package tendermint_test import ( + "errors" + upgradetypes "cosmossdk.io/x/upgrade/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" + solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -13,7 +16,7 @@ import ( func (suite *TendermintTestSuite) TestVerifyUpgrade() { var ( newChainID string - upgradedClient *ibctm.ClientState + upgradedClient exported.ClientState upgradedConsState exported.ConsensusState lastHeight clienttypes.Height path *ibctesting.Path @@ -23,9 +26,9 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { ) testCases := []struct { - name string - setup func() - expPass bool + name string + setup func() + expErr error }{ { name: "successful upgrade", @@ -38,7 +41,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for test // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -51,13 +53,13 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: true, + expErr: nil, }, { name: "successful upgrade to same revision", setup: func() { - upgradedClient = ibctm.NewClientState(suite.chainB.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(clienttypes.ParseChainID(suite.chainB.ChainID), upgradedClient.LatestHeight.GetRevisionHeight()+10), commitmenttypes.GetSDKSpecs(), upgradePath) - upgradedClient = upgradedClient.ZeroCustomFields() + upgradedClient = ibctm.NewClientState(suite.chainB.ChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(clienttypes.ParseChainID(suite.chainB.ChainID), upgradedClient.(*ibctm.ClientState).LatestHeight.GetRevisionHeight()+10), commitmenttypes.GetSDKSpecs(), upgradePath) + upgradedClient = upgradedClient.(*ibctm.ClientState).ZeroCustomFields() upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -82,9 +84,48 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: true, + expErr: nil, + }, + { + name: "unsuccessful upgrade: upgrade path not set", + setup: func() { + suite.coordinator.CommitBlock(suite.chainB) + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) + suite.Require().True(found) + tmCs, ok := cs.(*ibctm.ClientState) + suite.Require().True(ok) + + // set upgrade path to empty + tmCs.UpgradePath = []string{} + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmCs) + + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + }, + expErr: clienttypes.ErrInvalidUpgradeClient, }, + { + name: "unsuccessful upgrade: upgrade consensus state must be tendermint consensus state", + setup: func() { + upgradedConsState = &solomachine.ConsensusState{} + + suite.coordinator.CommitBlock(suite.chainB) + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) + suite.Require().True(found) + tmCs, ok := cs.(*ibctm.ClientState) + suite.Require().True(ok) + + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + }, + expErr: clienttypes.ErrInvalidConsensus, + }, { name: "unsuccessful upgrade: upgrade height revision height is more than the current client revision height", setup: func() { @@ -109,7 +150,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: committed client does not have zeroed custom fields", @@ -140,7 +181,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: chain-specified parameters do not match committed client", @@ -149,14 +190,16 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for test + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.Require().NoError(err) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + suite.Require().NoError(err) // change upgradedClient client-specified parameters upgradedClient = ibctm.NewClientState("wrongchainID", ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), upgradePath) suite.coordinator.CommitBlock(suite.chainB) - err := path.EndpointA.UpdateClient() + err = path.EndpointA.UpdateClient() suite.Require().NoError(err) cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) @@ -167,20 +210,25 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: client-specified parameters do not match previous client", setup: func() { + // upgrade Height is at next block + lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + // zero custom fields and store in upgrade store - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for test + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + suite.Require().NoError(err) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + suite.Require().NoError(err) // change upgradedClient client-specified parameters upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, ubdPeriod, ubdPeriod+trustingPeriod, maxClockDrift+5, lastHeight, commitmenttypes.GetSDKSpecs(), upgradePath) suite.coordinator.CommitBlock(suite.chainB) - err := path.EndpointA.UpdateClient() + err = path.EndpointA.UpdateClient() suite.Require().NoError(err) cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) @@ -191,25 +239,24 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, + }, + { + name: "unsuccessful upgrade: upgrade client is not tendermint", + setup: func() { + upgradedClient = &solomachine.ClientState{} + }, + expErr: clienttypes.ErrInvalidClientType, }, { name: "unsuccessful upgrade: relayer-submitted consensus state does not match counterparty-committed consensus state", setup: func() { - // upgrade Height is at next block - lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) - - // zero custom fields and store in upgrade store - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for test - // change submitted upgradedConsensusState upgradedConsState = &ibctm.ConsensusState{ NextValidatorsHash: []byte("maliciousValidators"), } // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -222,13 +269,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: client proof unmarshal failed", setup: func() { - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for test - cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) tmCs, ok := cs.(*ibctm.ClientState) @@ -238,13 +283,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof = []byte("proof") }, - expPass: false, + expErr: errors.New("could not unmarshal client merkle proof"), }, { name: "unsuccessful upgrade: consensus state proof unmarshal failed", setup: func() { - suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test - cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) suite.Require().True(found) tmCs, ok := cs.(*ibctm.ClientState) @@ -254,7 +297,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedConsensusStateProof = []byte("proof") }, - expPass: false, + expErr: errors.New("could not unmarshal consensus state merkle proof"), }, { name: "unsuccessful upgrade: client proof verification failed", @@ -274,7 +317,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: consensus state proof verification failed", @@ -294,10 +337,10 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { - name: "unsuccessful upgrade: upgrade path is empty", + name: "unsuccessful upgrade: client state merkle path is empty", setup: func() { // upgrade Height is at next block lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) @@ -306,7 +349,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -319,13 +361,13 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) - // SetClientState with empty upgrade path + // SetClientState with empty string upgrade path tmClient, ok := cs.(*ibctm.ClientState) suite.Require().True(ok) tmClient.UpgradePath = []string{""} suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmClient) }, - expPass: false, + expErr: errors.New("client state proof failed"), }, { name: "unsuccessful upgrade: upgraded height is not greater than current height", @@ -337,7 +379,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -350,7 +391,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: errors.New("consensus state proof failed"), }, { name: "unsuccessful upgrade: consensus state for upgrade height cannot be found", @@ -362,7 +403,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -375,7 +415,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: client is expired", @@ -384,7 +424,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -400,7 +439,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: updated unbonding period is equal to trusting period", @@ -412,7 +451,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -425,7 +463,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, }, { name: "unsuccessful upgrade: final client is not valid", @@ -443,7 +481,6 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for testing // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -456,7 +493,39 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, - expPass: false, + expErr: commitmenttypes.ErrInvalidProof, + }, + { + name: "unsuccessful upgrade: consensus state not found for latest height", + setup: func() { + // upgrade Height is at next block + lastHeight = clienttypes.NewHeight(0, uint64(suite.chainB.GetContext().BlockHeight()+1)) + + // zero custom fields and store in upgrade store + suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) //nolint:errcheck // ignore error for test + suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) //nolint:errcheck // ignore error for test + + // commit upgrade store changes and update clients + + suite.coordinator.CommitBlock(suite.chainB) + err := path.EndpointA.UpdateClient() + suite.Require().NoError(err) + + cs, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID) + suite.Require().True(found) + tmCs, ok := cs.(*ibctm.ClientState) + suite.Require().True(ok) + + revisionHeight := tmCs.LatestHeight.GetRevisionHeight() + + // set latest height to a height where consensus state does not exist + tmCs.LatestHeight = clienttypes.NewHeight(tmCs.LatestHeight.GetRevisionNumber(), tmCs.LatestHeight.GetRevisionHeight()+5) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmCs) + + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), revisionHeight) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), revisionHeight) + }, + expErr: clienttypes.ErrConsensusStateNotFound, }, } @@ -479,7 +548,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.Require().NoError(err) upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), upgradePath) - upgradedClient = upgradedClient.ZeroCustomFields() + + if upgraded, ok := upgradedClient.(*ibctm.ClientState); ok { + upgradedClient = upgraded.ZeroCustomFields() + } + upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -496,7 +569,9 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) // Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient - upgradedClient = upgradedClient.ZeroCustomFields() + if upgraded, ok := upgradedClient.(*ibctm.ClientState); ok { + upgradedClient = upgraded.ZeroCustomFields() + } err = cs.VerifyUpgradeAndUpdateState( suite.chainA.GetContext(), @@ -508,7 +583,8 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { upgradedConsensusStateProof, ) - if tc.expPass { + expPass := tc.expErr == nil + if expPass { suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) clientState, ok := suite.chainA.GetClientState(path.EndpointA.ClientID).(*ibctm.ClientState) @@ -519,7 +595,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { suite.Require().NotNil(consensusState, "verify upgrade failed on valid case: %s", tc.name) suite.Require().True(found) } else { - suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) + suite.Require().ErrorContains(err, tc.expErr.Error(), "verify upgrade passed on invalid case: %s", tc.name) } }) }