From 60366bc04ede7d1c39e85cdd61f64e3db0696364 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 31 Jan 2023 14:01:45 +0100 Subject: [PATCH 1/4] adding localhost AppModuleBasic to app.go. adding localhost client to InitGenesis. Fixing update localhost client --- modules/core/02-client/abci.go | 4 ++-- modules/core/02-client/genesis.go | 4 ++++ .../core/02-client/keeper/grpc_query_test.go | 11 ++++++--- modules/core/02-client/keeper/keeper.go | 12 ++++++++++ modules/core/02-client/keeper/keeper_test.go | 23 ++++++++++++++----- modules/core/03-connection/keeper/keeper.go | 19 --------------- .../09-localhost/client_state.go | 9 +++++++- testing/simapp/app.go | 2 ++ 8 files changed, 53 insertions(+), 31 deletions(-) diff --git a/modules/core/02-client/abci.go b/modules/core/02-client/abci.go index 7f2e1b72aef..66c092fa0d2 100644 --- a/modules/core/02-client/abci.go +++ b/modules/core/02-client/abci.go @@ -34,7 +34,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { } // update the localhost client with the latest block height - if err := k.UpdateClient(ctx, exported.Localhost, nil); err != nil { - k.Logger(ctx).Error(err.Error()) + if clientState, found := k.GetClientState(ctx, exported.Localhost); found { + k.UpdateLocalhostClient(ctx, clientState) } } diff --git a/modules/core/02-client/genesis.go b/modules/core/02-client/genesis.go index aae41d9ae5a..269eb7f6bd7 100644 --- a/modules/core/02-client/genesis.go +++ b/modules/core/02-client/genesis.go @@ -46,6 +46,10 @@ func InitGenesis(ctx sdk.Context, k keeper.Keeper, gs types.GenesisState) { } k.SetNextClientSequence(ctx, gs.NextClientSequence) + + if err := k.CreateLocalhostClient(ctx); err != nil { + panic(fmt.Sprintf("failed to initialise localhost client: %s", err.Error())) + } } // ExportGenesis returns the ibc client submodule's exported genesis. diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index aa4d12265ab..a10e8903dd1 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -111,13 +111,17 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { { "empty pagination", func() { + localhost := types.NewIdentifiedClientState(exported.Localhost, suite.chainA.GetClientState(exported.Localhost)) + expClientStates = types.IdentifiedClientStates{localhost} req = &types.QueryClientStatesRequest{} }, true, }, { - "success, no results", + "success, only localhost", func() { + localhost := types.NewIdentifiedClientState(exported.Localhost, suite.chainA.GetClientState(exported.Localhost)) + expClientStates = types.IdentifiedClientStates{localhost} req = &types.QueryClientStatesRequest{ Pagination: &query.PageRequest{ Limit: 3, @@ -139,11 +143,12 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { clientStateA1 := path1.EndpointA.GetClientState() clientStateA2 := path2.EndpointA.GetClientState() + localhost := types.NewIdentifiedClientState(exported.Localhost, suite.chainA.GetClientState(exported.Localhost)) idcs := types.NewIdentifiedClientState(path1.EndpointA.ClientID, clientStateA1) idcs2 := types.NewIdentifiedClientState(path2.EndpointA.ClientID, clientStateA2) // order is sorted by client id - expClientStates = types.IdentifiedClientStates{idcs, idcs2}.Sort() + expClientStates = types.IdentifiedClientStates{localhost, idcs, idcs2}.Sort() req = &types.QueryClientStatesRequest{ Pagination: &query.PageRequest{ Limit: 20, @@ -158,10 +163,10 @@ func (suite *KeeperTestSuite) TestQueryClientStates() { for _, tc := range testCases { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset + tc.malleate() ctx := sdk.WrapSDKContext(suite.chainA.GetContext()) - res, err := suite.chainA.QueryServer.ClientStates(ctx, req) if tc.expPass { diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 3342e6b402d..85851e6cad8 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -20,6 +20,7 @@ import ( host "github.com/cosmos/ibc-go/v7/modules/core/24-host" "github.com/cosmos/ibc-go/v7/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ) // Keeper represents a type that grants read and write permissions to any client @@ -53,6 +54,17 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+exported.ModuleName+"/"+types.SubModuleName) } +// CreateLocalhostClient initialises the 09-localhost client state and sets it in state. +func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { + var localhostClient localhost.ClientState + return localhostClient.Initialize(ctx, k.cdc, k.ClientStore(ctx, exported.Localhost), nil) +} + +// UpdateLocalhostClient updates the 09-localhost client to the latest block height and chain ID. +func (k Keeper) UpdateLocalhostClient(ctx sdk.Context, clientState exported.ClientState) []exported.Height { + return clientState.UpdateState(ctx, k.cdc, k.ClientStore(ctx, exported.Localhost), nil) +} + // GenerateClientIdentifier returns the next client identifier. func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) string { nextClientSeq := k.GetNextClientSequence(ctx) diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 8e5cac289d4..a995b56d1a5 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -21,6 +21,7 @@ import ( "github.com/cosmos/ibc-go/v7/modules/core/exported" solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ibctesting "github.com/cosmos/ibc-go/v7/testing" ibctestingmock "github.com/cosmos/ibc-go/v7/testing/mock" "github.com/cosmos/ibc-go/v7/testing/simapp" @@ -236,9 +237,10 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() { func (suite KeeperTestSuite) TestGetAllGenesisClients() { //nolint:govet // this is a test, we are okay with copying locks clientIDs := []string{ - testClientID2, testClientID3, testClientID, + exported.Localhost, testClientID2, testClientID3, testClientID, } expClients := []exported.ClientState{ + localhost.NewClientState(suite.chainA.ChainID, types.GetSelfHeight(suite.chainA.GetContext())), ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, types.ZeroHeight(), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath), @@ -418,22 +420,31 @@ func (suite KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this testCases := []struct { name string prefix []byte - expClientIDs []string + expClientIDs func() []string }{ { "all clientIDs", nil, - append(expSMClientIDs, expTMClientIDs...), + func() []string { + allClientIDs := []string{exported.Localhost} + allClientIDs = append(allClientIDs, expSMClientIDs...) + allClientIDs = append(allClientIDs, expTMClientIDs...) + return allClientIDs + }, }, { "tendermint clientIDs", []byte(exported.Tendermint), - expTMClientIDs, + func() []string { + return expTMClientIDs + }, }, { "solo machine clientIDs", []byte(exported.Solomachine), - expSMClientIDs, + func() []string { + return expSMClientIDs + }, }, } @@ -446,7 +457,7 @@ func (suite KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this return false }) - suite.Require().Equal(tc.expClientIDs, clientIDs) + suite.Require().ElementsMatch(tc.expClientIDs(), clientIDs) }) } } diff --git a/modules/core/03-connection/keeper/keeper.go b/modules/core/03-connection/keeper/keeper.go index 5b5266db3c5..3681f957aae 100644 --- a/modules/core/03-connection/keeper/keeper.go +++ b/modules/core/03-connection/keeper/keeper.go @@ -41,25 +41,6 @@ func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, paramSpace paramt } } -// EnableLocalhost is called by init genesis or an upgrade handler? -// EnableLocalhost sets the localhost loopback connection end in store -// NOTES: -// - channel handshake code can remain the same -// - packet handlers require access to a ClientState and use the following methods: -// - Status() -// - GetLatestHeight() -// - GetTimestampAtHeight() -// - VerifyMembership -// - VerifyNonMembership -func (k Keeper) EnableLocalhost(ctx sdk.Context) { - counterparty := types.NewCounterparty(exported.Localhost, types.LocalhostID, commitmenttypes.NewMerklePrefix(k.GetCommitmentPrefix().Bytes())) - connectionEnd := types.NewConnectionEnd(types.OPEN, exported.Localhost, counterparty, types.ExportedVersionsToProto(types.GetCompatibleVersions()), 0) - - store := ctx.KVStore(k.storeKey) - bz := k.cdc.MustMarshal(&connectionEnd) - store.Set(host.ConnectionKey(types.LocalhostID), bz) -} - // Logger returns a module-specific logger. func (k Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+exported.ModuleName+"/"+types.SubModuleName) diff --git a/modules/light-clients/09-localhost/client_state.go b/modules/light-clients/09-localhost/client_state.go index 859ccb1ac05..5e3d943af1f 100644 --- a/modules/light-clients/09-localhost/client_state.go +++ b/modules/light-clients/09-localhost/client_state.go @@ -62,11 +62,18 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState { } // Initialize ensures that initial consensus state for localhost is nil. -func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, consState exported.ConsensusState) error { +func (cs ClientState) Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error { if consState != nil { return sdkerrors.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") } + clientState := ClientState{ + ChainId: ctx.ChainID(), + LatestHeight: clienttypes.NewHeight(clienttypes.ParseChainID(ctx.ChainID()), uint64(ctx.BlockHeight())), + } + + clientStore.Set([]byte(host.KeyClientState), clienttypes.MustMarshalClientState(cdc, &clientState)) + return nil } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 6ed2411f9cd..d84e8fa6a06 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -114,6 +114,7 @@ import ( ibckeeper "github.com/cosmos/ibc-go/v7/modules/core/keeper" solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine" ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint" + localhost "github.com/cosmos/ibc-go/v7/modules/light-clients/09-localhost" ibcmock "github.com/cosmos/ibc-go/v7/testing/mock" simappparams "github.com/cosmos/ibc-go/v7/testing/simapp/params" simappupgrades "github.com/cosmos/ibc-go/v7/testing/simapp/upgrades" @@ -159,6 +160,7 @@ var ( slashing.AppModuleBasic{}, ibc.AppModuleBasic{}, ibctm.AppModuleBasic{}, + localhost.AppModuleBasic{}, solomachine.AppModuleBasic{}, feegrantmodule.AppModuleBasic{}, upgrade.AppModuleBasic{}, From fa7860fe2e72448b46cc09c2a2c3e34d694185f9 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 31 Jan 2023 14:07:31 +0100 Subject: [PATCH 2/4] renmaing variable --- modules/core/02-client/keeper/keeper.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 85851e6cad8..00fb32ad1ed 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -56,8 +56,8 @@ func (k Keeper) Logger(ctx sdk.Context) log.Logger { // CreateLocalhostClient initialises the 09-localhost client state and sets it in state. func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - var localhostClient localhost.ClientState - return localhostClient.Initialize(ctx, k.cdc, k.ClientStore(ctx, exported.Localhost), nil) + var clientState localhost.ClientState + return clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, exported.Localhost), nil) } // UpdateLocalhostClient updates the 09-localhost client to the latest block height and chain ID. From 58901137354883cce09b65f0804429cc242d348f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 31 Jan 2023 14:35:54 +0100 Subject: [PATCH 3/4] adding migration handler for enabling localhost client --- modules/core/02-client/keeper/migrations.go | 8 +++++- .../migrations/v7/expected_keepers.go | 1 + .../core/02-client/migrations/v7/localhost.go | 10 +++++++ .../02-client/migrations/v7/localhost_test.go | 26 +++++++++++++++++++ modules/core/module.go | 12 ++++++++- 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 modules/core/02-client/migrations/v7/localhost.go create mode 100644 modules/core/02-client/migrations/v7/localhost_test.go diff --git a/modules/core/02-client/keeper/migrations.go b/modules/core/02-client/keeper/migrations.go index ad3587ae901..b8290133042 100644 --- a/modules/core/02-client/keeper/migrations.go +++ b/modules/core/02-client/keeper/migrations.go @@ -16,7 +16,7 @@ func NewMigrator(keeper Keeper) Migrator { return Migrator{keeper: keeper} } -// Migrate2to3 migrates from version 2 to 3. +// Migrate2to3 migrates from consensus version 2 to 3. // This migration // - migrates solo machine client states from v2 to v3 protobuf definition // - prunes solo machine consensus states @@ -25,3 +25,9 @@ func NewMigrator(keeper Keeper) Migrator { func (m Migrator) Migrate2to3(ctx sdk.Context) error { return v7.MigrateStore(ctx, m.keeper.storeKey, m.keeper.cdc, m.keeper) } + +// Migrate3to4 migrates from consensus version 3 to 4. +// This migration enables the localhost client. +func (m Migrator) Migrate3to4(ctx sdk.Context) error { + return v7.MigrateLocalhostClient(ctx, m.keeper) +} diff --git a/modules/core/02-client/migrations/v7/expected_keepers.go b/modules/core/02-client/migrations/v7/expected_keepers.go index 6d424cc0370..f36be5fabe2 100644 --- a/modules/core/02-client/migrations/v7/expected_keepers.go +++ b/modules/core/02-client/migrations/v7/expected_keepers.go @@ -11,4 +11,5 @@ type ClientKeeper interface { GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) SetClientState(ctx sdk.Context, clientID string, clientState exported.ClientState) ClientStore(ctx sdk.Context, clientID string) sdk.KVStore + CreateLocalhostClient(ctx sdk.Context) error } diff --git a/modules/core/02-client/migrations/v7/localhost.go b/modules/core/02-client/migrations/v7/localhost.go new file mode 100644 index 00000000000..49709b9db9f --- /dev/null +++ b/modules/core/02-client/migrations/v7/localhost.go @@ -0,0 +1,10 @@ +package v7 + +import ( + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// MigrateLocalhostClient initialises the 09-localhost client state and sets it in state. +func MigrateLocalhostClient(ctx sdk.Context, clientKeeper ClientKeeper) error { + return clientKeeper.CreateLocalhostClient(ctx) +} diff --git a/modules/core/02-client/migrations/v7/localhost_test.go b/modules/core/02-client/migrations/v7/localhost_test.go new file mode 100644 index 00000000000..982641f42d7 --- /dev/null +++ b/modules/core/02-client/migrations/v7/localhost_test.go @@ -0,0 +1,26 @@ +package v7_test + +import ( + v7 "github.com/cosmos/ibc-go/v7/modules/core/02-client/migrations/v7" + host "github.com/cosmos/ibc-go/v7/modules/core/24-host" + "github.com/cosmos/ibc-go/v7/modules/core/exported" +) + +func (suite *MigrationsV7TestSuite) TestMigrateLocalhostClient() { + suite.SetupTest() + + // note: explicitly remove the localhost client before running migration handler + clientStore := suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), exported.Localhost) + clientStore.Delete(host.ClientStateKey()) + + clientState, found := suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), exported.Localhost) + suite.Require().False(found) + suite.Require().Nil(clientState) + + err := v7.MigrateLocalhostClient(suite.chainA.GetContext(), suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper) + suite.Require().NoError(err) + + clientState, found = suite.chainA.GetSimApp().GetIBCKeeper().ClientKeeper.GetClientState(suite.chainA.GetContext(), exported.Localhost) + suite.Require().True(found) + suite.Require().NotNil(clientState) +} diff --git a/modules/core/module.go b/modules/core/module.go index 9171d121986..15e901caa2d 100644 --- a/modules/core/module.go +++ b/modules/core/module.go @@ -131,7 +131,17 @@ func (am AppModule) RegisterServices(cfg module.Configurator) { } connectionMigrator := connectionkeeper.NewMigrator(am.keeper.ConnectionKeeper) - if err := cfg.RegisterMigration(exported.ModuleName, 3, connectionMigrator.Migrate3to4); err != nil { + if err := cfg.RegisterMigration(exported.ModuleName, 3, func(ctx sdk.Context) error { + if err := connectionMigrator.Migrate3to4(ctx); err != nil { + return err + } + + if err := clientMigrator.Migrate3to4(ctx); err != nil { + return err + } + + return nil + }); err != nil { panic(err) } } From 598fa146812723ac2e500fe203948c9f30a2639a Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 31 Jan 2023 14:49:21 +0100 Subject: [PATCH 4/4] updating to use clienttypes.GetSelfHeight() --- modules/light-clients/09-localhost/client_state.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/light-clients/09-localhost/client_state.go b/modules/light-clients/09-localhost/client_state.go index 5e3d943af1f..06dd4e8fd38 100644 --- a/modules/light-clients/09-localhost/client_state.go +++ b/modules/light-clients/09-localhost/client_state.go @@ -69,7 +69,7 @@ func (cs ClientState) Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientS clientState := ClientState{ ChainId: ctx.ChainID(), - LatestHeight: clienttypes.NewHeight(clienttypes.ParseChainID(ctx.ChainID()), uint64(ctx.BlockHeight())), + LatestHeight: clienttypes.GetSelfHeight(ctx), } clientStore.Set([]byte(host.KeyClientState), clienttypes.MustMarshalClientState(cdc, &clientState)) @@ -151,7 +151,7 @@ func (cs ClientState) UpdateStateOnMisbehaviour(_ sdk.Context, _ codec.BinaryCod // UpdateState updates and stores as necessary any associated information for an IBC client, such as the ClientState and corresponding ConsensusState. // Upon successful update, a list of consensus heights is returned. It assumes the ClientMessage has already been verified. func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg exported.ClientMessage) []exported.Height { - height := clienttypes.NewHeight(clienttypes.ParseChainID(ctx.ChainID()), uint64(ctx.BlockHeight())) + height := clienttypes.GetSelfHeight(ctx) clientState := NewClientState(ctx.ChainID(), height) clientStore.Set([]byte(host.KeyClientState), clienttypes.MustMarshalClientState(cdc, clientState))