github.com/fibonacci-chain/fbc@v0.0.0-20231124064014-c7636198c1e9/libs/ibc-go/modules/core/02-client/keeper/client_test.go (about)

     1  package keeper_test
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  	"math"
     7  	"time"
     8  
     9  	// tmtypes "github.com/tendermint/tendermint/types"
    10  
    11  	// 	upgradetypes "github.com/cosmos/cosmos-sdk/x/upgrade/types"
    12  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/02-client/types"
    13  	clienttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/02-client/types"
    14  	commitmenttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/23-commitment/types"
    15  	"github.com/fibonacci-chain/fbc/libs/ibc-go/modules/core/exported"
    16  	ibctmtypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/light-clients/07-tendermint/types"
    17  	localhosttypes "github.com/fibonacci-chain/fbc/libs/ibc-go/modules/light-clients/09-localhost/types"
    18  	ibctesting "github.com/fibonacci-chain/fbc/libs/ibc-go/testing"
    19  )
    20  
    21  const (
    22  	IBCHeight = math.MaxInt64 / 2
    23  )
    24  
    25  func (suite *KeeperTestSuite) TestCreateClient() {
    26  	cases := []struct {
    27  		msg         string
    28  		clientState exported.ClientState
    29  		expPass     bool
    30  	}{
    31  		{"success", ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false), true},
    32  		{"client type not supported", localhosttypes.NewClientState(testChainID, clienttypes.NewHeight(0, 1)), false},
    33  	}
    34  
    35  	for i, tc := range cases {
    36  
    37  		clientID, err := suite.keeper.CreateClient(suite.ctx, tc.clientState, suite.consensusState)
    38  		if tc.expPass {
    39  			suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.msg)
    40  			suite.Require().NotNil(clientID, "valid test case %d failed: %s", i, tc.msg)
    41  		} else {
    42  			suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.msg)
    43  			suite.Require().Equal("", clientID, "invalid test case %d passed: %s", i, tc.msg)
    44  		}
    45  	}
    46  }
    47  
    48  func (suite *KeeperTestSuite) TestUpdateClientTendermint() {
    49  	var (
    50  		path         *ibctesting.Path
    51  		updateHeader *ibctmtypes.Header
    52  	)
    53  
    54  	// Must create header creation functions since suite.header gets recreated on each test case
    55  	createFutureUpdateFn := func(trustedHeight clienttypes.Height) *ibctmtypes.Header {
    56  		header, err := suite.chainA.ConstructUpdateTMClientHeaderWithTrustedHeight(path.EndpointB.Chain, path.EndpointA.ClientID, trustedHeight)
    57  		suite.Require().NoError(err)
    58  		return header
    59  	}
    60  	createPastUpdateFn := func(fillHeight, trustedHeight clienttypes.Height) *ibctmtypes.Header {
    61  		consState, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, trustedHeight)
    62  		suite.Require().True(found)
    63  
    64  		return suite.chainB.CreateTMClientHeader(suite.chainB.ChainID(), int64(fillHeight.RevisionHeight), trustedHeight, consState.(*ibctmtypes.ConsensusState).Timestamp.Add(time.Second*5),
    65  			suite.chainB.Vals(), suite.chainB.Vals(), suite.chainB.Signers())
    66  	}
    67  
    68  	cases := []struct {
    69  		name      string
    70  		malleate  func()
    71  		expPass   bool
    72  		expFreeze bool
    73  	}{
    74  		{"valid update", func() {
    75  			clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState)
    76  			trustHeight := clientState.GetLatestHeight().(types.Height)
    77  
    78  			// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
    79  			path.EndpointA.UpdateClient()
    80  
    81  			updateHeader = createFutureUpdateFn(trustHeight)
    82  		}, true, false},
    83  		{"valid past update", func() {
    84  			clientState := path.EndpointA.GetClientState()
    85  			trustedHeight := clientState.GetLatestHeight().(types.Height)
    86  
    87  			currHeight := suite.chainB.CurrentHeader().Height
    88  			fillHeight := types.NewHeight(clientState.GetLatestHeight().GetRevisionNumber(), uint64(currHeight))
    89  
    90  			// commit a couple blocks to allow client to fill in gaps
    91  			suite.coordinator.CommitBlock(suite.chainB) // this height is not filled in yet
    92  			suite.coordinator.CommitBlock(suite.chainB) // this height is filled in by the update below
    93  
    94  			path.EndpointA.UpdateClient()
    95  
    96  			// ensure fill height not set
    97  			_, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, fillHeight)
    98  			suite.Require().False(found)
    99  
   100  			// updateHeader will fill in consensus state between prevConsState and suite.consState
   101  			// clientState should not be updated
   102  			updateHeader = createPastUpdateFn(fillHeight, trustedHeight)
   103  		}, true, false},
   104  		{"valid duplicate update", func() {
   105  			clientID := path.EndpointA.ClientID
   106  
   107  			height1 := types.NewHeight(0, 1)
   108  
   109  			// store previous consensus state
   110  			prevConsState := &ibctmtypes.ConsensusState{
   111  				Timestamp:          suite.past,
   112  				NextValidatorsHash: suite.chainB.Vals().Hash(IBCHeight),
   113  			}
   114  			suite.chainA.App().GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, height1, prevConsState)
   115  
   116  			height5 := types.NewHeight(0, 5)
   117  			// store next consensus state to check that trustedHeight does not need to be hightest consensus state before header height
   118  			nextConsState := &ibctmtypes.ConsensusState{
   119  				Timestamp:          suite.past.Add(time.Minute),
   120  				NextValidatorsHash: suite.chainB.Vals().Hash(IBCHeight),
   121  			}
   122  			suite.chainA.App().GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, height5, nextConsState)
   123  
   124  			height3 := types.NewHeight(0, 3)
   125  			// updateHeader will fill in consensus state between prevConsState and suite.consState
   126  			// clientState should not be updated
   127  			updateHeader = createPastUpdateFn(height3, height1)
   128  			// set updateHeader's consensus state in store to create duplicate UpdateClient scenario
   129  			suite.chainA.App().GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), clientID, updateHeader.GetHeight(), updateHeader.ConsensusState())
   130  		}, true, false},
   131  		{"client state not found", func() {
   132  			updateHeader = createFutureUpdateFn(path.EndpointA.GetClientState().GetLatestHeight().(types.Height))
   133  
   134  			path.EndpointA.ClientID = ibctesting.InvalidID
   135  		}, false, false},
   136  		{"consensus state not found", func() {
   137  			clientState := path.EndpointA.GetClientState()
   138  			tmClient, ok := clientState.(*ibctmtypes.ClientState)
   139  			suite.Require().True(ok)
   140  			tmClient.LatestHeight = tmClient.LatestHeight.Increment().(types.Height)
   141  
   142  			suite.chainA.App().GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientState)
   143  			updateHeader = createFutureUpdateFn(clientState.GetLatestHeight().(types.Height))
   144  		}, false, false},
   145  		{"client is not active", func() {
   146  			clientState := path.EndpointA.GetClientState().(*ibctmtypes.ClientState)
   147  			clientState.FrozenHeight = types.NewHeight(0, 1)
   148  			suite.chainA.App().GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientState)
   149  			updateHeader = createFutureUpdateFn(clientState.GetLatestHeight().(types.Height))
   150  		}, false, false},
   151  		{"invalid header", func() {
   152  			updateHeader = createFutureUpdateFn(path.EndpointA.GetClientState().GetLatestHeight().(types.Height))
   153  			updateHeader.TrustedHeight = updateHeader.TrustedHeight.Increment().(types.Height)
   154  		}, false, false},
   155  	}
   156  
   157  	for _, tc := range cases {
   158  		tc := tc
   159  		suite.Run(fmt.Sprintf("Case %s", tc.name), func() {
   160  			suite.SetupTest()
   161  			path = ibctesting.NewPath(suite.chainA, suite.chainB)
   162  			suite.coordinator.SetupClients(path)
   163  
   164  			tc.malleate()
   165  
   166  			var clientState exported.ClientState
   167  			if tc.expPass {
   168  				clientState = path.EndpointA.GetClientState()
   169  			}
   170  
   171  			err := suite.chainA.App().GetIBCKeeper().ClientKeeper.UpdateClient(suite.chainA.GetContext(), path.EndpointA.ClientID, updateHeader)
   172  
   173  			if tc.expPass {
   174  				suite.Require().NoError(err, err)
   175  
   176  				newClientState := path.EndpointA.GetClientState()
   177  
   178  				if tc.expFreeze {
   179  					suite.Require().True(!newClientState.(*ibctmtypes.ClientState).FrozenHeight.IsZero(), "client did not freeze after conflicting header was submitted to UpdateClient")
   180  				} else {
   181  					expConsensusState := &ibctmtypes.ConsensusState{
   182  						Timestamp:          updateHeader.GetTime(),
   183  						Root:               commitmenttypes.NewMerkleRoot(updateHeader.Header.GetAppHash()),
   184  						NextValidatorsHash: updateHeader.Header.NextValidatorsHash,
   185  					}
   186  
   187  					consensusState, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, updateHeader.GetHeight())
   188  					suite.Require().True(found)
   189  
   190  					// Determine if clientState should be updated or not
   191  					if updateHeader.GetHeight().GT(clientState.GetLatestHeight()) {
   192  						// Header Height is greater than clientState latest Height, clientState should be updated with header.GetHeight()
   193  						suite.Require().Equal(updateHeader.GetHeight(), newClientState.GetLatestHeight(), "clientstate height did not update")
   194  					} else {
   195  						// Update will add past consensus state, clientState should not be updated at all
   196  						suite.Require().Equal(clientState.GetLatestHeight(), newClientState.GetLatestHeight(), "client state height updated for past header")
   197  					}
   198  
   199  					suite.Require().NoError(err)
   200  					suite.Require().Equal(expConsensusState, consensusState, "consensus state should have been updated on case %s", tc.name)
   201  				}
   202  			} else {
   203  				suite.Require().Error(err)
   204  			}
   205  		})
   206  	}
   207  }
   208  
   209  func (suite *KeeperTestSuite) TestUpdateClientLocalhost() {
   210  	revision := types.ParseChainID(suite.chainA.ChainID())
   211  	chainACtx := suite.chainA.GetContext()
   212  	var localhostClient exported.ClientState = localhosttypes.NewClientState(suite.chainA.ChainID(), types.NewHeight(revision, uint64(chainACtx.BlockHeight())))
   213  
   214  	ctx := suite.chainA.GetContext().WithBlockHeight(chainACtx.BlockHeight() + 1)
   215  	err := suite.chainA.App().GetIBCKeeper().ClientKeeper.UpdateClient(ctx, exported.Localhost, nil)
   216  	suite.Require().NoError(err)
   217  
   218  	clientState, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientState(ctx, exported.Localhost)
   219  	suite.Require().True(found)
   220  	suite.Require().Equal(localhostClient.GetLatestHeight().(types.Height).Increment(), clientState.GetLatestHeight())
   221  }
   222  
   223  // todo add upgrade client
   224  func (suite *KeeperTestSuite) testUpgradeClient() {
   225  	//	var (
   226  	//		path                                        *ibctesting.Path
   227  	//		upgradedClient                              exported.ClientState
   228  	//		upgradedConsState                           exported.ConsensusState
   229  	//		lastHeight                                  exported.Height
   230  	//		proofUpgradedClient, proofUpgradedConsState []byte
   231  	//		upgradedClientBz, upgradedConsStateBz       []byte
   232  	//		err                                         error
   233  	//	)
   234  	//
   235  	//	testCases := []struct {
   236  	//		name    string
   237  	//		setup   func()
   238  	//		expPass bool
   239  	//	}{
   240  	//		{
   241  	//			name: "successful upgrade",
   242  	//			setup: func() {
   243  	//				tmpCtx := suite.chainB.GetContext()
   244  	//				// last Height is at next block
   245  	//				lastHeight = clienttypes.NewHeight(0, uint64(tmpCtx.BlockHeight()+1))
   246  	//
   247  	//				// zero custom fields and store in upgrade store
   248  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
   249  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
   250  	//
   251  	//				// commit upgrade store changes and update clients
   252  	//
   253  	//				suite.coordinator.CommitBlock(suite.chainB)
   254  	//				err := path.EndpointA.UpdateClient()
   255  	//				suite.Require().NoError(err)
   256  	//
   257  	//				cs, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID)
   258  	//				suite.Require().True(found)
   259  	//
   260  	//				proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   261  	//				proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   262  	//			},
   263  	//			expPass: true,
   264  	//		},
   265  	//		{
   266  	//			name: "client state not found",
   267  	//			setup: func() {
   268  	//				// last Height is at next block
   269  	//				tmpCtx := suite.chainB.GetContext()
   270  	//				lastHeight = clienttypes.NewHeight(0, uint64(tmpCtx.BlockHeight()+1))
   271  	//
   272  	//				// zero custom fields and store in upgrade store
   273  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
   274  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
   275  	//
   276  	//				// commit upgrade store changes and update clients
   277  	//
   278  	//				suite.coordinator.CommitBlock(suite.chainB)
   279  	//				err := path.EndpointA.UpdateClient()
   280  	//				suite.Require().NoError(err)
   281  	//
   282  	//				cs, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID)
   283  	//				suite.Require().True(found)
   284  	//
   285  	//				proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   286  	//				proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   287  	//
   288  	//				path.EndpointA.ClientID = "wrongclientid"
   289  	//			},
   290  	//			expPass: false,
   291  	//		},
   292  	//		{
   293  	//			name: "client state is not active",
   294  	//			setup: func() {
   295  	//				// client is frozen
   296  	//
   297  	//				tmpCtx := suite.chainB.GetContext()
   298  	//				// last Height is at next block
   299  	//				lastHeight = clienttypes.NewHeight(0, uint64(tmpCtx.BlockHeight()+1))
   300  	//
   301  	//				// zero custom fields and store in upgrade store
   302  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
   303  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
   304  	//
   305  	//				// commit upgrade store changes and update clients
   306  	//
   307  	//				suite.coordinator.CommitBlock(suite.chainB)
   308  	//				err := path.EndpointA.UpdateClient()
   309  	//				suite.Require().NoError(err)
   310  	//
   311  	//				cs, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID)
   312  	//				suite.Require().True(found)
   313  	//
   314  	//				proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   315  	//				proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   316  	//
   317  	//				// set frozen client in store
   318  	//				tmClient, ok := cs.(*ibctmtypes.ClientState)
   319  	//				suite.Require().True(ok)
   320  	//				tmClient.FrozenHeight = types.NewHeight(0, 1)
   321  	//				suite.chainA.App().GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, tmClient)
   322  	//			},
   323  	//			expPass: false,
   324  	//		},
   325  	//		{
   326  	//			name: "tendermint client VerifyUpgrade fails",
   327  	//			setup: func() {
   328  	//				// last Height is at next block
   329  	//				tmpCtx := suite.chainB.GetContext()
   330  	//				lastHeight = clienttypes.NewHeight(0, uint64(tmpCtx.BlockHeight()+1))
   331  	//
   332  	//				// zero custom fields and store in upgrade store
   333  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz)
   334  	//				suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz)
   335  	//
   336  	//				// change upgradedClient client-specified parameters
   337  	//				upgradedClient = ibctmtypes.NewClientState("wrongchainID", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, true, true)
   338  	//
   339  	//				suite.coordinator.CommitBlock(suite.chainB)
   340  	//				err := path.EndpointA.UpdateClient()
   341  	//				suite.Require().NoError(err)
   342  	//
   343  	//				cs, found := suite.chainA.App().GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID)
   344  	//				suite.Require().True(found)
   345  	//
   346  	//				proofUpgradedClient, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   347  	//				proofUpgradedConsState, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight())
   348  	//			},
   349  	//			expPass: false,
   350  	//		},
   351  	//	}
   352  	//
   353  	//	for _, tc := range testCases {
   354  	//		tc := tc
   355  	//		path = ibctesting.NewPath(suite.chainA, suite.chainB)
   356  	//		suite.coordinator.SetupClients(path)
   357  	//		upgradedClient = ibctmtypes.NewClientState("newChainId-1", ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, newClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   358  	//		upgradedClient = upgradedClient.ZeroCustomFields()
   359  	//		upgradedClientBz, err = types.MarshalClientState(suite.chainA.App().AppCodec(), upgradedClient)
   360  	//		suite.Require().NoError(err)
   361  	//
   362  	//		upgradedConsState = &ibctmtypes.ConsensusState{
   363  	//			NextValidatorsHash: []byte("nextValsHash"),
   364  	//		}
   365  	//		upgradedConsStateBz, err = types.MarshalConsensusState(suite.chainA.App().AppCodec(), upgradedConsState)
   366  	//		suite.Require().NoError(err)
   367  	//
   368  	//		tc.setup()
   369  	//
   370  	//		// Call ZeroCustomFields on upgraded clients to clear any client-chosen parameters in test-case upgradedClient
   371  	//		upgradedClient = upgradedClient.ZeroCustomFields()
   372  	//
   373  	//		err = suite.chainA.App().GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClient, upgradedConsState, proofUpgradedClient, proofUpgradedConsState)
   374  	//
   375  	//		if tc.expPass {
   376  	//			suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name)
   377  	//		} else {
   378  	//			suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name)
   379  	//		}
   380  	//	}
   381  	//
   382  	//}
   383  	//
   384  	//func (suite *KeeperTestSuite) TestCheckMisbehaviourAndUpdateState() {
   385  	//	var (
   386  	//		clientID string
   387  	//		err      error
   388  	//	)
   389  	//
   390  	//	altPrivVal := ibctestingmock.NewPV()
   391  	//	altPubKey, err := altPrivVal.GetPubKey()
   392  	//	suite.Require().NoError(err)
   393  	//	altVal := tmtypes.NewValidator(altPubKey, 4)
   394  	//
   395  	//	// Set valSet here with suite.valSet so it doesn't get reset on each testcase
   396  	//	valSet := suite.valSet
   397  	//	valsHash := valSet.Hash()
   398  	//
   399  	//	// Create bothValSet with both suite validator and altVal
   400  	//	bothValSet := tmtypes.NewValidatorSet(append(suite.valSet.Validators, altVal))
   401  	//	bothValsHash := bothValSet.Hash()
   402  	//	// Create alternative validator set with only altVal
   403  	//	altValSet := tmtypes.NewValidatorSet([]*tmtypes.Validator{altVal})
   404  	//
   405  	//	// Create signer array and ensure it is in same order as bothValSet
   406  	//	_, suiteVal := suite.valSet.GetByIndex(0)
   407  	//	bothSigners := ibctesting.CreateSortedSignerArray(altPrivVal, suite.privVal, altVal, suiteVal)
   408  	//
   409  	//	altSigners := []tmtypes.PrivValidator{altPrivVal}
   410  	//
   411  	//	// Create valid Misbehaviour by making a duplicate header that signs over different block time
   412  	//	altTime := suite.ctx.BlockTime().Add(time.Minute)
   413  	//
   414  	//	heightPlus3 := types.NewHeight(0, height+3)
   415  	//	heightPlus5 := types.NewHeight(0, height+5)
   416  	//
   417  	//	testCases := []struct {
   418  	//		name         string
   419  	//		misbehaviour *ibctmtypes.Misbehaviour
   420  	//		malleate     func() error
   421  	//		expPass      bool
   422  	//	}{
   423  	//		{
   424  	//			"trusting period misbehavior should pass",
   425  	//			&ibctmtypes.Misbehaviour{
   426  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
   427  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
   428  	//				ClientId: clientID,
   429  	//			},
   430  	//			func() error {
   431  	//				suite.consensusState.NextValidatorsHash = bothValsHash
   432  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   433  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   434  	//
   435  	//				return err
   436  	//			},
   437  	//			true,
   438  	//		},
   439  	//		{
   440  	//			"time misbehavior should pass",
   441  	//			&ibctmtypes.Misbehaviour{
   442  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+5), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
   443  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
   444  	//				ClientId: clientID,
   445  	//			},
   446  	//			func() error {
   447  	//				suite.consensusState.NextValidatorsHash = bothValsHash
   448  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   449  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   450  	//
   451  	//				return err
   452  	//			},
   453  	//			true,
   454  	//		},
   455  	//		{
   456  	//			"misbehavior at later height should pass",
   457  	//			&ibctmtypes.Misbehaviour{
   458  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, valSet, bothSigners),
   459  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
   460  	//				ClientId: clientID,
   461  	//			},
   462  	//			func() error {
   463  	//				suite.consensusState.NextValidatorsHash = valsHash
   464  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   465  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   466  	//
   467  	//				// store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height
   468  	//				intermediateConsState := &ibctmtypes.ConsensusState{
   469  	//					Timestamp:          suite.now.Add(time.Minute),
   470  	//					NextValidatorsHash: suite.chainB.Vals().Hash(),
   471  	//				}
   472  	//				suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState)
   473  	//
   474  	//				clientState.LatestHeight = heightPlus3
   475  	//				suite.keeper.SetClientState(suite.ctx, clientID, clientState)
   476  	//
   477  	//				return err
   478  	//			},
   479  	//			true,
   480  	//		},
   481  	//		{
   482  	//			"misbehavior at later height with different trusted heights should pass",
   483  	//			&ibctmtypes.Misbehaviour{
   484  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, valSet, bothSigners),
   485  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
   486  	//				ClientId: clientID,
   487  	//			},
   488  	//			func() error {
   489  	//				suite.consensusState.NextValidatorsHash = valsHash
   490  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   491  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   492  	//
   493  	//				// store trusted consensus state for Header2
   494  	//				intermediateConsState := &ibctmtypes.ConsensusState{
   495  	//					Timestamp:          suite.now.Add(time.Minute),
   496  	//					NextValidatorsHash: bothValsHash,
   497  	//				}
   498  	//				suite.keeper.SetClientConsensusState(suite.ctx, clientID, heightPlus3, intermediateConsState)
   499  	//
   500  	//				clientState.LatestHeight = heightPlus3
   501  	//				suite.keeper.SetClientState(suite.ctx, clientID, clientState)
   502  	//
   503  	//				return err
   504  	//			},
   505  	//			true,
   506  	//		},
   507  	//		{
   508  	//			"misbehavior ValidateBasic fails: misbehaviour height is at same height as trusted height",
   509  	//			&ibctmtypes.Misbehaviour{
   510  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
   511  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
   512  	//				ClientId: clientID,
   513  	//			},
   514  	//			func() error {
   515  	//				suite.consensusState.NextValidatorsHash = bothValsHash
   516  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   517  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   518  	//
   519  	//				return err
   520  	//			},
   521  	//			false,
   522  	//		},
   523  	//		{
   524  	//			"trusted ConsensusState1 not found",
   525  	//			&ibctmtypes.Misbehaviour{
   526  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, altTime, bothValSet, bothValSet, bothSigners),
   527  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, valSet, bothSigners),
   528  	//				ClientId: clientID,
   529  	//			},
   530  	//			func() error {
   531  	//				suite.consensusState.NextValidatorsHash = valsHash
   532  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   533  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   534  	//				// intermediate consensus state at height + 3 is not created
   535  	//				return err
   536  	//			},
   537  	//			false,
   538  	//		},
   539  	//		{
   540  	//			"trusted ConsensusState2 not found",
   541  	//			&ibctmtypes.Misbehaviour{
   542  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), testClientHeight, altTime, bothValSet, valSet, bothSigners),
   543  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(heightPlus5.RevisionHeight+1), heightPlus3, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
   544  	//				ClientId: clientID,
   545  	//			},
   546  	//			func() error {
   547  	//				suite.consensusState.NextValidatorsHash = valsHash
   548  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   549  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   550  	//				// intermediate consensus state at height + 3 is not created
   551  	//				return err
   552  	//			},
   553  	//			false,
   554  	//		},
   555  	//		{
   556  	//			"client state not found",
   557  	//			&ibctmtypes.Misbehaviour{},
   558  	//			func() error { return nil },
   559  	//			false,
   560  	//		},
   561  	//		{
   562  	//			"client already is not active - client is frozen",
   563  	//			&ibctmtypes.Misbehaviour{
   564  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
   565  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), bothValSet, bothValSet, bothSigners),
   566  	//				ClientId: clientID,
   567  	//			},
   568  	//			func() error {
   569  	//				suite.consensusState.NextValidatorsHash = bothValsHash
   570  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   571  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   572  	//
   573  	//				clientState.FrozenHeight = types.NewHeight(0, 1)
   574  	//				suite.keeper.SetClientState(suite.ctx, clientID, clientState)
   575  	//
   576  	//				return err
   577  	//			},
   578  	//			false,
   579  	//		},
   580  	//		{
   581  	//			"misbehaviour check failed",
   582  	//			&ibctmtypes.Misbehaviour{
   583  	//				Header1:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, altTime, bothValSet, bothValSet, bothSigners),
   584  	//				Header2:  suite.chainA.CreateTMClientHeader(testChainID, int64(testClientHeight.RevisionHeight+1), testClientHeight, suite.ctx.BlockTime(), altValSet, bothValSet, altSigners),
   585  	//				ClientId: clientID,
   586  	//			},
   587  	//			func() error {
   588  	//				clientState := ibctmtypes.NewClientState(testChainID, ibctmtypes.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath, false, false)
   589  	//				if err != nil {
   590  	//					return err
   591  	//				}
   592  	//				clientID, err = suite.keeper.CreateClient(suite.ctx, clientState, suite.consensusState)
   593  	//
   594  	//				return err
   595  	//			},
   596  	//			false,
   597  	//		},
   598  	//	}
   599  	//
   600  	//	for i, tc := range testCases {
   601  	//		tc := tc
   602  	//		i := i
   603  	//
   604  	//		suite.Run(tc.name, func() {
   605  	//			suite.SetupTest()       // reset
   606  	//			clientID = testClientID // must be explicitly changed
   607  	//
   608  	//			err := tc.malleate()
   609  	//			suite.Require().NoError(err)
   610  	//
   611  	//			tc.misbehaviour.ClientId = clientID
   612  	//
   613  	//			err = suite.keeper.CheckMisbehaviourAndUpdateState(suite.ctx, tc.misbehaviour)
   614  	//
   615  	//			if tc.expPass {
   616  	//				suite.Require().NoError(err, "valid test case %d failed: %s", i, tc.name)
   617  	//
   618  	//				clientState, found := suite.keeper.GetClientState(suite.ctx, clientID)
   619  	//				suite.Require().True(found, "valid test case %d failed: %s", i, tc.name)
   620  	//				suite.Require().True(!clientState.(*ibctmtypes.ClientState).FrozenHeight.IsZero(), "valid test case %d failed: %s", i, tc.name)
   621  	//			} else {
   622  	//				suite.Require().Error(err, "invalid test case %d passed: %s", i, tc.name)
   623  	//			}
   624  	//		})
   625  	//	}
   626  }
   627  
   628  func (suite *KeeperTestSuite) TestUpdateClientEventEmission() {
   629  	path := ibctesting.NewPath(suite.chainA, suite.chainB)
   630  	suite.coordinator.SetupClients(path)
   631  	header, err := suite.chainA.ConstructUpdateTMClientHeader(suite.chainB, path.EndpointA.ClientID)
   632  	suite.Require().NoError(err)
   633  
   634  	msg, err := clienttypes.NewMsgUpdateClient(
   635  		path.EndpointA.ClientID, header,
   636  		suite.chainA.SenderAccount().GetAddress(),
   637  	)
   638  
   639  	result, err := suite.chainA.SendMsgs(msg)
   640  	suite.Require().NoError(err)
   641  	// first event type is "message", followed by 3 "tx" events in ante
   642  	//todo why 5, 2nd is update
   643  	updateEvent := result.Events[1]
   644  	suite.Require().Equal(clienttypes.EventTypeUpdateClient, updateEvent.Type)
   645  
   646  	// use a boolean to ensure the update event contains the header
   647  	contains := false
   648  	for _, attr := range updateEvent.Attributes {
   649  		if string(attr.Key) == clienttypes.AttributeKeyHeader {
   650  			contains = true
   651  
   652  			bz, err := hex.DecodeString(string(attr.Value))
   653  			suite.Require().NoError(err)
   654  
   655  			// emittedHeader, err := types.UnmarshalHeader(suite.chainA.App().AppCodec(), bz)
   656  			emittedHeader, err := types.UnmarshalHeader(suite.chainA.App().AppCodec().GetProtocMarshal(), bz)
   657  			suite.Require().NoError(err)
   658  			suite.Require().Equal(header, emittedHeader)
   659  		}
   660  
   661  	}
   662  	suite.Require().True(contains)
   663  
   664  }