From c459971ab0188723f8b55f26eaa9438cf9a1996a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 29 Jan 2024 16:30:51 +0100 Subject: [PATCH 01/74] refactor: add initial light client module interface --- modules/core/exported/client.go | 80 +++++++++++++++++++ .../07-tendermint/light_client_module.go | 33 ++++++++ 2 files changed, 113 insertions(+) create mode 100644 modules/light-clients/07-tendermint/light_client_module.go diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index fec1564c4c3..9f2bb0903e7 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -44,6 +44,86 @@ const ( Unauthorized Status = "Unauthorized" ) +type LightClientModule interface { + // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the + // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. + Initialize(ctx sdk.Context, clientID string, clientState, consensusState []byte) error + + // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. + // It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour + // will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned + // if the ClientMessage fails to verify. + VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg ClientMessage) error + + // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage + // has already been verified. + CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg ClientMessage) bool + + // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified + UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg ClientMessage) + + // 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. + UpdateState(ctx sdk.Context, clientID string, clientMsg ClientMessage) []Height // TODO: change to concrete type + + // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. + // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). + VerifyMembership( + ctx sdk.Context, + clientID string, + height Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path Path, // TODO: change to conrete type + value []byte, + ) error + + // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. + // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). + VerifyNonMembership( + ctx sdk.Context, + clientID string, + height Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path Path, // TODO: change to conrete type + ) error + + // Status must return the status of the client. Only Active clients are allowed to process packets. + Status(ctx sdk.Context, clientID string) Status + + // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. + TimestampAtHeight( + ctx sdk.Context, + clientID string, + height Height, // TODO: change to concrete type + ) (uint64, error) + + // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. + // The light client must set the updated client and consensus states within the clientStore for the subject client. + // DEPRECATED: will be removed as performs internal functionality + RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error + + // Upgrade functions + // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last + // height committed by the current revision. Clients are responsible for ensuring that the planned last + // height of the current revision is somehow encoded in the proof verification process. + // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty + // may be cancelled or modified before the last planned height. + // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. + // DEPRECATED: will be removed as performs internal functionality + VerifyUpgradeAndUpdateState( + ctx sdk.Context, + clientID string, + newClient []byte, + newConsState []byte, + upgradeClientProof, + upgradeConsensusStateProof []byte, + ) error +} + // ClientState defines the required common functions for light clients. type ClientState interface { proto.Message diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go new file mode 100644 index 00000000000..44cc3ddd1ee --- /dev/null +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -0,0 +1,33 @@ +package tendermint + +import ( + errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +type LightClientModule struct { + cdc codec.BinaryCodec + prefixStoreKey storetypes.StoreKey +} + +// Initialize checks that the initial consensus state is an 07-tendermint consensus state and +// sets the client state, consensus state and associated metadata in the provided client store. +func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID, clientState conensusState []byte) error { + // validate args + // - client id + // client/consensus state if len == 0 + + // unpack client/consensus states + + // get store key + lcm.getStoreKey(clientID) + + return clientState.Initialize(ctx, lcm.cdc, storeKey, consensusState) +} + From e44bfc17c1cf7e73ea44e3ee105bff01f1b96b08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 29 Jan 2024 17:49:58 +0100 Subject: [PATCH 02/74] wip: add boiler plate light client module for tendermint client --- .../07-tendermint/keeper/keeper.go | 51 +++++ .../07-tendermint/light_client_module.go | 194 +++++++++++++++++- modules/light-clients/07-tendermint/module.go | 7 +- modules/light-clients/07-tendermint/store.go | 10 + testing/simapp/app.go | 4 +- 5 files changed, 253 insertions(+), 13 deletions(-) create mode 100644 modules/light-clients/07-tendermint/keeper/keeper.go diff --git a/modules/light-clients/07-tendermint/keeper/keeper.go b/modules/light-clients/07-tendermint/keeper/keeper.go new file mode 100644 index 00000000000..26ecfdf9e21 --- /dev/null +++ b/modules/light-clients/07-tendermint/keeper/keeper.go @@ -0,0 +1,51 @@ +package keeper + +import ( + "errors" + "fmt" + "strings" + + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +// Keeper defines the tendermint light client module keeper +type Keeper struct { + storeKey storetypes.StoreKey + cdc codec.BinaryCodec + + // the address capable of executing a MsgUpdateParams message. Typically, this + // should be the x/gov module account. + authority string +} + +func NewKeeper( + cdc codec.BinaryCodec, + key storetypes.StoreKey, + authority string, +) Keeper { + if strings.TrimSpace(authority) == "" { + panic(errors.New("authority must be non-empty")) + } + + return Keeper{ + cdc: cdc, + storeKey: key, + authority: authority, + } +} + +// ClientStore returns isolated prefix store for each client so they can read/write in separate +// namespace without being able to read/write other client's data +func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { + clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) + return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) +} + +func (k Keeper) Codec() codec.BinaryCodec { + return k.cdc +} diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 44cc3ddd1ee..56c2250d1e6 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -9,25 +9,199 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" + "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/keeper" ) type LightClientModule struct { - cdc codec.BinaryCodec - prefixStoreKey storetypes.StoreKey + keeper keeper.Keeper +} + +func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) LightClientModule { + return LightClientModule{ + keeper: keeper.NewKeeper(cdc, key, authority), + } } // Initialize checks that the initial consensus state is an 07-tendermint consensus state and // sets the client state, consensus state and associated metadata in the provided client store. -func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID, clientState conensusState []byte) error { - // validate args - // - client id - // client/consensus state if len == 0 +func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + + var clientState ClientState + if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + return err + } + + if err := clientState.Validate(); err != nil { + return err + } + + var consensusState ConsensusState + if err := lcm.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + return err + } + if err := consensusState.ValidateBasic(); err != nil { + return err + } - // unpack client/consensus states + clientStore := lcm.keeper.ClientStore(ctx, clientID) - // get store key - lcm.getStoreKey(clientID) + return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, &consensusState) +} + +func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } - return clientState.Initialize(ctx, lcm.cdc, storeKey, consensusState) + return nil } +func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + + return nil +} + +func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + + return nil +} + +func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + + return nil +} + +func (lcm LightClientModule) VerifyMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path Path, // TODO: change to conrete type + value []byte, +) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + + clientStore := lcm.keeper.ClientStore(clientID) + cdc := lcm.keeper.Codec() + + clientState := getClientState(clientStore, cdc) + + return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) +} + +func (lcm LightClientModule) VerifyNonMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path Path, // TODO: change to conrete type +) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + +} + +func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) Status { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + +} + +func (lcm LightClientModule) TimestampAtHeight( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type +) (uint64, error) { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + +} + +func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + +} + +func (lcm LightClientModule) VerifyUpgradeAndUpdateState( + ctx sdk.Context, + clientID string, + newClient []byte, + newConsState []byte, + upgradeClientProof, + upgradeConsensusStateProof []byte, +) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + +} diff --git a/modules/light-clients/07-tendermint/module.go b/modules/light-clients/07-tendermint/module.go index 9f28bd6613b..78d71691ce7 100644 --- a/modules/light-clients/07-tendermint/module.go +++ b/modules/light-clients/07-tendermint/module.go @@ -76,9 +76,12 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { // AppModule is the application module for the Tendermint client module type AppModule struct { AppModuleBasic + lightClientModule LightClientModule } // NewAppModule creates a new Tendermint client module -func NewAppModule() AppModule { - return AppModule{} +func NewAppModule(lightClientModule LightClientModule) AppModule { + return AppModule{ + lightClientModule: lightClientModule, + } } diff --git a/modules/light-clients/07-tendermint/store.go b/modules/light-clients/07-tendermint/store.go index 1dce3bbf521..c66b61f5e33 100644 --- a/modules/light-clients/07-tendermint/store.go +++ b/modules/light-clients/07-tendermint/store.go @@ -51,6 +51,16 @@ func setClientState(clientStore storetypes.KVStore, cdc codec.BinaryCodec, clien clientStore.Set(key, val) } +func getClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return nil, false + } + + clientStateI := clienttypes.MustUnmarshalClientState(cdc, bz) + return clientStateI.(*ClientState), true +} + // setConsensusState stores the consensus state at the given height. func setConsensusState(clientStore storetypes.KVStore, cdc codec.BinaryCodec, consensusState *ConsensusState, height exported.Height) { key := host.ConsensusStateKey(height) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index dc44a54bd14..d5907457f7a 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -561,6 +561,8 @@ func NewSimApp( // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.AddressCodec(), runtime.ProvideCometInfoService(), @@ -605,7 +607,7 @@ func NewSimApp( transfer.NewAppModule(app.TransferKeeper), ibcfee.NewAppModule(app.IBCFeeKeeper), ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), - ibctm.NewAppModule(), + ibctm.NewAppModule(tmLightClientModule), solomachine.NewAppModule(), mockModule, ) From 53a8dbeaa9b5f2b2029bd7497c954d6acdd6e580 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 29 Jan 2024 20:14:31 +0100 Subject: [PATCH 03/74] feat: adding initial light client module impl for 06-solomachine --- .../06-solomachine/keeper/keeper.go | 30 ++ .../06-solomachine/light_client_module.go | 267 ++++++++++++++++++ 2 files changed, 297 insertions(+) create mode 100644 modules/light-clients/06-solomachine/keeper/keeper.go create mode 100644 modules/light-clients/06-solomachine/light_client_module.go diff --git a/modules/light-clients/06-solomachine/keeper/keeper.go b/modules/light-clients/06-solomachine/keeper/keeper.go new file mode 100644 index 00000000000..c27f783b5eb --- /dev/null +++ b/modules/light-clients/06-solomachine/keeper/keeper.go @@ -0,0 +1,30 @@ +package keeper + +import ( + "fmt" + + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +// Keeper defines the 06-solomachine Keeper. +type Keeper struct { + cdc codec.Codec + storeKey storetypes.StoreKey +} + +// Codec returns the keeper codec. +func (k Keeper) Codec() codec.Codec { + return k.cdc +} + +// ClientStore returns a namespaced prefix store for the provided IBC client identifier. +func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { + clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) + return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) +} diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go new file mode 100644 index 00000000000..6de04a39e85 --- /dev/null +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -0,0 +1,267 @@ +package solomachine + +import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine/keeper" +) + +// LightClientModule implements the core IBC api.LightClientModule interface? +type LightClientModule struct { + keeper keeper.Keeper +} + +// Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the +// client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. +func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { + if err := validateClientID(clientID); err != nil { + return err + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + return err + } + + if err := clientState.Validate(); err != nil { + return err + } + + var consensusState ConsensusState + if err := l.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + return err + } + + if err := consensusState.ValidateBasic(); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + return clientState.Initialize(ctx, l.keeper.Codec(), store, &consensusState) +} + +// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. +// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour +// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned +// if the ClientMessage fails to verify. +func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + if err := validateClientID(clientID); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return err + } + + return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), store, clientMsg) +} + +// Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage +// has already been verified. +func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + if err := validateClientID(clientID); err != nil { + panic(err) + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + return clientState.CheckForMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) +} + +// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified +func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + if err := validateClientID(clientID); err != nil { + panic(err) + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + clientState.UpdateStateOnMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) +} + +// 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 (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + if err := validateClientID(clientID); err != nil { + panic(err) + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + return clientState.UpdateState(ctx, l.keeper.Codec(), store, clientMsg) +} + +// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +func (l LightClientModule) VerifyMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path exported.Path, // TODO: change to conrete type + value []byte, +) error { + if err := validateClientID(clientID); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return err + } + + return clientState.VerifyMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path, value) +} + +// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +func (l LightClientModule) VerifyNonMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path exported.Path, // TODO: change to conrete type +) error { + if err := validateClientID(clientID); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return err + } + + return clientState.VerifyNonMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path) +} + +// Status must return the status of the client. Only Active clients are allowed to process packets. +func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { + if err := validateClientID(clientID); err != nil { + return exported.Unknown // TODO: or panic + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + return clientState.Status(ctx, store, l.keeper.Codec()) +} + +// TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { + if err := validateClientID(clientID); err != nil { + return 0, err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return 0, fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return 0, err + } + + return clientState.GetTimestampAtHeight(ctx, store, l.keeper.Codec(), height) +} + +func validateClientID(clientID string) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Solomachine { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Solomachine, clientType) + } + + return nil +} + +// // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. +// // The light client must set the updated client and consensus states within the clientStore for the subject client. +// // DEPRECATED: will be removed as performs internal functionality +// RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error + +// // Upgrade functions +// // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last +// // height committed by the current revision. Clients are responsible for ensuring that the planned last +// // height of the current revision is somehow encoded in the proof verification process. +// // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty +// // may be cancelled or modified before the last planned height. +// // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. +// // DEPRECATED: will be removed as performs internal functionality +// VerifyUpgradeAndUpdateState( +// ctx sdk.Context, +// clientID string, +// newClient []byte, +// newConsState []byte, +// upgradeClientProof, +// upgradeConsensusStateProof []byte, +// ) error From f90c702e219f5aefb77d9414bb1bbeea115588b5 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Mon, 29 Jan 2024 20:18:17 +0100 Subject: [PATCH 04/74] chore: adding LightClientModule interface assertion for 06-solomachine --- .../06-solomachine/light_client_module.go | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 6de04a39e85..4b5d8a4bade 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -13,6 +13,8 @@ import ( "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine/keeper" ) +var _ exported.LightClientModule = (*LightClientModule)(nil) + // LightClientModule implements the core IBC api.LightClientModule interface? type LightClientModule struct { keeper keeper.Keeper @@ -247,7 +249,9 @@ func validateClientID(clientID string) error { // // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. // // The light client must set the updated client and consensus states within the clientStore for the subject client. // // DEPRECATED: will be removed as performs internal functionality -// RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error +func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + return nil +} // // Upgrade functions // // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last @@ -257,11 +261,6 @@ func validateClientID(clientID string) error { // // may be cancelled or modified before the last planned height. // // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. // // DEPRECATED: will be removed as performs internal functionality -// VerifyUpgradeAndUpdateState( -// ctx sdk.Context, -// clientID string, -// newClient []byte, -// newConsState []byte, -// upgradeClientProof, -// upgradeConsensusStateProof []byte, -// ) error +func (l LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { + return nil +} From 87e952f226be142413a2e27e5f99d243193e3092 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 10:04:24 +0100 Subject: [PATCH 05/74] chore: adding initial boiilerplate for 08-wasm mod --- .../light-clients/08-wasm/keeper/keeper.go | 26 +- .../08-wasm/light_client_module.go | 267 ++++++++++++++++++ 2 files changed, 288 insertions(+), 5 deletions(-) create mode 100644 modules/light-clients/08-wasm/light_client_module.go diff --git a/modules/light-clients/08-wasm/keeper/keeper.go b/modules/light-clients/08-wasm/keeper/keeper.go index 8676601a230..c39d4b7191f 100644 --- a/modules/light-clients/08-wasm/keeper/keeper.go +++ b/modules/light-clients/08-wasm/keeper/keeper.go @@ -9,8 +9,10 @@ import ( wasmvm "github.com/CosmWasm/wasmvm" - storetypes "cosmossdk.io/core/store" + "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -18,6 +20,7 @@ import ( "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // Keeper defines the 08-wasm keeper @@ -25,8 +28,10 @@ type Keeper struct { // implements gRPC QueryServer interface types.QueryServer - cdc codec.BinaryCodec - storeService storetypes.KVStoreService + cdc codec.BinaryCodec + + storeKey storetypes.StoreKey + storeService store.KVStoreService clientKeeper types.ClientKeeper @@ -38,7 +43,7 @@ type Keeper struct { // and the same Wasm VM instance should be shared with it. func NewKeeperWithVM( cdc codec.BinaryCodec, - storeService storetypes.KVStoreService, + storeService store.KVStoreService, clientKeeper types.ClientKeeper, authority string, vm ibcwasm.WasmEngine, @@ -87,7 +92,7 @@ func NewKeeperWithVM( // and a Wasm VM needs to be instantiated using the provided parameters. func NewKeeperWithConfig( cdc codec.BinaryCodec, - storeService storetypes.KVStoreService, + storeService store.KVStoreService, clientKeeper types.ClientKeeper, authority string, wasmConfig types.WasmConfig, @@ -102,6 +107,17 @@ func NewKeeperWithConfig( return NewKeeperWithVM(cdc, storeService, clientKeeper, authority, vm, queryRouter, opts...) } +// Codec returns the 08-wasm module's codec. +func (k Keeper) Codec() codec.BinaryCodec { + return k.cdc +} + +// ClientStore returns a namespaced prefix store for the provided IBC client identifier. +func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { + clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) + return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) +} + // GetAuthority returns the 08-wasm module's authority. func (k Keeper) GetAuthority() string { return k.authority diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go new file mode 100644 index 00000000000..b4fb8f08032 --- /dev/null +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -0,0 +1,267 @@ +package wasm + +import ( + "fmt" + + errorsmod "cosmossdk.io/errors" + + sdk "github.com/cosmos/cosmos-sdk/types" + + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +var _ exported.LightClientModule = (*LightClientModule)(nil) + +// LightClientModule implements the core IBC api.LightClientModule interface? +type LightClientModule struct { + keeper keeper.Keeper +} + +// Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the +// client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. +func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { + if err := validateClientID(clientID); err != nil { + return err + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + return err + } + + if err := clientState.Validate(); err != nil { + return err + } + + var consensusState types.ConsensusState + if err := l.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + return err + } + + if err := consensusState.ValidateBasic(); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + return clientState.Initialize(ctx, l.keeper.Codec(), store, &consensusState) +} + +// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. +// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour +// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned +// if the ClientMessage fails to verify. +func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + if err := validateClientID(clientID); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return err + } + + return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), store, clientMsg) +} + +// Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage +// has already been verified. +func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + if err := validateClientID(clientID); err != nil { + panic(err) + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + return clientState.CheckForMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) +} + +// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified +func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + if err := validateClientID(clientID); err != nil { + panic(err) + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + clientState.UpdateStateOnMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) +} + +// 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 (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + if err := validateClientID(clientID); err != nil { + panic(err) + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + return clientState.UpdateState(ctx, l.keeper.Codec(), store, clientMsg) +} + +// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +func (l LightClientModule) VerifyMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path exported.Path, // TODO: change to conrete type + value []byte, +) error { + if err := validateClientID(clientID); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return err + } + + return clientState.VerifyMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path, value) +} + +// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +func (l LightClientModule) VerifyNonMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path exported.Path, // TODO: change to conrete type +) error { + if err := validateClientID(clientID); err != nil { + return err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return err + } + + return clientState.VerifyNonMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path) +} + +// Status must return the status of the client. Only Active clients are allowed to process packets. +func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { + if err := validateClientID(clientID); err != nil { + return exported.Unknown // TODO: or panic + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + panic(err) + } + + return clientState.Status(ctx, store, l.keeper.Codec()) +} + +// TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { + if err := validateClientID(clientID); err != nil { + return 0, err + } + + store := l.keeper.ClientStore(ctx, clientID) + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return 0, fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) + } + + var clientState types.ClientState + if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + return 0, err + } + + return clientState.GetTimestampAtHeight(ctx, store, l.keeper.Codec(), height) +} + +func validateClientID(clientID string) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != types.Wasm { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", types.Wasm, clientType) + } + + return nil +} + +// // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. +// // The light client must set the updated client and consensus states within the clientStore for the subject client. +// // DEPRECATED: will be removed as performs internal functionality +func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + return nil +} + +// // Upgrade functions +// // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last +// // height committed by the current revision. Clients are responsible for ensuring that the planned last +// // height of the current revision is somehow encoded in the proof verification process. +// // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty +// // may be cancelled or modified before the last planned height. +// // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. +// // DEPRECATED: will be removed as performs internal functionality +func (l LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { + return nil +} From 100340a9c72d80ccb0dae51a4e20e3f09b61e2d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:40:39 +0100 Subject: [PATCH 06/74] refactor: add boilerplate tendermint light client module --- .../{ => internal}/keeper/keeper.go | 0 .../07-tendermint/light_client_module.go | 154 +++++++++++++++--- 2 files changed, 132 insertions(+), 22 deletions(-) rename modules/light-clients/07-tendermint/{ => internal}/keeper/keeper.go (100%) diff --git a/modules/light-clients/07-tendermint/keeper/keeper.go b/modules/light-clients/07-tendermint/internal/keeper/keeper.go similarity index 100% rename from modules/light-clients/07-tendermint/keeper/keeper.go rename to modules/light-clients/07-tendermint/internal/keeper/keeper.go diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 56c2250d1e6..298dcb3ea52 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -9,7 +9,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" - "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/keeper" + "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/internal/keeper" ) type LightClientModule struct { @@ -66,56 +66,87 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - return nil + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + return clientState.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) } func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { - return err + panic(err) } if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return nil + return clientState.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) } func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { - return err + panic(err) } if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return nil + clientState.UpdateStateOnMisbehaviour(ctx, cdc, clientStore, clientMsg) } func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { - return err + panic(err) } if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) + } + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return nil + return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path Path, // TODO: change to conrete type + path exported.Path, value []byte, ) error { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) @@ -127,10 +158,13 @@ func (lcm LightClientModule) VerifyMembership( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.keeper.ClientStore(clientID) + clientStore := lcm.keeper.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() - clientState := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } @@ -142,7 +176,7 @@ func (lcm LightClientModule) VerifyNonMembership( delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path Path, // TODO: change to conrete type + path exported.Path, // TODO: change to conrete type ) error { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { @@ -153,38 +187,88 @@ func (lcm LightClientModule) VerifyNonMembership( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } -func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) Status { +func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { - return err + return exported.Unknown } if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + return exported.Unknown + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return exported.Unknown } + return clientState.Status(ctx, clientStore, cdc) } func (lcm LightClientModule) TimestampAtHeight( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, ) (uint64, error) { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { - return err + return 0, err } if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + return 0, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } + return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) + } + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + substituteClientStore := lcm.keeper.ClientStore(ctx, substituteClientID) + substituteClient, found := getClientState(substituteClientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) + } + + return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } func (lcm LightClientModule) VerifyUpgradeAndUpdateState( @@ -204,4 +288,30 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } + var newClientState ClientState + if err := lcm.keeper.Codec().Unmarshal(newClient, &newClientState); err != nil { + return err + } + + if err := newClientState.Validate(); err != nil { + return err + } + + var newConsensusState ConsensusState + if err := lcm.keeper.Codec().Unmarshal(newConsState, &newConsensusState); err != nil { + return err + } + if err := newConsensusState.ValidateBasic(); err != nil { + return err + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + return clientState.VerifyUpgradeAndUpdateState(ctx, cdc, clientStore, &newClientState, &newConsensusState, upgradeClientProof, upgradeConsensusStateProof) } From 1ec5291215d786c9244439f8b2bcc501be7bc4b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Jan 2024 11:55:57 +0100 Subject: [PATCH 07/74] refactor: add localhost boilerplate code --- .../09-localhost/internal/keeper/keeper.go | 51 ++++ .../09-localhost/light_client_module.go | 228 ++++++++++++++++++ modules/light-clients/09-localhost/store.go | 18 ++ 3 files changed, 297 insertions(+) create mode 100644 modules/light-clients/09-localhost/internal/keeper/keeper.go create mode 100644 modules/light-clients/09-localhost/light_client_module.go create mode 100644 modules/light-clients/09-localhost/store.go diff --git a/modules/light-clients/09-localhost/internal/keeper/keeper.go b/modules/light-clients/09-localhost/internal/keeper/keeper.go new file mode 100644 index 00000000000..522bb24455c --- /dev/null +++ b/modules/light-clients/09-localhost/internal/keeper/keeper.go @@ -0,0 +1,51 @@ +package keeper + +import ( + "errors" + "fmt" + "strings" + + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +// Keeper defines the localhost light client module keeper +type Keeper struct { + storeKey storetypes.StoreKey + cdc codec.BinaryCodec + + // the address capable of executing a MsgUpdateParams message. Typically, this + // should be the x/gov module account. + authority string +} + +func NewKeeper( + cdc codec.BinaryCodec, + key storetypes.StoreKey, + authority string, +) Keeper { + if strings.TrimSpace(authority) == "" { + panic(errors.New("authority must be non-empty")) + } + + return Keeper{ + cdc: cdc, + storeKey: key, + authority: authority, + } +} + +// ClientStore returns isolated prefix store for each client so they can read/write in separate +// namespace without being able to read/write other client's data +func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { + clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) + return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) +} + +func (k Keeper) Codec() codec.BinaryCodec { + return k.cdc +} diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go new file mode 100644 index 00000000000..0341316946e --- /dev/null +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -0,0 +1,228 @@ +package localhost + +import ( + errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost/internal/keeper" +) + +type LightClientModule struct { + keeper keeper.Keeper +} + +func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) LightClientModule { + return LightClientModule{ + keeper: keeper.NewKeeper(cdc, key, authority), + } +} + +func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Localhost { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) + } + + if len(consensusStateBz) != 0 { + return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") + } + + var clientState ClientState + if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + return err + } + + if err := clientState.Validate(); err != nil { + return err + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + + return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, nil) +} + +func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Localhost { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + return clientState.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) +} + +func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + panic(err) + } + + if clientType != exported.Localhost { + panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) + } + + return false +} + +func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + panic(err) + } + + if clientType != exported.Localhost { + panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) + } +} + +func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + panic(err) + } + + if clientType != exported.Localhost { + panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) + } + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) + } + + return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) +} + +func (lcm LightClientModule) VerifyMembership( + ctx sdk.Context, + clientID string, + height exported.Height, + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path exported.Path, + value []byte, +) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Localhost { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) +} + +func (lcm LightClientModule) VerifyNonMembership( + ctx sdk.Context, + clientID string, + height exported.Height, // TODO: change to concrete type + delayTimePeriod uint64, + delayBlockPeriod uint64, + proof []byte, + path exported.Path, // TODO: change to conrete type +) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Localhost { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) +} + +func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return exported.Unknown + } + + if clientType != exported.Localhost { + return exported.Unknown + } + + clientStore := lcm.keeper.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := getClientState(clientStore, cdc) + if !found { + return exported.Unknown + } + + return clientState.Status(ctx, clientStore, cdc) +} + +func (lcm LightClientModule) TimestampAtHeight( + ctx sdk.Context, + clientID string, + height exported.Height, +) (uint64, error) { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return 0, err + } + + if clientType != exported.Localhost { + return 0, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) + } + + return uint64(ctx.BlockTime().UnixNano()), nil +} + +func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") +} + +func (lcm LightClientModule) VerifyUpgradeAndUpdateState( + ctx sdk.Context, + clientID string, + newClient []byte, + newConsState []byte, + upgradeClientProof, + upgradeConsensusStateProof []byte, +) error { + return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client") +} diff --git a/modules/light-clients/09-localhost/store.go b/modules/light-clients/09-localhost/store.go new file mode 100644 index 00000000000..0046ce0c093 --- /dev/null +++ b/modules/light-clients/09-localhost/store.go @@ -0,0 +1,18 @@ +package localhost + +import ( + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +func getClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return nil, false + } + + clientStateI := clienttypes.MustUnmarshalClientState(cdc, bz) + return clientStateI.(*ClientState), true +} From a21fdedc04714581c59727765363574f3f674733 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Jan 2024 12:09:40 +0100 Subject: [PATCH 08/74] imp: add basic 02-client router --- modules/core/02-client/keeper/keeper.go | 4 +- modules/core/02-client/types/router.go | 50 +++++++++++++++++++++++++ modules/core/keeper/keeper.go | 2 +- 3 files changed, 54 insertions(+), 2 deletions(-) create mode 100644 modules/core/02-client/types/router.go diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 026d60faea3..48bc84aa1e4 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -31,16 +31,18 @@ import ( type Keeper struct { storeKey storetypes.StoreKey cdc codec.BinaryCodec + router *types.Router legacySubspace types.ParamSubspace stakingKeeper types.StakingKeeper upgradeKeeper types.UpgradeKeeper } // NewKeeper creates a new NewKeeper instance -func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper { +func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, router *types.Router, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper { return Keeper{ storeKey: key, cdc: cdc, + router: router, legacySubspace: legacySubspace, stakingKeeper: sk, upgradeKeeper: uk, diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go new file mode 100644 index 00000000000..5fb4e87d738 --- /dev/null +++ b/modules/core/02-client/types/router.go @@ -0,0 +1,50 @@ +package types + +import ( + "errors" + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +// The router is a map from module name to the LightClientModule +// which contains all the module-defined callbacks required by ICS-26 +type Router struct { + routes map[string]exported.LightClientModule + sealed bool +} + +func NewRouter() *Router { + return &Router{ + routes: make(map[string]exported.LightClientModule), + } +} + +// AddRoute adds LightClientModule for a given module name. It returns the Router +// so AddRoute calls can be linked. It will panic if the Router is sealed. +func (rtr *Router) AddRoute(module string, cbs exported.LightClientModule) *Router { + if !sdk.IsAlphaNumeric(module) { + panic(errors.New("route expressions can only contain alphanumeric characters")) + } + if rtr.HasRoute(module) { + panic(fmt.Errorf("route %s has already been registered", module)) + } + + rtr.routes[module] = cbs + return rtr +} + +// HasRoute returns true if the Router has a module registered or false otherwise. +func (rtr *Router) HasRoute(module string) bool { + _, ok := rtr.routes[module] + return ok +} + +// GetRoute returns a LightClientModule for a given module. +func (rtr *Router) GetRoute(module string) (exported.LightClientModule, bool) { + if !rtr.HasRoute(module) { + return nil, false + } + return rtr.routes[module], true +} diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 08ee5dc027e..4655a427ef1 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -59,7 +59,7 @@ func NewKeeper( panic(errors.New("authority must be non-empty")) } - clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper, upgradeKeeper) + clientKeeper := clientkeeper.NewKeeper(cdc, key, clienttypes.NewRouter(), paramSpace, stakingKeeper, upgradeKeeper) connectionKeeper := connectionkeeper.NewKeeper(cdc, key, paramSpace, clientKeeper) portKeeper := portkeeper.NewKeeper(scopedKeeper) channelKeeper := channelkeeper.NewKeeper(cdc, key, clientKeeper, connectionKeeper, &portKeeper, scopedKeeper) From 9ee3fff7829f18b1cc217b502dd0d62eb60b7e23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Jan 2024 13:04:33 +0100 Subject: [PATCH 09/74] refactor: use light client module for client status --- modules/core/02-client/abci.go | 2 +- modules/core/02-client/keeper/client.go | 36 ++++++++++--------- modules/core/02-client/keeper/client_test.go | 5 ++- modules/core/02-client/keeper/events.go | 6 ++-- modules/core/02-client/keeper/grpc_query.go | 10 +----- modules/core/02-client/keeper/keeper.go | 21 +++++++++-- modules/core/02-client/types/errors.go | 1 + modules/core/02-client/types/router.go | 8 ++--- .../core/03-connection/keeper/handshake.go | 7 +--- modules/core/03-connection/keeper/verify.go | 20 +++++------ .../03-connection/types/expected_keepers.go | 2 +- modules/core/04-channel/keeper/handshake.go | 14 ++------ modules/core/04-channel/keeper/packet.go | 2 +- .../core/04-channel/types/expected_keepers.go | 2 +- modules/core/keeper/msg_server.go | 13 ++++--- testing/simapp/app.go | 3 ++ 16 files changed, 78 insertions(+), 74 deletions(-) diff --git a/modules/core/02-client/abci.go b/modules/core/02-client/abci.go index 90673bc209c..f15f92857ff 100644 --- a/modules/core/02-client/abci.go +++ b/modules/core/02-client/abci.go @@ -35,7 +35,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { // update the localhost client with the latest block height if it is active. if clientState, found := k.GetClientState(ctx, exported.Localhost); found { - if k.GetClientStatus(ctx, clientState, exported.Localhost) == exported.Active { + if k.GetClientStatus(ctx, exported.Localhost) == exported.Active { k.UpdateLocalhostClient(ctx, clientState) } } diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index 50dc9b34bcd..b6c88d959db 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -17,40 +17,44 @@ import ( // The client state is responsible for setting any client-specific data in the store via the Initialize method. // This includes the client state, initial consensus state and any associated metadata. func (k Keeper) CreateClient( - ctx sdk.Context, clientState exported.ClientState, consensusState exported.ConsensusState, + ctx sdk.Context, clientType string, clientState []byte, consensusState []byte, ) (string, error) { - if clientState.ClientType() == exported.Localhost { - return "", errorsmod.Wrapf(types.ErrInvalidClientType, "cannot create client of type: %s", clientState.ClientType()) + if clientType == exported.Localhost { + return "", errorsmod.Wrapf(types.ErrInvalidClientType, "cannot create client of type: %s", clientType) } params := k.GetParams(ctx) - if !params.IsAllowedClient(clientState.ClientType()) { + if !params.IsAllowedClient(clientType) { return "", errorsmod.Wrapf( types.ErrInvalidClientType, - "client state type %s is not registered in the allowlist", clientState.ClientType(), + "client state type %s is not registered in the allowlist", clientType, ) } - clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType()) - clientStore := k.ClientStore(ctx, clientID) + clientID := k.GenerateClientIdentifier(ctx, clientType) + + lightClientModule, found := k.router.GetRoute(clientType) + if !found { + return "", errorsmod.Wrap(types.ErrRouteNotFound, clientType) + } - if err := clientState.Initialize(ctx, k.cdc, clientStore, consensusState); err != nil { + if err := lightClientModule.Initialize(ctx, clientID, clientState, consensusState); err != nil { return "", err } - if status := k.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.GetClientStatus(ctx, clientID); status != exported.Active { return "", errorsmod.Wrapf(types.ErrClientNotActive, "cannot create client (%s) with status %s", clientID, status) } - k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) + // k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) defer telemetry.IncrCounterWithLabels( []string{"ibc", "client", "create"}, 1, - []metrics.Label{telemetry.NewLabel(types.LabelClientType, clientState.ClientType())}, + []metrics.Label{telemetry.NewLabel(types.LabelClientType, clientType)}, ) - emitCreateClientEvent(ctx, clientID, clientState) + emitCreateClientEvent(ctx, clientID, clientType) return clientID, nil } @@ -64,7 +68,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte clientStore := k.ClientStore(ctx, clientID) - if status := k.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(types.ErrClientNotActive, "cannot update client (%s) with status %s", clientID, status) } @@ -125,7 +129,7 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e clientStore := k.ClientStore(ctx, clientID) - if status := k.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status) } @@ -174,7 +178,7 @@ func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClient subjectClientStore := k.ClientStore(ctx, subjectClientID) - if status := k.GetClientStatus(ctx, subjectClientState, subjectClientID); status == exported.Active { + if status := k.GetClientStatus(ctx, subjectClientID); status == exported.Active { return errorsmod.Wrapf(types.ErrInvalidRecoveryClient, "cannot recover %s subject client", exported.Active) } @@ -189,7 +193,7 @@ func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClient substituteClientStore := k.ClientStore(ctx, substituteClientID) - if status := k.GetClientStatus(ctx, substituteClientState, substituteClientID); status != exported.Active { + if status := k.GetClientStatus(ctx, substituteClientID); status != exported.Active { return errorsmod.Wrapf(types.ErrClientNotActive, "substitute client is not %s, status is %s", exported.Active, status) } diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 63116bdcee8..0dc827fcc73 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -72,7 +72,10 @@ func (suite *KeeperTestSuite) TestCreateClient() { suite.SetupTest() // reset tc.malleate() - clientID, err := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.CreateClient(suite.chainA.GetContext(), clientState, consensusState) + clientStateBz := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.MustMarshalClientState(clientState) + consensusStateBz := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.MustMarshalConsensusState(consensusState) + + clientID, err := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.CreateClient(suite.chainA.GetContext(), clientState.ClientType(), clientStateBz, consensusStateBz) // assert correct behaviour based on expected error clientState, found := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientID) diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index 8b5a4e50a86..b5c443bb0fe 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -15,13 +15,13 @@ import ( ) // emitCreateClientEvent emits a create client event -func emitCreateClientEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { +func emitCreateClientEvent(ctx sdk.Context, clientID, clientType string) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeCreateClient, sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), + sdk.NewAttribute(types.AttributeKeyClientType, clientType), + // sdk.NewAttribute(types.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index 12daed284c7..a572823776b 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -239,15 +239,7 @@ func (k Keeper) ClientStatus(c context.Context, req *types.QueryClientStatusRequ } ctx := sdk.UnwrapSDKContext(c) - clientState, found := k.GetClientState(ctx, req.ClientId) - if !found { - return nil, status.Error( - codes.NotFound, - errorsmod.Wrap(types.ErrClientNotFound, req.ClientId).Error(), - ) - } - - clientStatus := k.GetClientStatus(ctx, clientState, req.ClientId) + clientStatus := k.GetClientStatus(ctx, req.ClientId) return &types.QueryClientStatusResponse{ Status: clientStatus.String(), diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 48bc84aa1e4..83e81dca268 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -54,6 +54,10 @@ func (Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+exported.ModuleName+"/"+types.SubModuleName) } +func (k Keeper) GetRouter() *types.Router { + return k.router +} + // CreateLocalhostClient initialises the 09-localhost client state and sets it in state. func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { var clientState localhost.ClientState @@ -411,11 +415,22 @@ func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore // GetClientStatus returns the status for a given clientState. If the client type is not in the allowed // clients param field, Unauthorized is returned, otherwise the client state status is returned. -func (k Keeper) GetClientStatus(ctx sdk.Context, clientState exported.ClientState, clientID string) exported.Status { - if !k.GetParams(ctx).IsAllowedClient(clientState.ClientType()) { +func (k Keeper) GetClientStatus(ctx sdk.Context, clientID string) exported.Status { + clientType, _, err := types.ParseClientIdentifier(clientID) + if err != nil { + return exported.Unauthorized + } + + if !k.GetParams(ctx).IsAllowedClient(clientType) { return exported.Unauthorized } - return clientState.Status(ctx, k.ClientStore(ctx, clientID), k.cdc) + + lightClientModule, found := k.router.GetRoute(clientID) + if !found { + return exported.Unauthorized + } + + return lightClientModule.Status(ctx, clientID) } // GetParams returns the total set of ibc-client parameters. diff --git a/modules/core/02-client/types/errors.go b/modules/core/02-client/types/errors.go index 3a726378cbc..98c4a502236 100644 --- a/modules/core/02-client/types/errors.go +++ b/modules/core/02-client/types/errors.go @@ -36,4 +36,5 @@ var ( ErrClientNotActive = errorsmod.Register(SubModuleName, 29, "client state is not active") ErrFailedMembershipVerification = errorsmod.Register(SubModuleName, 30, "membership verification failed") ErrFailedNonMembershipVerification = errorsmod.Register(SubModuleName, 31, "non-membership verification failed") + ErrRouteNotFound = errorsmod.Register(SubModuleName, 32, "light client module route not found") ) diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index 5fb4e87d738..3119da430ee 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -1,10 +1,8 @@ package types import ( - "errors" "fmt" - sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -24,9 +22,9 @@ func NewRouter() *Router { // AddRoute adds LightClientModule for a given module name. It returns the Router // so AddRoute calls can be linked. It will panic if the Router is sealed. func (rtr *Router) AddRoute(module string, cbs exported.LightClientModule) *Router { - if !sdk.IsAlphaNumeric(module) { - panic(errors.New("route expressions can only contain alphanumeric characters")) - } + // if !sdk.IsAlphaNumeric(module) { + // panic(errors.New("route expressions can only contain alphanumeric characters")) + // } if rtr.HasRoute(module) { panic(fmt.Errorf("route %s has already been registered", module)) } diff --git a/modules/core/03-connection/keeper/handshake.go b/modules/core/03-connection/keeper/handshake.go index c38d0504edd..b85ccd1e68e 100644 --- a/modules/core/03-connection/keeper/handshake.go +++ b/modules/core/03-connection/keeper/handshake.go @@ -34,12 +34,7 @@ func (k Keeper) ConnOpenInit( versions = []*types.Version{version} } - clientState, found := k.clientKeeper.GetClientState(ctx, clientID) - if !found { - return "", errorsmod.Wrapf(clienttypes.ErrClientNotFound, "clientID (%s)", clientID) - } - - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return "", errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 17948b8c020..1699f5e530c 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -32,7 +32,7 @@ func (k Keeper) VerifyClientState( return err } - if status := k.clientKeeper.GetClientStatus(ctx, targetClient, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -74,7 +74,7 @@ func (k Keeper) VerifyClientConsensusState( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -116,7 +116,7 @@ func (k Keeper) VerifyConnectionState( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -164,7 +164,7 @@ func (k Keeper) VerifyChannelState( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -208,7 +208,7 @@ func (k Keeper) VerifyPacketCommitment( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -251,7 +251,7 @@ func (k Keeper) VerifyPacketAcknowledgement( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -294,7 +294,7 @@ func (k Keeper) VerifyPacketReceiptAbsence( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -336,7 +336,7 @@ func (k Keeper) VerifyNextSequenceRecv( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -377,7 +377,7 @@ func (k Keeper) VerifyChannelUpgradeError( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } @@ -419,7 +419,7 @@ func (k Keeper) VerifyChannelUpgrade( return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientState, clientID); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } diff --git a/modules/core/03-connection/types/expected_keepers.go b/modules/core/03-connection/types/expected_keepers.go index a37605b64cf..bac734e0b40 100644 --- a/modules/core/03-connection/types/expected_keepers.go +++ b/modules/core/03-connection/types/expected_keepers.go @@ -11,7 +11,7 @@ import ( // ClientKeeper expected account IBC client keeper type ClientKeeper interface { - GetClientStatus(ctx sdk.Context, clientState exported.ClientState, clientID string) exported.Status + GetClientStatus(ctx sdk.Context, clientID string) exported.Status GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) GetSelfConsensusState(ctx sdk.Context, height exported.Height) (exported.ConsensusState, error) diff --git a/modules/core/04-channel/keeper/handshake.go b/modules/core/04-channel/keeper/handshake.go index fe647727676..6db739c56dd 100644 --- a/modules/core/04-channel/keeper/handshake.go +++ b/modules/core/04-channel/keeper/handshake.go @@ -52,12 +52,7 @@ func (k Keeper) ChanOpenInit( ) } - clientState, found := k.clientKeeper.GetClientState(ctx, connectionEnd.ClientId) - if !found { - return "", nil, errorsmod.Wrapf(clienttypes.ErrClientNotFound, "clientID (%s)", connectionEnd.ClientId) - } - - if status := k.clientKeeper.GetClientStatus(ctx, clientState, connectionEnd.ClientId); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, connectionEnd.ClientId); status != exported.Active { return "", nil, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", connectionEnd.ClientId, status) } @@ -396,12 +391,7 @@ func (k Keeper) ChanCloseInit( return errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) } - clientState, found := k.clientKeeper.GetClientState(ctx, connectionEnd.ClientId) - if !found { - return errorsmod.Wrapf(clienttypes.ErrClientNotFound, "clientID (%s)", connectionEnd.ClientId) - } - - if status := k.clientKeeper.GetClientStatus(ctx, clientState, connectionEnd.ClientId); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, connectionEnd.ClientId); status != exported.Active { return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", connectionEnd.ClientId, status) } diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index f6a68c1e123..9e9afcc71b8 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -69,7 +69,7 @@ func (k Keeper) SendPacket( } // prevent accidental sends with clients that cannot be updated - if status := k.clientKeeper.GetClientStatus(ctx, clientState, connectionEnd.GetClientID()); status != exported.Active { + if status := k.clientKeeper.GetClientStatus(ctx, connectionEnd.GetClientID()); status != exported.Active { return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot send packet using client (%s) with status %s", connectionEnd.GetClientID(), status) } diff --git a/modules/core/04-channel/types/expected_keepers.go b/modules/core/04-channel/types/expected_keepers.go index 3a40aaab978..22960a39975 100644 --- a/modules/core/04-channel/types/expected_keepers.go +++ b/modules/core/04-channel/types/expected_keepers.go @@ -12,7 +12,7 @@ import ( // ClientKeeper expected account IBC client keeper type ClientKeeper interface { - GetClientStatus(ctx sdk.Context, clientState exported.ClientState, clientID string) exported.Status + GetClientStatus(ctx sdk.Context, clientID string) exported.Status GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index f99ce0b3a82..b373ac73025 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -34,12 +34,15 @@ func (k Keeper) CreateClient(goCtx context.Context, msg *clienttypes.MsgCreateCl return nil, err } - consensusState, err := clienttypes.UnpackConsensusState(msg.ConsensusState) - if err != nil { - return nil, err - } + /* + consensusState, err := clienttypes.UnpackConsensusState(msg.ConsensusState) + if err != nil { + return nil, err + } + + */ - if _, err = k.ClientKeeper.CreateClient(ctx, clientState, consensusState); err != nil { + if _, err = k.ClientKeeper.CreateClient(ctx, clientState.ClientType(), msg.ClientState.Value, msg.ConsensusState.Value); err != nil { return nil, err } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index d5907457f7a..95111514f77 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -561,7 +561,10 @@ func NewSimApp( // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() + tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( From 95f1ff579711283387d0052fe729720c3df5e879 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 14:14:11 +0100 Subject: [PATCH 10/74] chore: move solomachine keeper to internal --- .../06-solomachine/{ => internal}/keeper/keeper.go | 0 modules/light-clients/06-solomachine/light_client_module.go | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename modules/light-clients/06-solomachine/{ => internal}/keeper/keeper.go (100%) diff --git a/modules/light-clients/06-solomachine/keeper/keeper.go b/modules/light-clients/06-solomachine/internal/keeper/keeper.go similarity index 100% rename from modules/light-clients/06-solomachine/keeper/keeper.go rename to modules/light-clients/06-solomachine/internal/keeper/keeper.go diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 4b5d8a4bade..f0100203c43 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -10,7 +10,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" - "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine/keeper" + "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine/internal/keeper" ) var _ exported.LightClientModule = (*LightClientModule)(nil) From 63483bfff9986e6457189fd33966a2b5929d5247 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 14:47:21 +0100 Subject: [PATCH 11/74] chore: adding GetTimestampAtHeight to clientkeeper using 02-client router --- modules/core/02-client/keeper/keeper.go | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 83e81dca268..1422ec84df1 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -433,6 +433,26 @@ func (k Keeper) GetClientStatus(ctx sdk.Context, clientID string) exported.Statu return lightClientModule.Status(ctx, clientID) } +// GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. +// TODO: Replace exported.Height with concrete type. +func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { + clientType, _, err := types.ParseClientIdentifier(clientID) + if err != nil { + return 0, errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) + } + + if !k.GetParams(ctx).IsAllowedClient(clientType) { + return 0, errorsmod.Wrapf(types.ErrInvalidClientType, "client state type %s is not registered in the allowlist", clientType) + } + + lightClientModule, found := k.router.GetRoute(clientID) + if !found { + return 0, errorsmod.Wrap(types.ErrRouteNotFound, clientType) + } + + return lightClientModule.TimestampAtHeight(ctx, clientID, height) +} + // GetParams returns the total set of ibc-client parameters. func (k Keeper) GetParams(ctx sdk.Context) types.Params { store := ctx.KVStore(k.storeKey) From f08c0041b857d9c5a5ff245272177c8ebbc5d60c Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 15:24:46 +0100 Subject: [PATCH 12/74] refactor: rm GetTimestampAtHeight from 03-connection and adapt api calls in 04-channel --- modules/core/03-connection/keeper/keeper.go | 18 ---- .../core/03-connection/keeper/keeper_test.go | 96 +++++++++---------- modules/core/04-channel/keeper/packet.go | 2 +- modules/core/04-channel/keeper/packet_test.go | 4 +- modules/core/04-channel/keeper/timeout.go | 2 +- modules/core/04-channel/keeper/upgrade.go | 2 +- .../core/04-channel/types/expected_keepers.go | 6 +- 7 files changed, 54 insertions(+), 76 deletions(-) diff --git a/modules/core/03-connection/keeper/keeper.go b/modules/core/03-connection/keeper/keeper.go index cd18555f56e..f7b787854fb 100644 --- a/modules/core/03-connection/keeper/keeper.go +++ b/modules/core/03-connection/keeper/keeper.go @@ -87,24 +87,6 @@ func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection t store.Set(host.ConnectionKey(connectionID), bz) } -// GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the -// given height. -func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, connection types.ConnectionEnd, height exported.Height) (uint64, error) { - clientState, found := k.clientKeeper.GetClientState(ctx, connection.GetClientID()) - if !found { - return 0, errorsmod.Wrapf( - clienttypes.ErrClientNotFound, "clientID (%s)", connection.GetClientID(), - ) - } - - timestamp, err := clientState.GetTimestampAtHeight(ctx, k.clientKeeper.ClientStore(ctx, connection.GetClientID()), k.cdc, height) - if err != nil { - return 0, err - } - - return timestamp, nil -} - // GetClientConnectionPaths returns all the connection paths stored under a // particular client func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]string, bool) { diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go index 8cd9b157839..1d4a7deaa12 100644 --- a/modules/core/03-connection/keeper/keeper_test.go +++ b/modules/core/03-connection/keeper/keeper_test.go @@ -1,7 +1,6 @@ package keeper_test import ( - "fmt" "testing" testifysuite "github.com/stretchr/testify/suite" @@ -114,53 +113,54 @@ func (suite KeeperTestSuite) TestGetAllClientConnectionPaths() { //nolint:govet suite.Require().Equal(expPaths, connPaths) } -// TestGetTimestampAtHeight verifies if the clients on each chain return the -// correct timestamp for the other chain. -func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { - var ( - connection types.ConnectionEnd - height exported.Height - ) - - cases := []struct { - msg string - malleate func() - expPass bool - }{ - {"verification success", func() { - path := ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupConnections() - connection = path.EndpointA.GetConnection() - height = suite.chainB.LatestCommittedHeader.GetHeight() - }, true}, - {"client state not found", func() {}, false}, - {"consensus state not found", func() { - path := ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupConnections() - connection = path.EndpointA.GetConnection() - height = suite.chainB.LatestCommittedHeader.GetHeight().Increment() - }, false}, - } - - for _, tc := range cases { - suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { - suite.SetupTest() // reset - - tc.malleate() - - actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight( - suite.chainA.GetContext(), connection, height, - ) - - if tc.expPass { - suite.Require().NoError(err) - suite.Require().EqualValues(uint64(suite.chainB.LatestCommittedHeader.GetTime().UnixNano()), actualTimestamp) - } else { - suite.Require().Error(err) - } - }) - } -} +// TODO(damian): move this test to clientkeeper :) +// // TestGetTimestampAtHeight verifies if the clients on each chain return the +// // correct timestamp for the other chain. +// func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { +// var ( +// connection types.ConnectionEnd +// height exported.Height +// ) + +// cases := []struct { +// msg string +// malleate func() +// expPass bool +// }{ +// {"verification success", func() { +// path := ibctesting.NewPath(suite.chainA, suite.chainB) +// path.SetupConnections() +// connection = path.EndpointA.GetConnection() +// height = suite.chainB.LatestCommittedHeader.GetHeight() +// }, true}, +// {"client state not found", func() {}, false}, +// {"consensus state not found", func() { +// path := ibctesting.NewPath(suite.chainA, suite.chainB) +// path.SetupConnections() +// connection = path.EndpointA.GetConnection() +// height = suite.chainB.LatestCommittedHeader.GetHeight().Increment() +// }, false}, +// } + +// for _, tc := range cases { +// suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { +// suite.SetupTest() // reset + +// tc.malleate() + +// actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight( +// suite.chainA.GetContext(), connection, height, +// ) + +// if tc.expPass { +// suite.Require().NoError(err) +// suite.Require().EqualValues(uint64(suite.chainB.LatestCommittedHeader.GetTime().UnixNano()), actualTimestamp) +// } else { +// suite.Require().Error(err) +// } +// }) +// } +// } func (suite *KeeperTestSuite) TestLocalhostConnectionEndCreation() { ctx := suite.chainA.GetContext() diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index 9e9afcc71b8..7967d462307 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -74,7 +74,7 @@ func (k Keeper) SendPacket( } latestHeight := clientState.GetLatestHeight() - latestTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connectionEnd, latestHeight) + latestTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.GetClientID(), latestHeight) if err != nil { return 0, err } diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index 12308037356..f7a7956ca3c 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -172,7 +172,7 @@ func (suite *KeeperTestSuite) TestSendPacket() { // use latest time on client state clientState := path.EndpointA.GetClientState() connection := path.EndpointA.GetConnection() - timestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection, clientState.GetLatestHeight()) + timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.GetClientID(), clientState.GetLatestHeight()) suite.Require().NoError(err) timeoutHeight = disabledTimeoutHeight @@ -190,7 +190,7 @@ func (suite *KeeperTestSuite) TestSendPacket() { path.EndpointA.SetConnection(connection) clientState := path.EndpointA.GetClientState() - timestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection, clientState.GetLatestHeight()) + timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.GetClientID(), clientState.GetLatestHeight()) suite.Require().NoError(err) sourceChannel = path.EndpointA.ChannelID diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index 15a7091ac09..d95dbb561af 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -63,7 +63,7 @@ func (k Keeper) TimeoutPacket( } // check that timeout height or timeout timestamp has passed on the other end - proofTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connectionEnd, proofHeight) + proofTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.GetClientID(), proofHeight) if err != nil { return err } diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index 1dae7f7a862..4454c659323 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -753,7 +753,7 @@ func (k Keeper) ChanUpgradeTimeout( ) } - proofTimestamp, err := k.connectionKeeper.GetTimestampAtHeight(ctx, connection, proofHeight) + proofTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connection.GetClientID(), proofHeight) if err != nil { return err } diff --git a/modules/core/04-channel/types/expected_keepers.go b/modules/core/04-channel/types/expected_keepers.go index 22960a39975..ee2e16cef2f 100644 --- a/modules/core/04-channel/types/expected_keepers.go +++ b/modules/core/04-channel/types/expected_keepers.go @@ -16,16 +16,12 @@ type ClientKeeper interface { GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore + GetTimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) } // ConnectionKeeper expected account IBC connection keeper type ConnectionKeeper interface { GetConnection(ctx sdk.Context, connectionID string) (connectiontypes.ConnectionEnd, bool) - GetTimestampAtHeight( - ctx sdk.Context, - connection connectiontypes.ConnectionEnd, - height exported.Height, - ) (uint64, error) VerifyChannelState( ctx sdk.Context, connection exported.ConnectionI, From 090cbbfa6cb5668b596447b8443fde9852630709 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 16:52:41 +0100 Subject: [PATCH 13/74] chore: wire up solomachine module with clientRouter in app.go --- .../06-solomachine/internal/keeper/keeper.go | 12 ++++++++++-- .../06-solomachine/light_client_module.go | 9 +++++++++ testing/simapp/app.go | 3 +++ 3 files changed, 22 insertions(+), 2 deletions(-) diff --git a/modules/light-clients/06-solomachine/internal/keeper/keeper.go b/modules/light-clients/06-solomachine/internal/keeper/keeper.go index c27f783b5eb..348e8a62d83 100644 --- a/modules/light-clients/06-solomachine/internal/keeper/keeper.go +++ b/modules/light-clients/06-solomachine/internal/keeper/keeper.go @@ -14,12 +14,20 @@ import ( // Keeper defines the 06-solomachine Keeper. type Keeper struct { - cdc codec.Codec + cdc codec.BinaryCodec storeKey storetypes.StoreKey } +// NewKeeper creates and returns a new 06-solomachine keeper. +func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Keeper { + return Keeper{ + cdc: cdc, + storeKey: storeKey, + } +} + // Codec returns the keeper codec. -func (k Keeper) Codec() codec.Codec { +func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index f0100203c43..02b8624629e 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -4,7 +4,9 @@ import ( "fmt" errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -20,6 +22,13 @@ type LightClientModule struct { keeper keeper.Keeper } +// NewLightClientModule creates and returns a new 06-solomachine LightClientModule. +func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) LightClientModule { + return LightClientModule{ + keeper: keeper.NewKeeper(cdc, key), + } +} + // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 95111514f77..377f92094b0 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -566,6 +566,9 @@ func NewSimApp( tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) + smClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) + clientRouter.AddRoute(solomachine.ModuleName, smClientModule) + // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.AddressCodec(), runtime.ProvideCometInfoService(), From 8d8bb34bd698f7fb50b7959693bb85ad15e10fb2 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 16:53:08 +0100 Subject: [PATCH 14/74] chore: move commented out test to client keeper - still has todo to uncomment and fix --- modules/core/02-client/keeper/keeper_test.go | 59 +++++++++++++++++++ .../core/03-connection/keeper/keeper_test.go | 49 --------------- 2 files changed, 59 insertions(+), 49 deletions(-) diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 8f1680bf5c3..5d2d044a9a1 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -431,6 +431,65 @@ func (suite KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this } } +// TODO(damian): uncomment and address this test +// func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { +// var ( +// clientID string +// height exported.Height +// ) + +// cases := []struct { +// msg string +// malleate func() +// expPass bool +// }{ +// { +// "verification success", +// func() { +// path := ibctesting.NewPath(suite.chainA, suite.chainB) +// path.SetupConnections() + +// clientID = path.EndpointA.ClientID +// height = suite.chainB.LatestCommittedHeader.GetHeight() +// }, +// true, +// }, +// { +// "client state not found", +// func() {}, +// false, +// }, +// { +// "consensus state not found", func() { +// path := ibctesting.NewPath(suite.chainA, suite.chainB) +// path.SetupConnections() +// clientID = path.EndpointA.ClientID +// height = suite.chainB.LatestCommittedHeader.GetHeight().Increment() +// }, +// false, +// }, +// } + +// for _, tc := range cases { +// suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { +// suite.SetupTest() // reset + +// tc.malleate() + +// actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight( +// suite.chainA.GetContext(), clientID, height, +// ) + +// if tc.expPass { +// suite.Require().NoError(err) +// suite.Require().EqualValues(uint64(suite.chainB.LatestCommittedHeader.GetTime().UnixNano()), actualTimestamp) +// } else { +// suite.Require().Error(err) +// } +// }) +// } +// } + // TestDefaultSetParams tests the default params set are what is expected func (suite *KeeperTestSuite) TestDefaultSetParams() { expParams := types.DefaultParams() diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go index 1d4a7deaa12..2069f611e43 100644 --- a/modules/core/03-connection/keeper/keeper_test.go +++ b/modules/core/03-connection/keeper/keeper_test.go @@ -113,55 +113,6 @@ func (suite KeeperTestSuite) TestGetAllClientConnectionPaths() { //nolint:govet suite.Require().Equal(expPaths, connPaths) } -// TODO(damian): move this test to clientkeeper :) -// // TestGetTimestampAtHeight verifies if the clients on each chain return the -// // correct timestamp for the other chain. -// func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { -// var ( -// connection types.ConnectionEnd -// height exported.Height -// ) - -// cases := []struct { -// msg string -// malleate func() -// expPass bool -// }{ -// {"verification success", func() { -// path := ibctesting.NewPath(suite.chainA, suite.chainB) -// path.SetupConnections() -// connection = path.EndpointA.GetConnection() -// height = suite.chainB.LatestCommittedHeader.GetHeight() -// }, true}, -// {"client state not found", func() {}, false}, -// {"consensus state not found", func() { -// path := ibctesting.NewPath(suite.chainA, suite.chainB) -// path.SetupConnections() -// connection = path.EndpointA.GetConnection() -// height = suite.chainB.LatestCommittedHeader.GetHeight().Increment() -// }, false}, -// } - -// for _, tc := range cases { -// suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { -// suite.SetupTest() // reset - -// tc.malleate() - -// actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ConnectionKeeper.GetTimestampAtHeight( -// suite.chainA.GetContext(), connection, height, -// ) - -// if tc.expPass { -// suite.Require().NoError(err) -// suite.Require().EqualValues(uint64(suite.chainB.LatestCommittedHeader.GetTime().UnixNano()), actualTimestamp) -// } else { -// suite.Require().Error(err) -// } -// }) -// } -// } - func (suite *KeeperTestSuite) TestLocalhostConnectionEndCreation() { ctx := suite.chainA.GetContext() connectionKeeper := suite.chainA.App.GetIBCKeeper().ConnectionKeeper From 2875686381bbc7d1c1ff7fdd6567695310c1ce3e Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 16:58:13 +0100 Subject: [PATCH 15/74] chore: add solomachine client module to AppModule constructor and wire up in app.go --- modules/light-clients/06-solomachine/module.go | 7 +++++-- testing/simapp/app.go | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/light-clients/06-solomachine/module.go b/modules/light-clients/06-solomachine/module.go index 0f380fd2fb8..906231124c5 100644 --- a/modules/light-clients/06-solomachine/module.go +++ b/modules/light-clients/06-solomachine/module.go @@ -76,9 +76,12 @@ func (AppModuleBasic) GetQueryCmd() *cobra.Command { // AppModule is the application module for the Solomachine client module type AppModule struct { AppModuleBasic + lightClientModule LightClientModule } // NewAppModule creates a new Solomachine client module -func NewAppModule() AppModule { - return AppModule{} +func NewAppModule(lightClientModule LightClientModule) AppModule { + return AppModule{ + lightClientModule: lightClientModule, + } } diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 377f92094b0..97fbe9ec412 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -614,7 +614,7 @@ func NewSimApp( ibcfee.NewAppModule(app.IBCFeeKeeper), ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), ibctm.NewAppModule(tmLightClientModule), - solomachine.NewAppModule(), + solomachine.NewAppModule(smClientModule), mockModule, ) From f36001badea7ea64145afb9ad96b6d216d20cd8d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Jan 2024 17:04:54 +0100 Subject: [PATCH 16/74] fix: use correct route for client status lookup --- modules/core/02-client/keeper/client_test.go | 46 +++++++++++-------- modules/core/02-client/keeper/keeper.go | 2 +- .../07-tendermint/light_client_module.go | 1 + 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 0dc827fcc73..7a47cd894a6 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -19,48 +19,55 @@ import ( func (suite *KeeperTestSuite) TestCreateClient() { var ( - clientState exported.ClientState - consensusState exported.ConsensusState + clientState []byte + consensusState []byte ) testCases := []struct { - msg string - malleate func() - expPass bool + msg string + malleate func() + clientType string + expPass bool }{ { "success: 07-tendermint client type supported", func() { - clientState = ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) - consensusState = suite.consensusState + tmClientState := ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + clientState = suite.chainA.App.AppCodec().MustMarshal(tmClientState) + consensusState = suite.chainA.App.AppCodec().MustMarshal(suite.consensusState) }, + exported.Tendermint, true, }, { "failure: 07-tendermint client status is not active", func() { - clientState = ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) - tmcs, ok := clientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmcs.FrozenHeight = ibctm.FrozenHeight - consensusState = suite.consensusState + tmClientState := ibctm.NewClientState(testChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod, maxClockDrift, testClientHeight, commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + tmClientState.FrozenHeight = ibctm.FrozenHeight + clientState = suite.chainA.App.AppCodec().MustMarshal(tmClientState) + consensusState = suite.chainA.App.AppCodec().MustMarshal(suite.consensusState) }, + exported.Tendermint, false, }, { "success: 06-solomachine client type supported", func() { - clientState = solomachine.NewClientState(0, &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time}) - consensusState = &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time} + smClientState := solomachine.NewClientState(0, &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time}) + smConsensusState := &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time} + clientState = suite.chainA.App.AppCodec().MustMarshal(smClientState) + consensusState = suite.chainA.App.AppCodec().MustMarshal(smConsensusState) }, + exported.Solomachine, true, }, { "failure: 09-localhost client type not supported", func() { - clientState = localhost.NewClientState(clienttypes.GetSelfHeight(suite.chainA.GetContext())) - consensusState = nil + lhClientState := localhost.NewClientState(clienttypes.GetSelfHeight(suite.chainA.GetContext())) + clientState = suite.chainA.App.AppCodec().MustMarshal(lhClientState) }, + exported.Localhost, false, }, } @@ -70,12 +77,11 @@ func (suite *KeeperTestSuite) TestCreateClient() { suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { suite.SetupTest() // reset - tc.malleate() + clientState, consensusState = []byte{}, []byte{} - clientStateBz := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.MustMarshalClientState(clientState) - consensusStateBz := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.MustMarshalConsensusState(consensusState) + tc.malleate() - clientID, err := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.CreateClient(suite.chainA.GetContext(), clientState.ClientType(), clientStateBz, consensusStateBz) + clientID, err := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.CreateClient(suite.chainA.GetContext(), tc.clientType, clientState, consensusState) // assert correct behaviour based on expected error clientState, found := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.GetClientState(suite.chainA.GetContext(), clientID) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 1422ec84df1..be4768271a4 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -425,7 +425,7 @@ func (k Keeper) GetClientStatus(ctx sdk.Context, clientID string) exported.Statu return exported.Unauthorized } - lightClientModule, found := k.router.GetRoute(clientID) + lightClientModule, found := k.router.GetRoute(clientType) if !found { return exported.Unauthorized } diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 298dcb3ea52..155cf670afd 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -47,6 +47,7 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client if err := lcm.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { return err } + if err := consensusState.ValidateBasic(); err != nil { return err } From a7f995d83d603b28f8aa82174ec3e2a4a694e6da Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 17:15:23 +0100 Subject: [PATCH 17/74] chore: add clientRouter to 08-wasm simapp and wire up --- .../08-wasm/light_client_module.go | 7 +++++++ .../08-wasm/testing/simapp/app.go | 18 +++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index b4fb8f08032..65e24d0940c 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -21,6 +21,13 @@ type LightClientModule struct { keeper keeper.Keeper } +// NewLightClientModule creates and returns a new 08-wasm LightClientModule. +func NewLightClientModule(keeper keeper.Keeper) LightClientModule { + return LightClientModule{ + keeper: keeper, + } +} + // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index 830ca619957..501dca57e76 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -596,6 +596,18 @@ func NewSimApp( // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() + + tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) + + smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) + clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule) + + wasmLightClientModule := wasm.NewLightClientModule(app.WasmClientKeeper) + clientRouter.AddRoute(wasmtypes.ModuleName, wasmLightClientModule) + + // wasmClientModule := wasm. // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.AddressCodec(), runtime.ProvideCometInfoService(), @@ -640,9 +652,9 @@ func NewSimApp( transfer.NewAppModule(app.TransferKeeper), ibcfee.NewAppModule(app.IBCFeeKeeper), ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), - wasm.NewAppModule(app.WasmClientKeeper), - ibctm.AppModuleBasic{}, - solomachine.AppModuleBasic{}, + wasm.NewAppModule(app.WasmClientKeeper), // TODO(damian): see if we want to pass the lightclient module here, keeper is used in AppModule.RegisterServices etc + ibctm.NewAppModule(tmLightClientModule), + solomachine.NewAppModule(smLightClientModule), mockModule, ) From 46ebec259d45981f60e168f0e25fd5cd038e3ddb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 30 Jan 2024 17:28:10 +0100 Subject: [PATCH 18/74] fix: solo machine unmarshal bug and 02-client keeper tests --- modules/core/02-client/keeper/client_test.go | 2 +- modules/core/02-client/keeper/events_test.go | 2 +- modules/core/02-client/keeper/grpc_query_test.go | 2 +- .../light-clients/06-solomachine/light_client_module.go | 8 ++++---- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 7a47cd894a6..b387077b23e 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -53,7 +53,7 @@ func (suite *KeeperTestSuite) TestCreateClient() { { "success: 06-solomachine client type supported", func() { - smClientState := solomachine.NewClientState(0, &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time}) + smClientState := solomachine.NewClientState(1, &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time}) smConsensusState := &solomachine.ConsensusState{PublicKey: suite.solomachine.ConsensusState().PublicKey, Diversifier: suite.solomachine.Diversifier, Timestamp: suite.solomachine.Time} clientState = suite.chainA.App.AppCodec().MustMarshal(smClientState) consensusState = suite.chainA.App.AppCodec().MustMarshal(smConsensusState) diff --git a/modules/core/02-client/keeper/events_test.go b/modules/core/02-client/keeper/events_test.go index c5d1fdd3057..24757f56ecd 100644 --- a/modules/core/02-client/keeper/events_test.go +++ b/modules/core/02-client/keeper/events_test.go @@ -39,7 +39,7 @@ func (suite *KeeperTestSuite) TestMsgCreateClientEvents() { clienttypes.EventTypeCreateClient, sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID), sdk.NewAttribute(clienttypes.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), + // sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), ), }.ToABCIEvents() diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 9e15f9808b1..af50c908f88 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -526,7 +526,7 @@ func (suite *KeeperTestSuite) TestQueryClientStatus() { ClientId: ibctesting.InvalidID, } }, - false, "", + true, exported.Unauthorized.String(), }, { "Active client status", diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 02b8624629e..9ccbc2e8c66 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -214,8 +214,8 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) } - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + var clientState exported.ClientState + if err := l.keeper.Codec().UnmarshalInterface(bz, &clientState); err != nil { panic(err) } @@ -234,8 +234,8 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return 0, fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) } - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { + var clientState exported.ClientState + if err := l.keeper.Codec().UnmarshalInterface(bz, &clientState); err != nil { return 0, err } From 896f22569c439970fba1d2bba7154aa4a595ddbe Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 17:37:30 +0100 Subject: [PATCH 19/74] test: fix GetTimestampAtHeight test in clientkeeper --- modules/core/02-client/keeper/keeper.go | 2 +- modules/core/02-client/keeper/keeper_test.go | 115 +++++++++---------- 2 files changed, 58 insertions(+), 59 deletions(-) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index be4768271a4..5219ccd5ca2 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -445,7 +445,7 @@ func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, clientID string, height ex return 0, errorsmod.Wrapf(types.ErrInvalidClientType, "client state type %s is not registered in the allowlist", clientType) } - lightClientModule, found := k.router.GetRoute(clientID) + lightClientModule, found := k.router.GetRoute(clientType) if !found { return 0, errorsmod.Wrap(types.ErrRouteNotFound, clientType) } diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 5d2d044a9a1..0b0b8238d0a 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -431,64 +431,63 @@ func (suite KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this } } -// TODO(damian): uncomment and address this test -// func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { -// var ( -// clientID string -// height exported.Height -// ) - -// cases := []struct { -// msg string -// malleate func() -// expPass bool -// }{ -// { -// "verification success", -// func() { -// path := ibctesting.NewPath(suite.chainA, suite.chainB) -// path.SetupConnections() - -// clientID = path.EndpointA.ClientID -// height = suite.chainB.LatestCommittedHeader.GetHeight() -// }, -// true, -// }, -// { -// "client state not found", -// func() {}, -// false, -// }, -// { -// "consensus state not found", func() { -// path := ibctesting.NewPath(suite.chainA, suite.chainB) -// path.SetupConnections() -// clientID = path.EndpointA.ClientID -// height = suite.chainB.LatestCommittedHeader.GetHeight().Increment() -// }, -// false, -// }, -// } - -// for _, tc := range cases { -// suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { -// suite.SetupTest() // reset - -// tc.malleate() - -// actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight( -// suite.chainA.GetContext(), clientID, height, -// ) - -// if tc.expPass { -// suite.Require().NoError(err) -// suite.Require().EqualValues(uint64(suite.chainB.LatestCommittedHeader.GetTime().UnixNano()), actualTimestamp) -// } else { -// suite.Require().Error(err) -// } -// }) -// } -// } +func (suite *KeeperTestSuite) TestGetTimestampAtHeight() { + var ( + clientID string + height exported.Height + ) + + cases := []struct { + msg string + malleate func() + expPass bool + }{ + { + "verification success", + func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupConnections() + + clientID = path.EndpointA.ClientID + height = suite.chainB.LatestCommittedHeader.GetHeight() + }, + true, + }, + { + "client state not found", + func() {}, + false, + }, + { + "consensus state not found", func() { + path := ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupConnections() + clientID = path.EndpointA.ClientID + height = suite.chainB.LatestCommittedHeader.GetHeight().Increment() + }, + false, + }, + } + + for _, tc := range cases { + suite.Run(fmt.Sprintf("Case %s", tc.msg), func() { + suite.SetupTest() // reset + + tc.malleate() + + actualTimestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight( + suite.chainA.GetContext(), clientID, height, + ) + + if tc.expPass { + suite.Require().NoError(err) + suite.Require().EqualValues(uint64(suite.chainB.LatestCommittedHeader.GetTime().UnixNano()), actualTimestamp) + } else { + suite.Require().Error(err) + } + }) + } +} // TestDefaultSetParams tests the default params set are what is expected func (suite *KeeperTestSuite) TestDefaultSetParams() { From 55ffa1911d41f4f8fc8da4e687bdaaf4098bec94 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 18:18:13 +0100 Subject: [PATCH 20/74] refactor(solomachine): add getClientState helper and unmarhsal interface --- .../06-solomachine/light_client_module.go | 129 +++++++----------- modules/light-clients/06-solomachine/store.go | 20 +++ 2 files changed, 72 insertions(+), 77 deletions(-) create mode 100644 modules/light-clients/06-solomachine/store.go diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 9ccbc2e8c66..44550d84148 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -1,8 +1,6 @@ package solomachine import ( - "fmt" - errorsmod "cosmossdk.io/errors" storetypes "cosmossdk.io/store/types" @@ -10,7 +8,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine/internal/keeper" ) @@ -54,8 +51,10 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return err } - store := l.keeper.ClientStore(ctx, clientID) - return clientState.Initialize(ctx, l.keeper.Codec(), store, &consensusState) + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() + + return clientState.Initialize(ctx, cdc, clientStore, &consensusState) } // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. @@ -67,18 +66,15 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return err + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), store, clientMsg) + return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), clientStore, clientMsg) } // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage @@ -88,18 +84,15 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string panic(err) } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.CheckForMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) + return clientState.CheckForMisbehaviour(ctx, l.keeper.Codec(), clientStore, clientMsg) } // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified @@ -108,18 +101,15 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s panic(err) } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - clientState.UpdateStateOnMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) + clientState.UpdateStateOnMisbehaviour(ctx, l.keeper.Codec(), clientStore, clientMsg) } // UpdateState updates and stores as necessary any associated information for an IBC client, such as the ClientState and corresponding ConsensusState. @@ -129,18 +119,15 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM panic(err) } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := getClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.UpdateState(ctx, l.keeper.Codec(), store, clientMsg) + return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. @@ -159,18 +146,15 @@ func (l LightClientModule) VerifyMembership( return err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return err + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path, value) + return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. @@ -188,18 +172,15 @@ func (l LightClientModule) VerifyNonMembership( return err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return err + clientState, found := getClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyNonMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path) + return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } // Status must return the status of the client. Only Active clients are allowed to process packets. @@ -208,18 +189,15 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta return exported.Unknown // TODO: or panic } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState exported.ClientState - if err := l.keeper.Codec().UnmarshalInterface(bz, &clientState); err != nil { - panic(err) + clientState, found := getClientState(clientStore, cdc) + if !found { + return exported.Unknown } - return clientState.Status(ctx, store, l.keeper.Codec()) + return clientState.Status(ctx, clientStore, cdc) } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. @@ -228,18 +206,15 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return 0, err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return 0, fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState exported.ClientState - if err := l.keeper.Codec().UnmarshalInterface(bz, &clientState); err != nil { - return 0, err + clientState, found := getClientState(clientStore, cdc) + if !found { + return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.GetTimestampAtHeight(ctx, store, l.keeper.Codec(), height) + return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } func validateClientID(clientID string) error { diff --git a/modules/light-clients/06-solomachine/store.go b/modules/light-clients/06-solomachine/store.go new file mode 100644 index 00000000000..f974882dcac --- /dev/null +++ b/modules/light-clients/06-solomachine/store.go @@ -0,0 +1,20 @@ +package solomachine + +import ( + storetypes "cosmossdk.io/store/types" + + "github.com/cosmos/cosmos-sdk/codec" + + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" +) + +func getClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return nil, false + } + + clientStateI := clienttypes.MustUnmarshalClientState(cdc, bz) + return clientStateI.(*ClientState), true +} From 3e9a40c27169a9e986b4ed700c4201728e39cb0f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 18:26:57 +0100 Subject: [PATCH 21/74] refactor: align 08-wasm, add GetClientState helper and unmarshal interface --- .../08-wasm/light_client_module.go | 129 +++++++----------- modules/light-clients/08-wasm/types/store.go | 14 ++ 2 files changed, 66 insertions(+), 77 deletions(-) diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 65e24d0940c..0f0e343efdd 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -1,8 +1,6 @@ package wasm import ( - "fmt" - errorsmod "cosmossdk.io/errors" sdk "github.com/cosmos/cosmos-sdk/types" @@ -10,7 +8,6 @@ import ( "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -53,8 +50,10 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return err } - store := l.keeper.ClientStore(ctx, clientID) - return clientState.Initialize(ctx, l.keeper.Codec(), store, &consensusState) + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() + + return clientState.Initialize(ctx, cdc, clientStore, &consensusState) } // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. @@ -66,18 +65,15 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return err + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), store, clientMsg) + return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), clientStore, clientMsg) } // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage @@ -87,18 +83,15 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string panic(err) } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.CheckForMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) + return clientState.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) } // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified @@ -107,18 +100,15 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s panic(err) } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - clientState.UpdateStateOnMisbehaviour(ctx, l.keeper.Codec(), store, clientMsg) + clientState.UpdateStateOnMisbehaviour(ctx, cdc, clientStore, clientMsg) } // UpdateState updates and stores as necessary any associated information for an IBC client, such as the ClientState and corresponding ConsensusState. @@ -128,18 +118,15 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM panic(err) } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.UpdateState(ctx, l.keeper.Codec(), store, clientMsg) + return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. @@ -158,18 +145,15 @@ func (l LightClientModule) VerifyMembership( return err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return err + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path, value) + return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. @@ -187,18 +171,15 @@ func (l LightClientModule) VerifyNonMembership( return err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return err + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyNonMembership(ctx, store, l.keeper.Codec(), height, delayTimePeriod, delayBlockPeriod, proof, path) + return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } // Status must return the status of the client. Only Active clients are allowed to process packets. @@ -207,18 +188,15 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta return exported.Unknown // TODO: or panic } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - panic(fmt.Errorf("failed to retrieve client state for client ID: %s", clientID)) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - panic(err) + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return exported.Unknown } - return clientState.Status(ctx, store, l.keeper.Codec()) + return clientState.Status(ctx, clientStore, cdc) } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. @@ -227,18 +205,15 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return 0, err } - store := l.keeper.ClientStore(ctx, clientID) - bz := store.Get(host.ClientStateKey()) - if len(bz) == 0 { - return 0, fmt.Errorf("failed to retrieve client state for client ID: %s", clientID) - } + clientStore := l.keeper.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() - var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(bz, &clientState); err != nil { - return 0, err + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.GetTimestampAtHeight(ctx, store, l.keeper.Codec(), height) + return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } func validateClientID(clientID string) error { diff --git a/modules/light-clients/08-wasm/types/store.go b/modules/light-clients/08-wasm/types/store.go index 9f6cbcb49b7..c96e0b22493 100644 --- a/modules/light-clients/08-wasm/types/store.go +++ b/modules/light-clients/08-wasm/types/store.go @@ -17,7 +17,11 @@ import ( "cosmossdk.io/store/tracekv" storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) var ( @@ -28,6 +32,16 @@ var ( substitutePrefix = []byte("substitute/") ) +func GetClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { + bz := store.Get(host.ClientStateKey()) + if len(bz) == 0 { + return nil, false + } + + clientStateI := clienttypes.MustUnmarshalClientState(cdc, bz) + return clientStateI.(*ClientState), true +} + // Checksum is a type alias used for wasm byte code checksums. type Checksum = wasmvmtypes.Checksum From 61311e8a19e8b845fd60a714c12c6a6bc4c694c8 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 20:18:43 +0100 Subject: [PATCH 22/74] fix(temp): temporarily add WithStoreKey opt to wasmkeeper to fix failing tests --- modules/light-clients/08-wasm/keeper/options.go | 9 +++++++++ modules/light-clients/08-wasm/testing/simapp/app.go | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/light-clients/08-wasm/keeper/options.go b/modules/light-clients/08-wasm/keeper/options.go index 8977a6df371..b45c0c949bf 100644 --- a/modules/light-clients/08-wasm/keeper/options.go +++ b/modules/light-clients/08-wasm/keeper/options.go @@ -3,6 +3,8 @@ package keeper import ( "errors" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ) @@ -30,3 +32,10 @@ func WithQueryPlugins(plugins *types.QueryPlugins) Option { ibcwasm.SetQueryPlugins(&newPlugins) }) } + +// TODO(damian): remove this in favour of store service approach +func WithStoreKey(storeKey storetypes.StoreKey) Option { + return optsFn(func(k *Keeper) { + k.storeKey = storeKey + }) +} diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index 501dca57e76..7abae6ebe3d 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -471,7 +471,7 @@ func NewSimApp( // NOTE: mockVM is used for testing purposes only! app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( appCodec, runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), mockVM, app.GRPCQueryRouter(), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), mockVM, app.GRPCQueryRouter(), wasmkeeper.WithStoreKey(keys[ibcexported.StoreKey]), ) } else { app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( From daf3b474f4dd7087a1f0a8c564be1d9d26d1f3bc Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 20:24:56 +0100 Subject: [PATCH 23/74] fix: wire up callbacks simapp to fix failing tests --- modules/apps/callbacks/testing/simapp/app.go | 12 ++++++++++-- testing/simapp/app.go | 6 +++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 56cce8c58d2..1961a248ef9 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -567,6 +567,14 @@ func NewSimApp( // Seal the IBC Router app.IBCKeeper.SetRouter(ibcRouter) + clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() + + tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) + clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) + + smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) + clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule) + // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.AddressCodec(), runtime.ProvideCometInfoService(), @@ -611,8 +619,8 @@ func NewSimApp( transfer.NewAppModule(app.TransferKeeper), ibcfee.NewAppModule(app.IBCFeeKeeper), ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), - ibctm.NewAppModule(), - solomachine.NewAppModule(), + ibctm.NewAppModule(tmLightClientModule), + solomachine.NewAppModule(smLightClientModule), mockModule, ) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 97fbe9ec412..2098e997ad8 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -566,8 +566,8 @@ func NewSimApp( tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) - smClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) - clientRouter.AddRoute(solomachine.ModuleName, smClientModule) + smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) + clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule) // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( @@ -614,7 +614,7 @@ func NewSimApp( ibcfee.NewAppModule(app.IBCFeeKeeper), ica.NewAppModule(&app.ICAControllerKeeper, &app.ICAHostKeeper), ibctm.NewAppModule(tmLightClientModule), - solomachine.NewAppModule(smClientModule), + solomachine.NewAppModule(smLightClientModule), mockModule, ) From a4cc0bc5b2bab3ec87118dfa1bf4800f210ea8a0 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Tue, 30 Jan 2024 20:43:37 +0100 Subject: [PATCH 24/74] refactor: modify UpdateClient handler to use light client module api --- modules/core/02-client/keeper/client.go | 31 ++++++++++++++----------- modules/core/02-client/keeper/events.go | 4 ++-- 2 files changed, 19 insertions(+), 16 deletions(-) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index b6c88d959db..53ed40d2b92 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -61,24 +61,27 @@ func (k Keeper) CreateClient( // UpdateClient updates the consensus state and the state root from a provided header. func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - clientState, found := k.GetClientState(ctx, clientID) - if !found { - return errorsmod.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) + if status := k.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(types.ErrClientNotActive, "cannot update client (%s) with status %s", clientID, status) } - clientStore := k.ClientStore(ctx, clientID) + clientType, _, err := types.ParseClientIdentifier(clientID) + if err != nil { + return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) + } - if status := k.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(types.ErrClientNotActive, "cannot update client (%s) with status %s", clientID, status) + lightClientModule, found := k.router.GetRoute(clientType) + if !found { + return errorsmod.Wrap(types.ErrRouteNotFound, clientType) } - if err := clientState.VerifyClientMessage(ctx, k.cdc, clientStore, clientMsg); err != nil { + if err := lightClientModule.VerifyClientMessage(ctx, clientID, clientMsg); err != nil { return err } - foundMisbehaviour := clientState.CheckForMisbehaviour(ctx, k.cdc, clientStore, clientMsg) + foundMisbehaviour := lightClientModule.CheckForMisbehaviour(ctx, clientID, clientMsg) if foundMisbehaviour { - clientState.UpdateStateOnMisbehaviour(ctx, k.cdc, clientStore, clientMsg) + lightClientModule.UpdateStateOnMisbehaviour(ctx, clientID, clientMsg) k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", clientID) @@ -86,18 +89,18 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte []string{"ibc", "client", "misbehaviour"}, 1, []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), + telemetry.NewLabel(types.LabelClientType, clientType), telemetry.NewLabel(types.LabelClientID, clientID), telemetry.NewLabel(types.LabelMsgType, "update"), }, ) - emitSubmitMisbehaviourEvent(ctx, clientID, clientState) + emitSubmitMisbehaviourEvent(ctx, clientID, clientType) return nil } - consensusHeights := clientState.UpdateState(ctx, k.cdc, clientStore, clientMsg) + consensusHeights := lightClientModule.UpdateState(ctx, clientID, clientMsg) k.Logger(ctx).Info("client state updated", "client-id", clientID, "heights", consensusHeights) @@ -105,14 +108,14 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte []string{"ibc", "client", "update"}, 1, []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, clientState.ClientType()), + telemetry.NewLabel(types.LabelClientType, clientType), telemetry.NewLabel(types.LabelClientID, clientID), telemetry.NewLabel(types.LabelUpdateType, "msg"), }, ) // emitting events in the keeper emits for both begin block and handler client updates - emitUpdateClientEvent(ctx, clientID, clientState.ClientType(), consensusHeights, k.cdc, clientMsg) + emitUpdateClientEvent(ctx, clientID, clientType, consensusHeights, k.cdc, clientMsg) return nil } diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index b5c443bb0fe..3c57db7ef2e 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -76,12 +76,12 @@ func emitUpgradeClientEvent(ctx sdk.Context, clientID string, clientState export } // emitSubmitMisbehaviourEvent emits a client misbehaviour event -func emitSubmitMisbehaviourEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { +func emitSubmitMisbehaviourEvent(ctx sdk.Context, clientID string, clientType string) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeSubmitMisbehaviour, sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), + sdk.NewAttribute(types.AttributeKeyClientType, clientType), ), sdk.NewEvent( sdk.EventTypeMessage, From 3020f381bc068374d3d61e0fd4cc72c1822f3f3f Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 31 Jan 2024 15:34:07 +0100 Subject: [PATCH 25/74] feat: add ClientStoreProvider interface for isolated prefix stores (#5781) --- modules/apps/callbacks/testing/simapp/app.go | 8 ++-- modules/core/02-client/keeper/keeper.go | 4 +- modules/core/02-client/types/router.go | 19 ++++++---- modules/core/02-client/types/store.go | 31 +++++++++++++++ modules/core/exported/client.go | 9 +++++ modules/core/keeper/keeper.go | 2 +- .../06-solomachine/internal/keeper/keeper.go | 23 ++--------- .../06-solomachine/light_client_module.go | 30 ++++++++------- .../07-tendermint/internal/keeper/keeper.go | 23 +---------- .../07-tendermint/light_client_module.go | 38 +++++++++++-------- .../light-clients/08-wasm/keeper/keeper.go | 10 ----- .../light-clients/08-wasm/keeper/options.go | 9 ----- .../08-wasm/light_client_module.go | 25 +++++++----- .../08-wasm/testing/simapp/app.go | 12 +++--- .../09-localhost/internal/keeper/keeper.go | 23 +---------- .../09-localhost/light_client_module.go | 26 ++++++++----- testing/simapp/app.go | 8 ++-- 17 files changed, 147 insertions(+), 153 deletions(-) create mode 100644 modules/core/02-client/types/store.go diff --git a/modules/apps/callbacks/testing/simapp/app.go b/modules/apps/callbacks/testing/simapp/app.go index 1961a248ef9..2854e75d45c 100644 --- a/modules/apps/callbacks/testing/simapp/app.go +++ b/modules/apps/callbacks/testing/simapp/app.go @@ -569,11 +569,11 @@ func NewSimApp( clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() - tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) - clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) + tmLightClientModule := ibctm.NewLightClientModule(appCodec, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + clientRouter.AddRoute(ibctm.ModuleName, &tmLightClientModule) - smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) - clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule) + smLightClientModule := solomachine.NewLightClientModule(appCodec) + clientRouter.AddRoute(solomachine.ModuleName, &smLightClientModule) // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 5219ccd5ca2..c481978e495 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -38,11 +38,11 @@ type Keeper struct { } // NewKeeper creates a new NewKeeper instance -func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, router *types.Router, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper { +func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper { return Keeper{ storeKey: key, cdc: cdc, - router: router, + router: types.NewRouter(key), legacySubspace: legacySubspace, stakingKeeper: sk, upgradeKeeper: uk, diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index 3119da430ee..bd41e3925e3 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -3,33 +3,38 @@ package types import ( "fmt" + storetypes "cosmossdk.io/store/types" + "github.com/cosmos/ibc-go/v8/modules/core/exported" ) // The router is a map from module name to the LightClientModule // which contains all the module-defined callbacks required by ICS-26 type Router struct { - routes map[string]exported.LightClientModule - sealed bool + routes map[string]exported.LightClientModule + storeProvider exported.ClientStoreProvider } -func NewRouter() *Router { +func NewRouter(key storetypes.StoreKey) *Router { return &Router{ - routes: make(map[string]exported.LightClientModule), + routes: make(map[string]exported.LightClientModule), + storeProvider: NewStoreProvider(key), } } // AddRoute adds LightClientModule for a given module name. It returns the Router // so AddRoute calls can be linked. It will panic if the Router is sealed. -func (rtr *Router) AddRoute(module string, cbs exported.LightClientModule) *Router { +func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule) *Router { // if !sdk.IsAlphaNumeric(module) { // panic(errors.New("route expressions can only contain alphanumeric characters")) // } - if rtr.HasRoute(module) { + if rtr.HasRoute(clientType) { panic(fmt.Errorf("route %s has already been registered", module)) } - rtr.routes[module] = cbs + rtr.routes[clientType] = module + + module.RegisterStoreProvider(rtr.storeProvider) return rtr } diff --git a/modules/core/02-client/types/store.go b/modules/core/02-client/types/store.go new file mode 100644 index 00000000000..d527a12d548 --- /dev/null +++ b/modules/core/02-client/types/store.go @@ -0,0 +1,31 @@ +package types + +import ( + "fmt" + + "cosmossdk.io/store/prefix" + storetypes "cosmossdk.io/store/types" + + sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +var _ exported.ClientStoreProvider = (*storeProvider)(nil) + +type storeProvider struct { + storeKey storetypes.StoreKey +} + +func NewStoreProvider(storeKey storetypes.StoreKey) exported.ClientStoreProvider { + return storeProvider{ + storeKey: storeKey, + } +} + +// ClientStore returns isolated prefix store for each client so they can read/write in separate +// namespace without being able to read/write other client's data +func (s storeProvider) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { + clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) + return prefix.NewStore(ctx.KVStore(s.storeKey), clientPrefix) +} diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 9f2bb0903e7..61785dbbc84 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -44,7 +44,16 @@ const ( Unauthorized Status = "Unauthorized" ) +type ClientStoreProvider interface { + ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore +} + type LightClientModule interface { + // RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. + // It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores + // to IBC light client instances. + RegisterStoreProvider(storeProvider ClientStoreProvider) + // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. Initialize(ctx sdk.Context, clientID string, clientState, consensusState []byte) error diff --git a/modules/core/keeper/keeper.go b/modules/core/keeper/keeper.go index 4655a427ef1..08ee5dc027e 100644 --- a/modules/core/keeper/keeper.go +++ b/modules/core/keeper/keeper.go @@ -59,7 +59,7 @@ func NewKeeper( panic(errors.New("authority must be non-empty")) } - clientKeeper := clientkeeper.NewKeeper(cdc, key, clienttypes.NewRouter(), paramSpace, stakingKeeper, upgradeKeeper) + clientKeeper := clientkeeper.NewKeeper(cdc, key, paramSpace, stakingKeeper, upgradeKeeper) connectionKeeper := connectionkeeper.NewKeeper(cdc, key, paramSpace, clientKeeper) portKeeper := portkeeper.NewKeeper(scopedKeeper) channelKeeper := channelkeeper.NewKeeper(cdc, key, clientKeeper, connectionKeeper, &portKeeper, scopedKeeper) diff --git a/modules/light-clients/06-solomachine/internal/keeper/keeper.go b/modules/light-clients/06-solomachine/internal/keeper/keeper.go index 348e8a62d83..046e4b90615 100644 --- a/modules/light-clients/06-solomachine/internal/keeper/keeper.go +++ b/modules/light-clients/06-solomachine/internal/keeper/keeper.go @@ -1,28 +1,19 @@ package keeper import ( - "fmt" - - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // Keeper defines the 06-solomachine Keeper. +// TODO(damian): delete the keeper and put the codec on the LightClientModule? type Keeper struct { - cdc codec.BinaryCodec - storeKey storetypes.StoreKey + cdc codec.BinaryCodec } // NewKeeper creates and returns a new 06-solomachine keeper. -func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Keeper { +func NewKeeper(cdc codec.BinaryCodec) Keeper { return Keeper{ - cdc: cdc, - storeKey: storeKey, + cdc: cdc, } } @@ -30,9 +21,3 @@ func NewKeeper(cdc codec.BinaryCodec, storeKey storetypes.StoreKey) Keeper { func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } - -// ClientStore returns a namespaced prefix store for the provided IBC client identifier. -func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { - clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) - return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) -} diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 44550d84148..80dc5cb39cc 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -2,7 +2,6 @@ package solomachine import ( errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -16,16 +15,21 @@ var _ exported.LightClientModule = (*LightClientModule)(nil) // LightClientModule implements the core IBC api.LightClientModule interface? type LightClientModule struct { - keeper keeper.Keeper + keeper keeper.Keeper + storeProvider exported.ClientStoreProvider } // NewLightClientModule creates and returns a new 06-solomachine LightClientModule. -func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) LightClientModule { +func NewLightClientModule(cdc codec.BinaryCodec) LightClientModule { return LightClientModule{ - keeper: keeper.NewKeeper(cdc, key), + keeper: keeper.NewKeeper(cdc), } } +func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + l.storeProvider = storeProvider +} + // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { @@ -51,7 +55,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() return clientState.Initialize(ctx, cdc, clientStore, &consensusState) @@ -66,7 +70,7 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -84,7 +88,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string panic(err) } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -101,7 +105,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s panic(err) } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -119,7 +123,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM panic(err) } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -146,7 +150,7 @@ func (l LightClientModule) VerifyMembership( return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -172,7 +176,7 @@ func (l LightClientModule) VerifyNonMembership( return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -189,7 +193,7 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta return exported.Unknown // TODO: or panic } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -206,7 +210,7 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return 0, err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) diff --git a/modules/light-clients/07-tendermint/internal/keeper/keeper.go b/modules/light-clients/07-tendermint/internal/keeper/keeper.go index 26ecfdf9e21..f76e86570f0 100644 --- a/modules/light-clients/07-tendermint/internal/keeper/keeper.go +++ b/modules/light-clients/07-tendermint/internal/keeper/keeper.go @@ -2,50 +2,31 @@ package keeper import ( "errors" - "fmt" "strings" - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // Keeper defines the tendermint light client module keeper type Keeper struct { - storeKey storetypes.StoreKey - cdc codec.BinaryCodec + cdc codec.BinaryCodec // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. authority string } -func NewKeeper( - cdc codec.BinaryCodec, - key storetypes.StoreKey, - authority string, -) Keeper { +func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper { if strings.TrimSpace(authority) == "" { panic(errors.New("authority must be non-empty")) } return Keeper{ cdc: cdc, - storeKey: key, authority: authority, } } -// ClientStore returns isolated prefix store for each client so they can read/write in separate -// namespace without being able to read/write other client's data -func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { - clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) - return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) -} - func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 155cf670afd..98625ef3ab3 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -2,7 +2,6 @@ package tendermint import ( errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,16 +11,23 @@ import ( "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/internal/keeper" ) +var _ exported.LightClientModule = (*LightClientModule)(nil) + type LightClientModule struct { - keeper keeper.Keeper + keeper keeper.Keeper + storeProvider exported.ClientStoreProvider } -func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) LightClientModule { +func NewLightClientModule(cdc codec.BinaryCodec, authority string) LightClientModule { return LightClientModule{ - keeper: keeper.NewKeeper(cdc, key, authority), + keeper: keeper.NewKeeper(cdc, authority), } } +func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + lcm.storeProvider = storeProvider +} + // Initialize checks that the initial consensus state is an 07-tendermint consensus state and // sets the client state, consensus state and associated metadata in the provided client store. func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { @@ -52,7 +58,7 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return err } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, &consensusState) } @@ -67,7 +73,7 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -88,7 +94,7 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -109,7 +115,7 @@ func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -129,7 +135,7 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien if clientType != exported.Tendermint { panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -159,7 +165,7 @@ func (lcm LightClientModule) VerifyMembership( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -188,7 +194,7 @@ func (lcm LightClientModule) VerifyNonMembership( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -209,7 +215,7 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S return exported.Unknown } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -234,7 +240,7 @@ func (lcm LightClientModule) TimestampAtHeight( return 0, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -255,7 +261,7 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -263,7 +269,7 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - substituteClientStore := lcm.keeper.ClientStore(ctx, substituteClientID) + substituteClientStore := lcm.storeProvider.ClientStore(ctx, substituteClientID) substituteClient, found := getClientState(substituteClientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) @@ -306,7 +312,7 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( return err } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) diff --git a/modules/light-clients/08-wasm/keeper/keeper.go b/modules/light-clients/08-wasm/keeper/keeper.go index c39d4b7191f..91e86798cc8 100644 --- a/modules/light-clients/08-wasm/keeper/keeper.go +++ b/modules/light-clients/08-wasm/keeper/keeper.go @@ -11,8 +11,6 @@ import ( "cosmossdk.io/core/store" errorsmod "cosmossdk.io/errors" - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -20,7 +18,6 @@ import ( "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // Keeper defines the 08-wasm keeper @@ -30,7 +27,6 @@ type Keeper struct { cdc codec.BinaryCodec - storeKey storetypes.StoreKey storeService store.KVStoreService clientKeeper types.ClientKeeper @@ -112,12 +108,6 @@ func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } -// ClientStore returns a namespaced prefix store for the provided IBC client identifier. -func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { - clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) - return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) -} - // GetAuthority returns the 08-wasm module's authority. func (k Keeper) GetAuthority() string { return k.authority diff --git a/modules/light-clients/08-wasm/keeper/options.go b/modules/light-clients/08-wasm/keeper/options.go index b45c0c949bf..8977a6df371 100644 --- a/modules/light-clients/08-wasm/keeper/options.go +++ b/modules/light-clients/08-wasm/keeper/options.go @@ -3,8 +3,6 @@ package keeper import ( "errors" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/internal/ibcwasm" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" ) @@ -32,10 +30,3 @@ func WithQueryPlugins(plugins *types.QueryPlugins) Option { ibcwasm.SetQueryPlugins(&newPlugins) }) } - -// TODO(damian): remove this in favour of store service approach -func WithStoreKey(storeKey storetypes.StoreKey) Option { - return optsFn(func(k *Keeper) { - k.storeKey = storeKey - }) -} diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 0f0e343efdd..e302a38b8bc 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -15,7 +15,8 @@ var _ exported.LightClientModule = (*LightClientModule)(nil) // LightClientModule implements the core IBC api.LightClientModule interface? type LightClientModule struct { - keeper keeper.Keeper + keeper keeper.Keeper + storeProvider exported.ClientStoreProvider } // NewLightClientModule creates and returns a new 08-wasm LightClientModule. @@ -25,6 +26,10 @@ func NewLightClientModule(keeper keeper.Keeper) LightClientModule { } } +func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + l.storeProvider = storeProvider +} + // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { @@ -50,7 +55,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() return clientState.Initialize(ctx, cdc, clientStore, &consensusState) @@ -65,7 +70,7 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -83,7 +88,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string panic(err) } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -100,7 +105,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s panic(err) } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -118,7 +123,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM panic(err) } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -145,7 +150,7 @@ func (l LightClientModule) VerifyMembership( return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -171,7 +176,7 @@ func (l LightClientModule) VerifyNonMembership( return err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -188,7 +193,7 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta return exported.Unknown // TODO: or panic } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) @@ -205,7 +210,7 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return 0, err } - clientStore := l.keeper.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index 7abae6ebe3d..8aa8aaa83f4 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -471,7 +471,7 @@ func NewSimApp( // NOTE: mockVM is used for testing purposes only! app.WasmClientKeeper = wasmkeeper.NewKeeperWithVM( appCodec, runtime.NewKVStoreService(keys[wasmtypes.StoreKey]), app.IBCKeeper.ClientKeeper, - authtypes.NewModuleAddress(govtypes.ModuleName).String(), mockVM, app.GRPCQueryRouter(), wasmkeeper.WithStoreKey(keys[ibcexported.StoreKey]), + authtypes.NewModuleAddress(govtypes.ModuleName).String(), mockVM, app.GRPCQueryRouter(), ) } else { app.WasmClientKeeper = wasmkeeper.NewKeeperWithConfig( @@ -598,14 +598,14 @@ func NewSimApp( clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() - tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) - clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) + tmLightClientModule := ibctm.NewLightClientModule(appCodec, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + clientRouter.AddRoute(ibctm.ModuleName, &tmLightClientModule) - smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) - clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule) + smLightClientModule := solomachine.NewLightClientModule(appCodec) + clientRouter.AddRoute(solomachine.ModuleName, &smLightClientModule) wasmLightClientModule := wasm.NewLightClientModule(app.WasmClientKeeper) - clientRouter.AddRoute(wasmtypes.ModuleName, wasmLightClientModule) + clientRouter.AddRoute(wasmtypes.ModuleName, &wasmLightClientModule) // wasmClientModule := wasm. // create evidence keeper with router diff --git a/modules/light-clients/09-localhost/internal/keeper/keeper.go b/modules/light-clients/09-localhost/internal/keeper/keeper.go index 522bb24455c..ed208013821 100644 --- a/modules/light-clients/09-localhost/internal/keeper/keeper.go +++ b/modules/light-clients/09-localhost/internal/keeper/keeper.go @@ -2,50 +2,31 @@ package keeper import ( "errors" - "fmt" "strings" - "cosmossdk.io/store/prefix" - storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/codec" - sdk "github.com/cosmos/cosmos-sdk/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) // Keeper defines the localhost light client module keeper type Keeper struct { - storeKey storetypes.StoreKey - cdc codec.BinaryCodec + cdc codec.BinaryCodec // the address capable of executing a MsgUpdateParams message. Typically, this // should be the x/gov module account. authority string } -func NewKeeper( - cdc codec.BinaryCodec, - key storetypes.StoreKey, - authority string, -) Keeper { +func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper { if strings.TrimSpace(authority) == "" { panic(errors.New("authority must be non-empty")) } return Keeper{ cdc: cdc, - storeKey: key, authority: authority, } } -// ClientStore returns isolated prefix store for each client so they can read/write in separate -// namespace without being able to read/write other client's data -func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { - clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) - return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) -} - func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index 0341316946e..f2b8154f4af 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -2,7 +2,6 @@ package localhost import ( errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" @@ -12,16 +11,23 @@ import ( "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost/internal/keeper" ) +var _ exported.LightClientModule = (*LightClientModule)(nil) + type LightClientModule struct { - keeper keeper.Keeper + keeper keeper.Keeper + storeProvider exported.ClientStoreProvider } -func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) LightClientModule { +func NewLightClientModule(cdc codec.BinaryCodec, authority string) LightClientModule { return LightClientModule{ - keeper: keeper.NewKeeper(cdc, key, authority), + keeper: keeper.NewKeeper(cdc, authority), } } +func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + lcm.storeProvider = storeProvider +} + func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { @@ -45,7 +51,7 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return err } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, nil) } @@ -60,7 +66,7 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -104,7 +110,7 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien if clientType != exported.Localhost { panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -134,7 +140,7 @@ func (lcm LightClientModule) VerifyMembership( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -163,7 +169,7 @@ func (lcm LightClientModule) VerifyNonMembership( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) @@ -184,7 +190,7 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S return exported.Unknown } - clientStore := lcm.keeper.ClientStore(ctx, clientID) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() clientState, found := getClientState(clientStore, cdc) diff --git a/testing/simapp/app.go b/testing/simapp/app.go index 2098e997ad8..d830dce6efd 100644 --- a/testing/simapp/app.go +++ b/testing/simapp/app.go @@ -563,11 +563,11 @@ func NewSimApp( clientRouter := app.IBCKeeper.ClientKeeper.GetRouter() - tmLightClientModule := ibctm.NewLightClientModule(appCodec, keys[ibcexported.StoreKey], authtypes.NewModuleAddress(govtypes.ModuleName).String()) - clientRouter.AddRoute(ibctm.ModuleName, tmLightClientModule) + tmLightClientModule := ibctm.NewLightClientModule(appCodec, authtypes.NewModuleAddress(govtypes.ModuleName).String()) + clientRouter.AddRoute(ibctm.ModuleName, &tmLightClientModule) - smLightClientModule := solomachine.NewLightClientModule(appCodec, keys[ibcexported.StoreKey]) - clientRouter.AddRoute(solomachine.ModuleName, smLightClientModule) + smLightClientModule := solomachine.NewLightClientModule(appCodec) + clientRouter.AddRoute(solomachine.ModuleName, &smLightClientModule) // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( From 92747c84305445a2a29b63e1936a6dbd3820a688 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 31 Jan 2024 15:49:53 +0100 Subject: [PATCH 26/74] refactor: rm internal/keeper from solomachine --- .../06-solomachine/internal/keeper/keeper.go | 23 ------- .../06-solomachine/light_client_module.go | 61 +++++++------------ 2 files changed, 21 insertions(+), 63 deletions(-) delete mode 100644 modules/light-clients/06-solomachine/internal/keeper/keeper.go diff --git a/modules/light-clients/06-solomachine/internal/keeper/keeper.go b/modules/light-clients/06-solomachine/internal/keeper/keeper.go deleted file mode 100644 index 046e4b90615..00000000000 --- a/modules/light-clients/06-solomachine/internal/keeper/keeper.go +++ /dev/null @@ -1,23 +0,0 @@ -package keeper - -import ( - "github.com/cosmos/cosmos-sdk/codec" -) - -// Keeper defines the 06-solomachine Keeper. -// TODO(damian): delete the keeper and put the codec on the LightClientModule? -type Keeper struct { - cdc codec.BinaryCodec -} - -// NewKeeper creates and returns a new 06-solomachine keeper. -func NewKeeper(cdc codec.BinaryCodec) Keeper { - return Keeper{ - cdc: cdc, - } -} - -// Codec returns the keeper codec. -func (k Keeper) Codec() codec.BinaryCodec { - return k.cdc -} diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 80dc5cb39cc..cb785b41ce3 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -8,21 +8,20 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" - "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine/internal/keeper" ) var _ exported.LightClientModule = (*LightClientModule)(nil) // LightClientModule implements the core IBC api.LightClientModule interface? type LightClientModule struct { - keeper keeper.Keeper + cdc codec.BinaryCodec storeProvider exported.ClientStoreProvider } // NewLightClientModule creates and returns a new 06-solomachine LightClientModule. func NewLightClientModule(cdc codec.BinaryCodec) LightClientModule { return LightClientModule{ - keeper: keeper.NewKeeper(cdc), + cdc: cdc, } } @@ -38,7 +37,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt } var clientState ClientState - if err := l.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + if err := l.cdc.Unmarshal(clientStateBz, &clientState); err != nil { return err } @@ -47,7 +46,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt } var consensusState ConsensusState - if err := l.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + if err := l.cdc.Unmarshal(consensusStateBz, &consensusState); err != nil { return err } @@ -56,9 +55,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - return clientState.Initialize(ctx, cdc, clientStore, &consensusState) + return clientState.Initialize(ctx, l.cdc, clientStore, &consensusState) } // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. @@ -71,14 +68,12 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), clientStore, clientMsg) + return clientState.VerifyClientMessage(ctx, l.cdc, clientStore, clientMsg) } // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage @@ -89,14 +84,12 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.CheckForMisbehaviour(ctx, l.keeper.Codec(), clientStore, clientMsg) + return clientState.CheckForMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified @@ -106,14 +99,12 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - clientState.UpdateStateOnMisbehaviour(ctx, l.keeper.Codec(), clientStore, clientMsg) + clientState.UpdateStateOnMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } // UpdateState updates and stores as necessary any associated information for an IBC client, such as the ClientState and corresponding ConsensusState. @@ -124,14 +115,12 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) + return clientState.UpdateState(ctx, l.cdc, clientStore, clientMsg) } // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. @@ -151,14 +140,12 @@ func (l LightClientModule) VerifyMembership( } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) + return clientState.VerifyMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. @@ -177,14 +164,12 @@ func (l LightClientModule) VerifyNonMembership( } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) + return clientState.VerifyNonMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } // Status must return the status of the client. Only Active clients are allowed to process packets. @@ -194,14 +179,12 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return exported.Unknown } - return clientState.Status(ctx, clientStore, cdc) + return clientState.Status(ctx, clientStore, l.cdc) } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. @@ -211,14 +194,12 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h } clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) + return clientState.GetTimestampAtHeight(ctx, clientStore, l.cdc, height) } func validateClientID(clientID string) error { From 379e0d3a6c8829b65af66284dc9f50ec0f149928 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 31 Jan 2024 15:53:53 +0100 Subject: [PATCH 27/74] refactor: begin removing stale client state interfaces --- modules/core/02-client/keeper/keeper.go | 7 +++- modules/core/exported/client.go | 32 ------------------- .../09-localhost/client_state.go | 7 +--- .../09-localhost/client_state_test.go | 7 +--- .../09-localhost/light_client_module.go | 22 ++----------- .../09-localhost/light_client_module_test.go | 11 +++++++ 6 files changed, 22 insertions(+), 64 deletions(-) create mode 100644 modules/light-clients/09-localhost/light_client_module_test.go diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index c481978e495..a7f13fcb04c 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -66,7 +66,12 @@ func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { // 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.LocalhostClientID), nil) + lightClientModule, found := k.router.GetRoute(exported.Localhost) + if !found { + panic(errorsmod.Wrap(types.ErrRouteNotFound, exported.Localhost)) + } + + return lightClientModule.UpdateState(ctx, exported.LocalhostClientID, nil) } // GenerateClientIdentifier returns the next client identifier. diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 61785dbbc84..0136c956c4c 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -141,9 +141,6 @@ type ClientState interface { GetLatestHeight() Height Validate() error - // Status must return the status of the client. Only Active clients are allowed to process packets. - Status(ctx sdk.Context, clientStore storetypes.KVStore, cdc codec.BinaryCodec) Status - // ExportMetadata must export metadata stored within the clientStore for genesis export ExportMetadata(clientStore storetypes.KVStore) []GenesisMetadata @@ -152,18 +149,6 @@ type ClientState interface { // Used to verify upgrades ZeroCustomFields() ClientState - // GetTimestampAtHeight must return the timestamp for the consensus state associated with the provided height. - GetTimestampAtHeight( - ctx sdk.Context, - clientStore storetypes.KVStore, - cdc codec.BinaryCodec, - height Height, - ) (uint64, error) - - // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the - // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. - Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, consensusState ConsensusState) error - // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). VerifyMembership( @@ -191,23 +176,6 @@ type ClientState interface { path Path, ) error - // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. - // It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour - // will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned - // if the ClientMessage fails to verify. - VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg ClientMessage) error - - // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage - // has already been verified. - CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg ClientMessage) bool - - // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified - UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg ClientMessage) - - // 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. - UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore storetypes.KVStore, clientMsg ClientMessage) []Height - // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. CheckSubstituteAndUpdateState(ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore storetypes.KVStore, substituteClient ClientState) error diff --git a/modules/light-clients/09-localhost/client_state.go b/modules/light-clients/09-localhost/client_state.go index 89c9b4a8c28..b6da37768e8 100644 --- a/modules/light-clients/09-localhost/client_state.go +++ b/modules/light-clients/09-localhost/client_state.go @@ -19,7 +19,7 @@ import ( var _ exported.ClientState = (*ClientState)(nil) // NewClientState creates a new 09-localhost ClientState instance. -func NewClientState(height clienttypes.Height) exported.ClientState { +func NewClientState(height clienttypes.Height) *ClientState { return &ClientState{ LatestHeight: height, } @@ -35,11 +35,6 @@ func (cs ClientState) GetLatestHeight() exported.Height { return cs.LatestHeight } -// Status always returns Active. The 09-localhost status cannot be changed. -func (ClientState) Status(_ sdk.Context, _ storetypes.KVStore, _ codec.BinaryCodec) exported.Status { - return exported.Active -} - // Validate performs a basic validation of the client state fields. func (cs ClientState) Validate() error { if cs.LatestHeight.RevisionHeight == 0 { diff --git a/modules/light-clients/09-localhost/client_state_test.go b/modules/light-clients/09-localhost/client_state_test.go index 7764289768d..3a85ad83ed1 100644 --- a/modules/light-clients/09-localhost/client_state_test.go +++ b/modules/light-clients/09-localhost/client_state_test.go @@ -15,11 +15,6 @@ import ( "github.com/cosmos/ibc-go/v8/testing/mock" ) -func (suite *LocalhostTestSuite) TestStatus() { - clientState := localhost.NewClientState(clienttypes.NewHeight(3, 10)) - suite.Require().Equal(exported.Active, clientState.Status(suite.chain.GetContext(), nil, nil)) -} - func (suite *LocalhostTestSuite) TestClientType() { clientState := localhost.NewClientState(clienttypes.NewHeight(3, 10)) suite.Require().Equal(exported.Localhost, clientState.ClientType()) @@ -419,7 +414,7 @@ func (suite *LocalhostTestSuite) TestUpdateState() { expHeight := clienttypes.NewHeight(1, uint64(suite.chain.GetContext().BlockHeight())) suite.Require().True(heights[0].EQ(expHeight)) - clientState = suite.chain.GetClientState(exported.LocalhostClientID) + clientState = suite.chain.GetClientState(exported.LocalhostClientID).(*localhost.ClientState) suite.Require().True(heights[0].EQ(clientState.GetLatestHeight())) } diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index f2b8154f4af..badeb1a2556 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -18,7 +18,7 @@ type LightClientModule struct { storeProvider exported.ClientStoreProvider } -func NewLightClientModule(cdc codec.BinaryCodec, authority string) LightClientModule { +func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) LightClientModule { return LightClientModule{ keeper: keeper.NewKeeper(cdc, authority), } @@ -180,25 +180,9 @@ func (lcm LightClientModule) VerifyNonMembership( return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } +// Status always returns Active. The 09-localhost status cannot be changed. func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return exported.Unknown - } - - if clientType != exported.Localhost { - return exported.Unknown - } - - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() - - clientState, found := getClientState(clientStore, cdc) - if !found { - return exported.Unknown - } - - return clientState.Status(ctx, clientStore, cdc) + return exported.Active } func (lcm LightClientModule) TimestampAtHeight( diff --git a/modules/light-clients/09-localhost/light_client_module_test.go b/modules/light-clients/09-localhost/light_client_module_test.go new file mode 100644 index 00000000000..340c9717f96 --- /dev/null +++ b/modules/light-clients/09-localhost/light_client_module_test.go @@ -0,0 +1,11 @@ +package localhost_test + +import ( + "github.com/cosmos/ibc-go/v8/modules/core/exported" +) + +func (s *LocalhostTestSuite) TestStatus() { + lightClientModule, found := s.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + s.Require().True(found) + s.Require().Equal(exported.Active, lightClientModule.Status(s.chain.GetContext(), exported.LocalhostClientID)) +} From 3099d335dd8a2d1c1ec37afad8859169f455b840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:10:46 +0100 Subject: [PATCH 28/74] feat: wire up localhost --- modules/core/02-client/keeper/keeper.go | 5 +-- .../09-localhost/internal/keeper/keeper.go | 32 ----------------- .../09-localhost/light_client_module.go | 36 +++++++++---------- 3 files changed, 20 insertions(+), 53 deletions(-) delete mode 100644 modules/light-clients/09-localhost/internal/keeper/keeper.go diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index a7f13fcb04c..3616a513c6f 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -60,8 +60,9 @@ func (k Keeper) GetRouter() *types.Router { // CreateLocalhostClient initialises the 09-localhost client state and sets it in state. func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - var clientState localhost.ClientState - return clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, exported.LocalhostClientID), nil) + localhostModule := localhost.NewLightClientModule(k.cdc, k.storeKey) + k.router.AddRoute(exported.Localhost, localhostModule) + return localhostModule.Initialize(ctx, exported.LocalhostClientID, nil, nil) } // UpdateLocalhostClient updates the 09-localhost client to the latest block height and chain ID. diff --git a/modules/light-clients/09-localhost/internal/keeper/keeper.go b/modules/light-clients/09-localhost/internal/keeper/keeper.go deleted file mode 100644 index ed208013821..00000000000 --- a/modules/light-clients/09-localhost/internal/keeper/keeper.go +++ /dev/null @@ -1,32 +0,0 @@ -package keeper - -import ( - "errors" - "strings" - - "github.com/cosmos/cosmos-sdk/codec" -) - -// Keeper defines the localhost light client module keeper -type Keeper struct { - cdc codec.BinaryCodec - - // the address capable of executing a MsgUpdateParams message. Typically, this - // should be the x/gov module account. - authority string -} - -func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper { - if strings.TrimSpace(authority) == "" { - panic(errors.New("authority must be non-empty")) - } - - return Keeper{ - cdc: cdc, - authority: authority, - } -} - -func (k Keeper) Codec() codec.BinaryCodec { - return k.cdc -} diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index badeb1a2556..4c6f849c655 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -2,25 +2,28 @@ package localhost import ( errorsmod "cosmossdk.io/errors" + storetypes "cosmossdk.io/store/types" "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" - "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost/internal/keeper" ) var _ exported.LightClientModule = (*LightClientModule)(nil) type LightClientModule struct { - keeper keeper.Keeper + cdc codec.BinaryCodec + key storetypes.StoreKey storeProvider exported.ClientStoreProvider } -func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey, authority string) LightClientModule { - return LightClientModule{ - keeper: keeper.NewKeeper(cdc, authority), +func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) *LightClientModule { + return &LightClientModule{ + cdc: cdc, + key: key, } } @@ -42,18 +45,13 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") } - var clientState ClientState - if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { - return err - } - - if err := clientState.Validate(); err != nil { - return err + clientState := ClientState{ + LatestHeight: clienttypes.GetSelfHeight(ctx), } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - - return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, nil) + clientStore := lcm.storeProvider.ClientStore(ctx, exported.LocalhostClientID) + clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(lcm.cdc, &clientState)) + return nil } func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { @@ -67,7 +65,7 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + cdc := lcm.cdc clientState, found := getClientState(clientStore, cdc) if !found { @@ -111,7 +109,7 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + cdc := lcm.cdc clientState, found := getClientState(clientStore, cdc) if !found { @@ -141,7 +139,7 @@ func (lcm LightClientModule) VerifyMembership( } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + cdc := lcm.cdc clientState, found := getClientState(clientStore, cdc) if !found { @@ -170,7 +168,7 @@ func (lcm LightClientModule) VerifyNonMembership( } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + cdc := lcm.cdc clientState, found := getClientState(clientStore, cdc) if !found { From 2ca1ddfd604410ca2640699acaa643b7d7dc921d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:18:13 +0100 Subject: [PATCH 29/74] fix: tests in 06-solomachine and 07-tendermint --- modules/light-clients/06-solomachine/update_test.go | 2 +- modules/light-clients/07-tendermint/client_state_test.go | 2 +- .../07-tendermint/misbehaviour_handle_test.go | 4 ++-- modules/light-clients/07-tendermint/update_test.go | 8 ++++---- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/modules/light-clients/06-solomachine/update_test.go b/modules/light-clients/06-solomachine/update_test.go index 30a3ff15986..4299f249fb1 100644 --- a/modules/light-clients/06-solomachine/update_test.go +++ b/modules/light-clients/06-solomachine/update_test.go @@ -399,7 +399,7 @@ func (suite *SoloMachineTestSuite) TestVerifyClientMessageMisbehaviour() { func (suite *SoloMachineTestSuite) TestUpdateState() { var ( - clientState exported.ClientState + clientState *solomachine.ClientState clientMsg exported.ClientMessage ) diff --git a/modules/light-clients/07-tendermint/client_state_test.go b/modules/light-clients/07-tendermint/client_state_test.go index 7c436531297..b0a81c69c8f 100644 --- a/modules/light-clients/07-tendermint/client_state_test.go +++ b/modules/light-clients/07-tendermint/client_state_test.go @@ -106,7 +106,7 @@ func (suite *TendermintTestSuite) TestGetTimestampAtHeight() { path = ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) height = clientState.GetLatestHeight() store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) diff --git a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go index 60363558811..346cba52d52 100644 --- a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go +++ b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go @@ -342,7 +342,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { tc.malleate() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, misbehaviour) @@ -629,7 +629,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { tc.malleate() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) err = clientState.VerifyClientMessage(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, misbehaviour) diff --git a/modules/light-clients/07-tendermint/update_test.go b/modules/light-clients/07-tendermint/update_test.go index 4c7f3de0a19..a87fa67e7a9 100644 --- a/modules/light-clients/07-tendermint/update_test.go +++ b/modules/light-clients/07-tendermint/update_test.go @@ -290,7 +290,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { tc.malleate() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) @@ -489,7 +489,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { tc.malleate() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) if tc.expPass { @@ -771,7 +771,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { tc.malleate() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) foundMisbehaviour := clientState.CheckForMisbehaviour( @@ -818,7 +818,7 @@ func (suite *TendermintTestSuite) TestUpdateStateOnMisbehaviour() { tc.malleate() - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) clientState.UpdateStateOnMisbehaviour(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), clientStore, nil) From 029f5ef8104122724765aa95db69a8ab9b4191e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:48:02 +0100 Subject: [PATCH 30/74] fix: rest of tests --- modules/core/02-client/keeper/keeper.go | 13 ++++++++++--- .../08-wasm/types/client_state_test.go | 4 ++-- .../08-wasm/types/misbehaviour_handle_test.go | 2 +- modules/light-clients/08-wasm/types/querier_test.go | 4 ++-- modules/light-clients/08-wasm/types/update_test.go | 4 ++-- modules/light-clients/08-wasm/types/upgrade_test.go | 2 +- 6 files changed, 18 insertions(+), 11 deletions(-) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 3616a513c6f..05ad97ee049 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -39,10 +39,14 @@ type Keeper struct { // NewKeeper creates a new NewKeeper instance func NewKeeper(cdc codec.BinaryCodec, key storetypes.StoreKey, legacySubspace types.ParamSubspace, sk types.StakingKeeper, uk types.UpgradeKeeper) Keeper { + router := types.NewRouter(key) + localhostModule := localhost.NewLightClientModule(cdc, key) + router.AddRoute(exported.Localhost, localhostModule) + return Keeper{ storeKey: key, cdc: cdc, - router: types.NewRouter(key), + router: router, legacySubspace: legacySubspace, stakingKeeper: sk, upgradeKeeper: uk, @@ -60,8 +64,11 @@ func (k Keeper) GetRouter() *types.Router { // CreateLocalhostClient initialises the 09-localhost client state and sets it in state. func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - localhostModule := localhost.NewLightClientModule(k.cdc, k.storeKey) - k.router.AddRoute(exported.Localhost, localhostModule) + localhostModule, found := k.router.GetRoute(exported.Localhost) + if !found { + errorsmod.Wrap(types.ErrRouteNotFound, exported.Localhost) + } + return localhostModule.Initialize(ctx, exported.LocalhostClientID, nil, nil) } diff --git a/modules/light-clients/08-wasm/types/client_state_test.go b/modules/light-clients/08-wasm/types/client_state_test.go index b2da5984a31..e28d7355ffe 100644 --- a/modules/light-clients/08-wasm/types/client_state_test.go +++ b/modules/light-clients/08-wasm/types/client_state_test.go @@ -85,7 +85,7 @@ func (suite *TypesTestSuite) TestStatus() { tc.malleate() clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) status := clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) suite.Require().Equal(tc.expStatus, status) @@ -233,7 +233,7 @@ func (suite *TypesTestSuite) TestValidate() { func (suite *TypesTestSuite) TestInitialize() { var ( consensusState exported.ConsensusState - clientState exported.ClientState + clientState *types.ClientState clientStore storetypes.KVStore ) diff --git a/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go b/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go index 05fd12e7566..9ab7c586832 100644 --- a/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go +++ b/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go @@ -77,7 +77,7 @@ func (suite *TypesTestSuite) TestCheckForMisbehaviour() { err := endpoint.CreateClient() suite.Require().NoError(err) - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) clientMessage = &types.ClientMessage{ Data: clienttypes.MustMarshalClientMessage(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientMisbehaviour), } diff --git a/modules/light-clients/08-wasm/types/querier_test.go b/modules/light-clients/08-wasm/types/querier_test.go index 89a9cf911f6..df3495e2722 100644 --- a/modules/light-clients/08-wasm/types/querier_test.go +++ b/modules/light-clients/08-wasm/types/querier_test.go @@ -106,7 +106,7 @@ func (suite *TypesTestSuite) TestCustomQuery() { tc.malleate() clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) // reset query plugins after each test @@ -191,7 +191,7 @@ func (suite *TypesTestSuite) TestStargateQuery() { tc.malleate() clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) // reset query plugins after each test diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index b1e4a4a9525..2c8ba4d1889 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -146,7 +146,7 @@ func (suite *TypesTestSuite) TestUpdateState() { tc.malleate() - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) var heights []exported.Height updateState := func() { @@ -273,7 +273,7 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { clientMsg = &types.ClientMessage{ Data: clienttypes.MustMarshalClientMessage(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientMisbehaviour), } - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) tc.malleate() diff --git a/modules/light-clients/08-wasm/types/upgrade_test.go b/modules/light-clients/08-wasm/types/upgrade_test.go index 7c75a90870f..84420353793 100644 --- a/modules/light-clients/08-wasm/types/upgrade_test.go +++ b/modules/light-clients/08-wasm/types/upgrade_test.go @@ -100,7 +100,7 @@ func (suite *TypesTestSuite) TestVerifyClientMessage() { suite.Require().NoError(err) clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState() + clientState := endpoint.GetClientState().(*types.ClientState) clientMsg = &types.ClientMessage{ Data: clienttypes.MustMarshalClientMessage(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientHeader), From 23b5cbb419afddce82bb18318959a597aeec5a12 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 31 Jan 2024 17:01:11 +0100 Subject: [PATCH 31/74] refactor: use light client module APIs in 03-connection state verify --- modules/core/03-connection/keeper/verify.go | 125 +++++++++++------- .../03-connection/types/expected_keepers.go | 2 + 2 files changed, 82 insertions(+), 45 deletions(-) diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 86909fc6ed7..b1b73c39c18 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -26,13 +26,18 @@ func (k Keeper) VerifyClientState( clientState exported.ClientState, ) error { clientID := connection.GetClientID() - targetClient, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(connection.GetCounterparty().GetClientID())) @@ -46,8 +51,8 @@ func (k Keeper) VerifyClientState( return err } - if err := targetClient.VerifyMembership( - ctx, clientStore, k.cdc, height, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, ); err != nil { @@ -68,13 +73,18 @@ func (k Keeper) VerifyClientConsensusState( consensusState exported.ConsensusState, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } merklePath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(connection.GetCounterparty().GetClientID(), consensusHeight)) @@ -88,8 +98,8 @@ func (k Keeper) VerifyClientConsensusState( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, ); err != nil { @@ -110,13 +120,18 @@ func (k Keeper) VerifyConnectionState( counterpartyConnection types.ConnectionEnd, // opposite connection ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) @@ -130,8 +145,8 @@ func (k Keeper) VerifyConnectionState( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, ); err != nil { @@ -153,13 +168,18 @@ func (k Keeper) VerifyChannelState( channel channeltypes.Channel, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) @@ -173,8 +193,8 @@ func (k Keeper) VerifyChannelState( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, ); err != nil { @@ -197,13 +217,18 @@ func (k Keeper) VerifyPacketCommitment( commitmentBytes []byte, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } // get time and block delays @@ -216,10 +241,8 @@ func (k Keeper) VerifyPacketCommitment( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, - timeDelay, blockDelay, - proof, merklePath, commitmentBytes, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, commitmentBytes, ); err != nil { return errorsmod.Wrapf(err, "failed packet commitment verification for client (%s)", clientID) } @@ -240,13 +263,18 @@ func (k Keeper) VerifyPacketAcknowledgement( acknowledgement []byte, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } // get time and block delays @@ -259,9 +287,8 @@ func (k Keeper) VerifyPacketAcknowledgement( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, - timeDelay, blockDelay, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, channeltypes.CommitAcknowledgement(acknowledgement), ); err != nil { return errorsmod.Wrapf(err, "failed packet acknowledgement verification for client (%s)", clientID) @@ -283,13 +310,18 @@ func (k Keeper) VerifyPacketReceiptAbsence( sequence uint64, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } // get time and block delays @@ -302,10 +334,8 @@ func (k Keeper) VerifyPacketReceiptAbsence( return err } - if err := clientState.VerifyNonMembership( - ctx, clientStore, k.cdc, height, - timeDelay, blockDelay, - proof, merklePath, + if err := lightClientModule.VerifyNonMembership( + ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, ); err != nil { return errorsmod.Wrapf(err, "failed packet receipt absence verification for client (%s)", clientID) } @@ -408,13 +438,18 @@ func (k Keeper) VerifyChannelUpgrade( upgrade channeltypes.Upgrade, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradePath(portID, channelID)) @@ -428,8 +463,8 @@ func (k Keeper) VerifyChannelUpgrade( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, proofHeight, + if err := lightClientModule.VerifyMembership( + ctx, clientID, proofHeight, 0, 0, // skip delay period checks for non-packet processing verification upgradeProof, merklePath, bz, ); err != nil { diff --git a/modules/core/03-connection/types/expected_keepers.go b/modules/core/03-connection/types/expected_keepers.go index bac734e0b40..8d95e20f87e 100644 --- a/modules/core/03-connection/types/expected_keepers.go +++ b/modules/core/03-connection/types/expected_keepers.go @@ -6,6 +6,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" paramtypes "github.com/cosmos/cosmos-sdk/x/params/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -18,6 +19,7 @@ type ClientKeeper interface { ValidateSelfClient(ctx sdk.Context, clientState exported.ClientState) error IterateClientStates(ctx sdk.Context, prefix []byte, cb func(string, exported.ClientState) bool) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore + GetRouter() *clienttypes.Router } // ParamSubspace defines the expected Subspace interface for module parameters. From 2a2133bd6ad51c190b2be55c9181f59af03e2cbf Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 31 Jan 2024 17:13:26 +0100 Subject: [PATCH 32/74] chore: adapt remaining handlers to use light client module api in 03-connection --- modules/core/03-connection/keeper/verify.go | 47 +++++++++------------ 1 file changed, 20 insertions(+), 27 deletions(-) diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index b1b73c39c18..7d9003ff938 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -4,7 +4,6 @@ import ( "math" errorsmod "cosmossdk.io/errors" - storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" @@ -355,13 +354,18 @@ func (k Keeper) VerifyNextSequenceRecv( nextSequenceRecv uint64, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } // get time and block delays @@ -374,8 +378,8 @@ func (k Keeper) VerifyNextSequenceRecv( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, sdk.Uint64ToBigEndian(nextSequenceRecv), ); err != nil { @@ -396,13 +400,18 @@ func (k Keeper) VerifyChannelUpgradeError( errorReceipt channeltypes.ErrorReceipt, ) error { clientID := connection.GetClientID() - clientState, clientStore, err := k.getClientStateAndVerificationStore(ctx, clientID) + if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { + return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + } + + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { return err } - if status := k.clientKeeper.GetClientStatus(ctx, clientID); status != exported.Active { - return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + if !found { + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeErrorPath(portID, channelID)) @@ -416,8 +425,8 @@ func (k Keeper) VerifyChannelUpgradeError( return err } - if err := clientState.VerifyMembership( - ctx, clientStore, k.cdc, height, + if err := lightClientModule.VerifyMembership( + ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, ); err != nil { @@ -488,19 +497,3 @@ func (k Keeper) getBlockDelay(ctx sdk.Context, connection types.ConnectionEnd) u timeDelay := connection.GetDelayPeriod() return uint64(math.Ceil(float64(timeDelay) / float64(expectedTimePerBlock))) } - -// getClientStateAndVerificationStore returns the client state and associated KVStore for the provided client identifier. -// If the client type is localhost then the core IBC KVStore is returned, otherwise the client prefixed store is returned. -func (k Keeper) getClientStateAndVerificationStore(ctx sdk.Context, clientID string) (exported.ClientState, storetypes.KVStore, error) { - clientState, found := k.clientKeeper.GetClientState(ctx, clientID) - if !found { - return nil, nil, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) - } - - store := k.clientKeeper.ClientStore(ctx, clientID) - if clientID == exported.LocalhostClientID { - store = ctx.KVStore(k.storeKey) - } - - return clientState, store, nil -} From f60c4be7ff3b01a96860f7fa5e1508065ecfa991 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 31 Jan 2024 17:16:40 +0100 Subject: [PATCH 33/74] fix: locahost verify membership and non membership in light client module --- .../09-localhost/client_state_test.go | 293 ------------------ .../09-localhost/light_client_module.go | 6 +- .../09-localhost/light_client_module_test.go | 292 +++++++++++++++++ 3 files changed, 296 insertions(+), 295 deletions(-) diff --git a/modules/light-clients/09-localhost/client_state_test.go b/modules/light-clients/09-localhost/client_state_test.go index 3a85ad83ed1..338b90b04cb 100644 --- a/modules/light-clients/09-localhost/client_state_test.go +++ b/modules/light-clients/09-localhost/client_state_test.go @@ -1,18 +1,10 @@ package localhost_test import ( - sdk "github.com/cosmos/cosmos-sdk/types" - clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" - channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" - commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" - host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" - ibctesting "github.com/cosmos/ibc-go/v8/testing" - "github.com/cosmos/ibc-go/v8/testing/mock" ) func (suite *LocalhostTestSuite) TestClientType() { @@ -108,291 +100,6 @@ func (suite *LocalhostTestSuite) TestInitialize() { } } -func (suite *LocalhostTestSuite) TestVerifyMembership() { - var ( - path exported.Path - value []byte - ) - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success: client state verification", - func() { - clientState := suite.chain.GetClientState(exported.LocalhostClientID) - - merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(exported.LocalhostClientID)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = clienttypes.MustMarshalClientState(suite.chain.Codec, clientState) - }, - true, - }, - { - "success: connection state verification", - func() { - connectionEnd := connectiontypes.NewConnectionEnd( - connectiontypes.OPEN, - exported.LocalhostClientID, - connectiontypes.NewCounterparty(exported.LocalhostClientID, exported.LocalhostConnectionID, suite.chain.GetPrefix()), - connectiontypes.GetCompatibleVersions(), 0, - ) - - suite.chain.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chain.GetContext(), exported.LocalhostConnectionID, connectionEnd) - - merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(exported.LocalhostConnectionID)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = suite.chain.Codec.MustMarshal(&connectionEnd) - }, - true, - }, - { - "success: channel state verification", - func() { - channel := channeltypes.NewChannel( - channeltypes.OPEN, - channeltypes.UNORDERED, - channeltypes.NewCounterparty(mock.PortID, ibctesting.FirstChannelID), - []string{exported.LocalhostConnectionID}, - mock.Version, - ) - - suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) - - merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = suite.chain.Codec.MustMarshal(&channel) - }, - true, - }, - { - "success: next sequence recv verification", - func() { - nextSeqRecv := uint64(100) - suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetNextSequenceRecv(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, nextSeqRecv) - - merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(mock.PortID, ibctesting.FirstChannelID)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = sdk.Uint64ToBigEndian(nextSeqRecv) - }, - true, - }, - { - "success: packet commitment verification", - func() { - packet := channeltypes.NewPacket( - ibctesting.MockPacketData, - 1, - ibctesting.MockPort, - ibctesting.FirstChannelID, - ibctesting.MockPort, - ibctesting.FirstChannelID, - clienttypes.NewHeight(0, 10), - 0, - ) - - commitmentBz := channeltypes.CommitPacket(suite.chain.Codec, packet) - suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketCommitment(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, commitmentBz) - - merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = commitmentBz - }, - true, - }, - { - "success: packet acknowledgement verification", - func() { - suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, ibctesting.MockAcknowledgement) - - merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(mock.PortID, ibctesting.FirstChannelID, 1)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = ibctesting.MockAcknowledgement - }, - true, - }, - { - "invalid type for key path", - func() { - path = mock.KeyPath{} - }, - false, - }, - { - "key path has too many elements", - func() { - path = commitmenttypes.NewMerklePath("ibc", "test", "key") - }, - false, - }, - { - "no value found at provided key path", - func() { - merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(mock.PortID, ibctesting.FirstChannelID, 100)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - value = ibctesting.MockAcknowledgement - }, - false, - }, - { - "invalid value, bytes are not equal", - func() { - channel := channeltypes.NewChannel( - channeltypes.OPEN, - channeltypes.UNORDERED, - channeltypes.NewCounterparty(mock.PortID, ibctesting.FirstChannelID), - []string{exported.LocalhostConnectionID}, - mock.Version, - ) - - suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) - - merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - - // modify the channel before marshalling to value bz - channel.State = channeltypes.CLOSED - value = suite.chain.Codec.MustMarshal(&channel) - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - - tc.malleate() - - clientState := suite.chain.GetClientState(exported.LocalhostClientID) - store := suite.chain.GetContext().KVStore(suite.chain.GetSimApp().GetKey(exported.StoreKey)) - - err := clientState.VerifyMembership( - suite.chain.GetContext(), - store, - suite.chain.Codec, - clienttypes.ZeroHeight(), - 0, 0, // use zero values for delay periods - localhost.SentinelProof, - path, - value, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - -func (suite *LocalhostTestSuite) TestVerifyNonMembership() { - var path exported.Path - - testCases := []struct { - name string - malleate func() - expPass bool - }{ - { - "success: packet receipt absence verification", - func() { - merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(mock.PortID, ibctesting.FirstChannelID, 1)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - }, - true, - }, - { - "packet receipt absence verification fails", - func() { - suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketReceipt(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1) - - merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(mock.PortID, ibctesting.FirstChannelID, 1)) - merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) - suite.Require().NoError(err) - - path = merklePath - }, - false, - }, - { - "invalid type for key path", - func() { - path = mock.KeyPath{} - }, - false, - }, - { - "key path has too many elements", - func() { - path = commitmenttypes.NewMerklePath("ibc", "test", "key") - }, - false, - }, - } - - for _, tc := range testCases { - tc := tc - - suite.Run(tc.name, func() { - suite.SetupTest() - - tc.malleate() - - clientState := suite.chain.GetClientState(exported.LocalhostClientID) - store := suite.chain.GetContext().KVStore(suite.chain.GetSimApp().GetKey(exported.StoreKey)) - - err := clientState.VerifyNonMembership( - suite.chain.GetContext(), - store, - suite.chain.Codec, - clienttypes.ZeroHeight(), - 0, 0, // use zero values for delay periods - localhost.SentinelProof, - path, - ) - - if tc.expPass { - suite.Require().NoError(err) - } else { - suite.Require().Error(err) - } - }) - } -} - func (suite *LocalhostTestSuite) TestVerifyClientMessage() { clientState := localhost.NewClientState(clienttypes.NewHeight(1, 10)) suite.Require().Error(clientState.VerifyClientMessage(suite.chain.GetContext(), nil, nil, nil)) diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index 4c6f849c655..890f40de8e0 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -139,6 +139,7 @@ func (lcm LightClientModule) VerifyMembership( } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + ibcStore := ctx.KVStore(lcm.key) cdc := lcm.cdc clientState, found := getClientState(clientStore, cdc) @@ -146,7 +147,7 @@ func (lcm LightClientModule) VerifyMembership( return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) + return clientState.VerifyMembership(ctx, ibcStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } func (lcm LightClientModule) VerifyNonMembership( @@ -168,6 +169,7 @@ func (lcm LightClientModule) VerifyNonMembership( } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + ibcStore := ctx.KVStore(lcm.key) cdc := lcm.cdc clientState, found := getClientState(clientStore, cdc) @@ -175,7 +177,7 @@ func (lcm LightClientModule) VerifyNonMembership( return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) + return clientState.VerifyNonMembership(ctx, ibcStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } // Status always returns Active. The 09-localhost status cannot be changed. diff --git a/modules/light-clients/09-localhost/light_client_module_test.go b/modules/light-clients/09-localhost/light_client_module_test.go index 340c9717f96..3de479f5fb8 100644 --- a/modules/light-clients/09-localhost/light_client_module_test.go +++ b/modules/light-clients/09-localhost/light_client_module_test.go @@ -1,7 +1,16 @@ package localhost_test import ( + sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" + channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" + commitmenttypes "github.com/cosmos/ibc-go/v8/modules/core/23-commitment/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" + localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" + ibctesting "github.com/cosmos/ibc-go/v8/testing" + "github.com/cosmos/ibc-go/v8/testing/mock" ) func (s *LocalhostTestSuite) TestStatus() { @@ -9,3 +18,286 @@ func (s *LocalhostTestSuite) TestStatus() { s.Require().True(found) s.Require().Equal(exported.Active, lightClientModule.Status(s.chain.GetContext(), exported.LocalhostClientID)) } + +func (s *LocalhostTestSuite) TestVerifyMembership() { + var ( + path exported.Path + value []byte + ) + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success: client state verification", + func() { + clientState := s.chain.GetClientState(exported.LocalhostClientID) + + merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(exported.LocalhostClientID)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = clienttypes.MustMarshalClientState(s.chain.Codec, clientState) + }, + true, + }, + { + "success: connection state verification", + func() { + connectionEnd := connectiontypes.NewConnectionEnd( + connectiontypes.OPEN, + exported.LocalhostClientID, + connectiontypes.NewCounterparty(exported.LocalhostClientID, exported.LocalhostConnectionID, s.chain.GetPrefix()), + connectiontypes.GetCompatibleVersions(), 0, + ) + + s.chain.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(s.chain.GetContext(), exported.LocalhostConnectionID, connectionEnd) + + merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(exported.LocalhostConnectionID)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = s.chain.Codec.MustMarshal(&connectionEnd) + }, + true, + }, + { + "success: channel state verification", + func() { + channel := channeltypes.NewChannel( + channeltypes.OPEN, + channeltypes.UNORDERED, + channeltypes.NewCounterparty(mock.PortID, ibctesting.FirstChannelID), + []string{exported.LocalhostConnectionID}, + mock.Version, + ) + + s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) + + merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = s.chain.Codec.MustMarshal(&channel) + }, + true, + }, + { + "success: next sequence recv verification", + func() { + nextSeqRecv := uint64(100) + s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetNextSequenceRecv(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, nextSeqRecv) + + merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(mock.PortID, ibctesting.FirstChannelID)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = sdk.Uint64ToBigEndian(nextSeqRecv) + }, + true, + }, + { + "success: packet commitment verification", + func() { + packet := channeltypes.NewPacket( + ibctesting.MockPacketData, + 1, + ibctesting.MockPort, + ibctesting.FirstChannelID, + ibctesting.MockPort, + ibctesting.FirstChannelID, + clienttypes.NewHeight(0, 10), + 0, + ) + + commitmentBz := channeltypes.CommitPacket(s.chain.Codec, packet) + s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketCommitment(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, commitmentBz) + + merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = commitmentBz + }, + true, + }, + { + "success: packet acknowledgement verification", + func() { + s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, ibctesting.MockAcknowledgement) + + merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(mock.PortID, ibctesting.FirstChannelID, 1)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = ibctesting.MockAcknowledgement + }, + true, + }, + { + "invalid type for key path", + func() { + path = mock.KeyPath{} + }, + false, + }, + { + "key path has too many elements", + func() { + path = commitmenttypes.NewMerklePath("ibc", "test", "key") + }, + false, + }, + { + "no value found at provided key path", + func() { + merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(mock.PortID, ibctesting.FirstChannelID, 100)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + value = ibctesting.MockAcknowledgement + }, + false, + }, + { + "invalid value, bytes are not equal", + func() { + channel := channeltypes.NewChannel( + channeltypes.OPEN, + channeltypes.UNORDERED, + channeltypes.NewCounterparty(mock.PortID, ibctesting.FirstChannelID), + []string{exported.LocalhostConnectionID}, + mock.Version, + ) + + s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) + + merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + + // modify the channel before marshalling to value bz + channel.State = channeltypes.CLOSED + value = s.chain.Codec.MustMarshal(&channel) + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + s.SetupTest() + + tc.malleate() + + lightClientModule, found := s.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + s.Require().True(found) + + err := lightClientModule.VerifyMembership( + s.chain.GetContext(), + exported.LocalhostClientID, + clienttypes.ZeroHeight(), + 0, 0, // use zero values for delay periods + localhost.SentinelProof, + path, + value, + ) + + if tc.expPass { + s.Require().NoError(err) + } else { + s.Require().Error(err) + } + }) + } +} + +func (s *LocalhostTestSuite) TestVerifyNonMembership() { + var path exported.Path + + testCases := []struct { + name string + malleate func() + expPass bool + }{ + { + "success: packet receipt absence verification", + func() { + merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(mock.PortID, ibctesting.FirstChannelID, 1)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + }, + true, + }, + { + "packet receipt absence verification fails", + func() { + s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketReceipt(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1) + + merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(mock.PortID, ibctesting.FirstChannelID, 1)) + merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) + s.Require().NoError(err) + + path = merklePath + }, + false, + }, + { + "invalid type for key path", + func() { + path = mock.KeyPath{} + }, + false, + }, + { + "key path has too many elements", + func() { + path = commitmenttypes.NewMerklePath("ibc", "test", "key") + }, + false, + }, + } + + for _, tc := range testCases { + tc := tc + + s.Run(tc.name, func() { + s.SetupTest() + + tc.malleate() + + lightClientModule, found := s.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + s.Require().True(found) + + err := lightClientModule.VerifyNonMembership( + s.chain.GetContext(), + exported.LocalhostClientID, + clienttypes.ZeroHeight(), + 0, 0, // use zero values for delay periods + localhost.SentinelProof, + path, + ) + + if tc.expPass { + s.Require().NoError(err) + } else { + s.Require().Error(err) + } + }) + } +} From 47521d7bae0b4354bf7880d8ac029aeafcb550a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 31 Jan 2024 17:27:24 +0100 Subject: [PATCH 34/74] refactor: remove VerifyMembership and VerifyNonMembership from client state interface --- modules/core/exported/client.go | 27 ------------------- .../08-wasm/types/client_state_test.go | 8 +++--- 2 files changed, 4 insertions(+), 31 deletions(-) diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 0136c956c4c..db02c654544 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -149,33 +149,6 @@ type ClientState interface { // Used to verify upgrades ZeroCustomFields() ClientState - // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. - // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). - VerifyMembership( - ctx sdk.Context, - clientStore storetypes.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - proof []byte, - path Path, - value []byte, - ) error - - // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. - // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). - VerifyNonMembership( - ctx sdk.Context, - clientStore storetypes.KVStore, - cdc codec.BinaryCodec, - height Height, - delayTimePeriod uint64, - delayBlockPeriod uint64, - proof []byte, - path Path, - ) error - // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. CheckSubstituteAndUpdateState(ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore storetypes.KVStore, substituteClient ClientState) error diff --git a/modules/light-clients/08-wasm/types/client_state_test.go b/modules/light-clients/08-wasm/types/client_state_test.go index e28d7355ffe..dcb06be2e2e 100644 --- a/modules/light-clients/08-wasm/types/client_state_test.go +++ b/modules/light-clients/08-wasm/types/client_state_test.go @@ -342,7 +342,7 @@ func (suite *TypesTestSuite) TestInitialize() { func (suite *TypesTestSuite) TestVerifyMembership() { var ( - clientState exported.ClientState + clientState *types.ClientState expClientStateBz []byte path exported.Path proof []byte @@ -465,7 +465,7 @@ func (suite *TypesTestSuite) TestVerifyMembership() { value = []byte("value") clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState = endpoint.GetClientState() + clientState = endpoint.GetClientState().(*types.ClientState) tc.malleate() @@ -486,7 +486,7 @@ func (suite *TypesTestSuite) TestVerifyMembership() { func (suite *TypesTestSuite) TestVerifyNonMembership() { var ( - clientState exported.ClientState + clientState *types.ClientState expClientStateBz []byte path exported.Path proof []byte @@ -605,7 +605,7 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { proofHeight = clienttypes.NewHeight(0, 1) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState = endpoint.GetClientState() + clientState = endpoint.GetClientState().(*types.ClientState) tc.malleate() From 91084ba9533e71b6c3fa08077d3214e2ced3d908 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 1 Feb 2024 16:52:53 +0100 Subject: [PATCH 35/74] fix: rm getters for clientID from connection (conflict) --- modules/core/04-channel/keeper/packet.go | 4 ++-- modules/core/04-channel/keeper/packet_test.go | 2 +- modules/core/04-channel/keeper/timeout.go | 2 +- modules/core/04-channel/keeper/upgrade.go | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index d0209b5945b..3e80d11e5dd 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -70,11 +70,11 @@ func (k Keeper) SendPacket( // prevent accidental sends with clients that cannot be updated if status := k.clientKeeper.GetClientStatus(ctx, connectionEnd.ClientId); status != exported.Active { - return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot send packet using client (%s) with status %s", connectionEnd.GetClientID(), status) + return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot send packet using client (%s) with status %s", connectionEnd.ClientId, status) } latestHeight := clientState.GetLatestHeight() - latestTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.GetClientID(), latestHeight) + latestTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.ClientId, latestHeight) if err != nil { return 0, err } diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index a911587d2ab..8798b727006 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -167,7 +167,7 @@ func (suite *KeeperTestSuite) TestSendPacket() { // use latest time on client state clientState := path.EndpointA.GetClientState() connection := path.EndpointA.GetConnection() - timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.GetClientID(), clientState.GetLatestHeight()) + timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.ClientId, clientState.GetLatestHeight()) suite.Require().NoError(err) timeoutHeight = disabledTimeoutHeight diff --git a/modules/core/04-channel/keeper/timeout.go b/modules/core/04-channel/keeper/timeout.go index 60da7280c16..a6b4b1319e7 100644 --- a/modules/core/04-channel/keeper/timeout.go +++ b/modules/core/04-channel/keeper/timeout.go @@ -63,7 +63,7 @@ func (k Keeper) TimeoutPacket( } // check that timeout height or timeout timestamp has passed on the other end - proofTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.GetClientID(), proofHeight) + proofTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.ClientId, proofHeight) if err != nil { return err } diff --git a/modules/core/04-channel/keeper/upgrade.go b/modules/core/04-channel/keeper/upgrade.go index 7bc366338ca..99280aac986 100644 --- a/modules/core/04-channel/keeper/upgrade.go +++ b/modules/core/04-channel/keeper/upgrade.go @@ -745,7 +745,7 @@ func (k Keeper) ChanUpgradeTimeout( return errorsmod.Wrapf(connectiontypes.ErrInvalidConnectionState, "connection state is not OPEN (got %s)", connection.State) } - proofTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connection.GetClientID(), proofHeight) + proofTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connection.ClientId, proofHeight) if err != nil { return err } From f08a0e6bafc33a5c16ca7f5a9a09e743304d7b73 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 8 Feb 2024 09:17:37 +0100 Subject: [PATCH 36/74] 02-client routing: fix linter warnings (#5818) * 02-client routing: fix linter warnings * fix variable name * return error --- e2e/testsuite/testsuite.go | 1 + modules/core/02-client/keeper/keeper.go | 2 +- modules/core/02-client/types/store.go | 1 + modules/core/exported/client.go | 4 +- .../06-solomachine/light_client_module.go | 86 +++++++------- .../08-wasm/light_client_module.go | 74 ++++++------ .../09-localhost/light_client_module.go | 12 +- .../09-localhost/light_client_module_test.go | 109 +++++++++--------- modules/light-clients/09-localhost/store.go | 2 + 9 files changed, 148 insertions(+), 143 deletions(-) diff --git a/e2e/testsuite/testsuite.go b/e2e/testsuite/testsuite.go index 3d3e9410438..138632982ba 100644 --- a/e2e/testsuite/testsuite.go +++ b/e2e/testsuite/testsuite.go @@ -18,6 +18,7 @@ import ( sdkmath "cosmossdk.io/math" govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + "github.com/cosmos/ibc-go/e2e/relayer" "github.com/cosmos/ibc-go/e2e/testsuite/diagnostics" feetypes "github.com/cosmos/ibc-go/v8/modules/apps/29-fee/types" diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 05ad97ee049..657c76672a6 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -66,7 +66,7 @@ func (k Keeper) GetRouter() *types.Router { func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { localhostModule, found := k.router.GetRoute(exported.Localhost) if !found { - errorsmod.Wrap(types.ErrRouteNotFound, exported.Localhost) + return errorsmod.Wrap(types.ErrRouteNotFound, exported.Localhost) } return localhostModule.Initialize(ctx, exported.LocalhostClientID, nil, nil) diff --git a/modules/core/02-client/types/store.go b/modules/core/02-client/types/store.go index d527a12d548..10c7be7f7ac 100644 --- a/modules/core/02-client/types/store.go +++ b/modules/core/02-client/types/store.go @@ -7,6 +7,7 @@ import ( storetypes "cosmossdk.io/store/types" sdk "github.com/cosmos/cosmos-sdk/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index db02c654544..b1bc51f1eab 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -112,7 +112,7 @@ type LightClientModule interface { // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. - // DEPRECATED: will be removed as performs internal functionality + // Deprecated: will be removed as performs internal functionality RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error // Upgrade functions @@ -122,7 +122,7 @@ type LightClientModule interface { // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty // may be cancelled or modified before the last planned height. // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. - // DEPRECATED: will be removed as performs internal functionality + // Deprecated: will be removed as performs internal functionality VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index cb785b41ce3..68941c1e478 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -25,19 +25,19 @@ func NewLightClientModule(cdc codec.BinaryCodec) LightClientModule { } } -func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { - l.storeProvider = storeProvider +func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + lcm.storeProvider = storeProvider } // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. -func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { +func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { if err := validateClientID(clientID); err != nil { return err } var clientState ClientState - if err := l.cdc.Unmarshal(clientStateBz, &clientState); err != nil { + if err := lcm.cdc.Unmarshal(clientStateBz, &clientState); err != nil { return err } @@ -46,7 +46,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt } var consensusState ConsensusState - if err := l.cdc.Unmarshal(consensusStateBz, &consensusState); err != nil { + if err := lcm.cdc.Unmarshal(consensusStateBz, &consensusState); err != nil { return err } @@ -54,78 +54,78 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - return clientState.Initialize(ctx, l.cdc, clientStore, &consensusState) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + return clientState.Initialize(ctx, lcm.cdc, clientStore, &consensusState) } // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. // It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour // will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned // if the ClientMessage fails to verify. -func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { +func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { if err := validateClientID(clientID); err != nil { return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, l.cdc, clientStore, clientMsg) + return clientState.VerifyClientMessage(ctx, lcm.cdc, clientStore, clientMsg) } // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage // has already been verified. -func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { +func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { if err := validateClientID(clientID); err != nil { panic(err) } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.CheckForMisbehaviour(ctx, l.cdc, clientStore, clientMsg) + return clientState.CheckForMisbehaviour(ctx, lcm.cdc, clientStore, clientMsg) } // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified -func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { +func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { if err := validateClientID(clientID); err != nil { panic(err) } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - clientState.UpdateStateOnMisbehaviour(ctx, l.cdc, clientStore, clientMsg) + clientState.UpdateStateOnMisbehaviour(ctx, lcm.cdc, clientStore, clientMsg) } // 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 (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { +func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { if err := validateClientID(clientID); err != nil { panic(err) } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.UpdateState(ctx, l.cdc, clientStore, clientMsg) + return clientState.UpdateState(ctx, lcm.cdc, clientStore, clientMsg) } // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -func (l LightClientModule) VerifyMembership( +func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -139,18 +139,18 @@ func (l LightClientModule) VerifyMembership( return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) + return clientState.VerifyMembership(ctx, clientStore, lcm.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -func (l LightClientModule) VerifyNonMembership( +func (lcm LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -163,43 +163,43 @@ func (l LightClientModule) VerifyNonMembership( return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyNonMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) + return clientState.VerifyNonMembership(ctx, clientStore, lcm.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } // Status must return the status of the client. Only Active clients are allowed to process packets. -func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { +func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { if err := validateClientID(clientID); err != nil { return exported.Unknown // TODO: or panic } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { return exported.Unknown } - return clientState.Status(ctx, clientStore, l.cdc) + return clientState.Status(ctx, clientStore, lcm.cdc) } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. -func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { +func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { if err := validateClientID(clientID); err != nil { return 0, err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, l.cdc) + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) if !found { return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.GetTimestampAtHeight(ctx, clientStore, l.cdc, height) + return clientState.GetTimestampAtHeight(ctx, clientStore, lcm.cdc, height) } func validateClientID(clientID string) error { @@ -217,8 +217,8 @@ func validateClientID(clientID string) error { // // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. // // The light client must set the updated client and consensus states within the clientStore for the subject client. -// // DEPRECATED: will be removed as performs internal functionality -func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +// // Deprecated: will be removed as performs internal functionality +func (LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { return nil } @@ -229,7 +229,7 @@ func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteCl // // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty // // may be cancelled or modified before the last planned height. // // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. -// // DEPRECATED: will be removed as performs internal functionality -func (l LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { +// // Deprecated: will be removed as performs internal functionality +func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { return nil } diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index e302a38b8bc..141d78bfd38 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -5,7 +5,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" - "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" + wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" @@ -15,30 +15,30 @@ var _ exported.LightClientModule = (*LightClientModule)(nil) // LightClientModule implements the core IBC api.LightClientModule interface? type LightClientModule struct { - keeper keeper.Keeper + keeper wasmkeeper.Keeper storeProvider exported.ClientStoreProvider } // NewLightClientModule creates and returns a new 08-wasm LightClientModule. -func NewLightClientModule(keeper keeper.Keeper) LightClientModule { +func NewLightClientModule(keeper wasmkeeper.Keeper) LightClientModule { return LightClientModule{ keeper: keeper, } } -func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { - l.storeProvider = storeProvider +func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + lcm.storeProvider = storeProvider } // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. -func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { +func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { if err := validateClientID(clientID); err != nil { return err } var clientState types.ClientState - if err := l.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { return err } @@ -47,7 +47,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt } var consensusState types.ConsensusState - if err := l.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + if err := lcm.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { return err } @@ -55,8 +55,8 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() return clientState.Initialize(ctx, cdc, clientStore, &consensusState) } @@ -65,31 +65,31 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt // It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour // will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned // if the ClientMessage fails to verify. -func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { +func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { if err := validateClientID(clientID); err != nil { return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), clientStore, clientMsg) + return clientState.VerifyClientMessage(ctx, lcm.keeper.Codec(), clientStore, clientMsg) } // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage // has already been verified. -func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { +func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { if err := validateClientID(clientID); err != nil { panic(err) } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -100,13 +100,13 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string } // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified -func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { +func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { if err := validateClientID(clientID); err != nil { panic(err) } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -118,13 +118,13 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s // 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 (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { +func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { if err := validateClientID(clientID); err != nil { panic(err) } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -136,7 +136,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -func (l LightClientModule) VerifyMembership( +func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -150,8 +150,8 @@ func (l LightClientModule) VerifyMembership( return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -163,7 +163,7 @@ func (l LightClientModule) VerifyMembership( // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -func (l LightClientModule) VerifyNonMembership( +func (lcm LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -176,8 +176,8 @@ func (l LightClientModule) VerifyNonMembership( return err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -188,13 +188,13 @@ func (l LightClientModule) VerifyNonMembership( } // Status must return the status of the client. Only Active clients are allowed to process packets. -func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { +func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { if err := validateClientID(clientID); err != nil { return exported.Unknown // TODO: or panic } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -205,13 +205,13 @@ func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Sta } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. -func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { +func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { if err := validateClientID(clientID); err != nil { return 0, err } - clientStore := l.storeProvider.ClientStore(ctx, clientID) - cdc := l.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -237,7 +237,7 @@ func validateClientID(clientID string) error { // // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. // // The light client must set the updated client and consensus states within the clientStore for the subject client. // // DEPRECATED: will be removed as performs internal functionality -func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +func (LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { return nil } @@ -249,6 +249,6 @@ func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteCl // // may be cancelled or modified before the last planned height. // // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. // // DEPRECATED: will be removed as performs internal functionality -func (l LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { +func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { return nil } diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index 890f40de8e0..87dce96aa55 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -75,7 +75,7 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin return clientState.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) } -func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { +func (LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { panic(err) @@ -88,7 +88,7 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri return false } -func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { +func (LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { clientType, _, err := clienttypes.ParseClientIdentifier(clientID) if err != nil { panic(err) @@ -181,11 +181,11 @@ func (lcm LightClientModule) VerifyNonMembership( } // Status always returns Active. The 09-localhost status cannot be changed. -func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { +func (LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { return exported.Active } -func (lcm LightClientModule) TimestampAtHeight( +func (LightClientModule) TimestampAtHeight( ctx sdk.Context, clientID string, height exported.Height, @@ -202,11 +202,11 @@ func (lcm LightClientModule) TimestampAtHeight( return uint64(ctx.BlockTime().UnixNano()), nil } -func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +func (LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") } -func (lcm LightClientModule) VerifyUpgradeAndUpdateState( +func (LightClientModule) VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, newClient []byte, diff --git a/modules/light-clients/09-localhost/light_client_module_test.go b/modules/light-clients/09-localhost/light_client_module_test.go index 3de479f5fb8..c56c76fa0a8 100644 --- a/modules/light-clients/09-localhost/light_client_module_test.go +++ b/modules/light-clients/09-localhost/light_client_module_test.go @@ -2,6 +2,7 @@ package localhost_test import ( sdk "github.com/cosmos/cosmos-sdk/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" channeltypes "github.com/cosmos/ibc-go/v8/modules/core/04-channel/types" @@ -13,13 +14,13 @@ import ( "github.com/cosmos/ibc-go/v8/testing/mock" ) -func (s *LocalhostTestSuite) TestStatus() { - lightClientModule, found := s.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) - s.Require().True(found) - s.Require().Equal(exported.Active, lightClientModule.Status(s.chain.GetContext(), exported.LocalhostClientID)) +func (suite *LocalhostTestSuite) TestStatus() { + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + suite.Require().True(found) + suite.Require().Equal(exported.Active, lightClientModule.Status(suite.chain.GetContext(), exported.LocalhostClientID)) } -func (s *LocalhostTestSuite) TestVerifyMembership() { +func (suite *LocalhostTestSuite) TestVerifyMembership() { var ( path exported.Path value []byte @@ -33,14 +34,14 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { { "success: client state verification", func() { - clientState := s.chain.GetClientState(exported.LocalhostClientID) + clientState := suite.chain.GetClientState(exported.LocalhostClientID) merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(exported.LocalhostClientID)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath - value = clienttypes.MustMarshalClientState(s.chain.Codec, clientState) + value = clienttypes.MustMarshalClientState(suite.chain.Codec, clientState) }, true, }, @@ -50,18 +51,18 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { connectionEnd := connectiontypes.NewConnectionEnd( connectiontypes.OPEN, exported.LocalhostClientID, - connectiontypes.NewCounterparty(exported.LocalhostClientID, exported.LocalhostConnectionID, s.chain.GetPrefix()), + connectiontypes.NewCounterparty(exported.LocalhostClientID, exported.LocalhostConnectionID, suite.chain.GetPrefix()), connectiontypes.GetCompatibleVersions(), 0, ) - s.chain.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(s.chain.GetContext(), exported.LocalhostConnectionID, connectionEnd) + suite.chain.GetSimApp().GetIBCKeeper().ConnectionKeeper.SetConnection(suite.chain.GetContext(), exported.LocalhostConnectionID, connectionEnd) merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(exported.LocalhostConnectionID)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath - value = s.chain.Codec.MustMarshal(&connectionEnd) + value = suite.chain.Codec.MustMarshal(&connectionEnd) }, true, }, @@ -76,14 +77,14 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { mock.Version, ) - s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) + suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath - value = s.chain.Codec.MustMarshal(&channel) + value = suite.chain.Codec.MustMarshal(&channel) }, true, }, @@ -91,11 +92,11 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { "success: next sequence recv verification", func() { nextSeqRecv := uint64(100) - s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetNextSequenceRecv(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, nextSeqRecv) + suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetNextSequenceRecv(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, nextSeqRecv) merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(mock.PortID, ibctesting.FirstChannelID)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath value = sdk.Uint64ToBigEndian(nextSeqRecv) @@ -116,12 +117,12 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { 0, ) - commitmentBz := channeltypes.CommitPacket(s.chain.Codec, packet) - s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketCommitment(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, commitmentBz) + commitmentBz := channeltypes.CommitPacket(suite.chain.Codec, packet) + suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketCommitment(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, commitmentBz) merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(packet.GetSourcePort(), packet.GetSourceChannel(), packet.GetSequence())) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath value = commitmentBz @@ -131,11 +132,11 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { { "success: packet acknowledgement verification", func() { - s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, ibctesting.MockAcknowledgement) + suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketAcknowledgement(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1, ibctesting.MockAcknowledgement) merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(mock.PortID, ibctesting.FirstChannelID, 1)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath value = ibctesting.MockAcknowledgement @@ -160,8 +161,8 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { "no value found at provided key path", func() { merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(mock.PortID, ibctesting.FirstChannelID, 100)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath value = ibctesting.MockAcknowledgement @@ -179,17 +180,17 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { mock.Version, ) - s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) + suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetChannel(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, channel) merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath // modify the channel before marshalling to value bz channel.State = channeltypes.CLOSED - value = s.chain.Codec.MustMarshal(&channel) + value = suite.chain.Codec.MustMarshal(&channel) }, false, }, @@ -198,16 +199,16 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { for _, tc := range testCases { tc := tc - s.Run(tc.name, func() { - s.SetupTest() + suite.Run(tc.name, func() { + suite.SetupTest() tc.malleate() - lightClientModule, found := s.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) - s.Require().True(found) + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + suite.Require().True(found) err := lightClientModule.VerifyMembership( - s.chain.GetContext(), + suite.chain.GetContext(), exported.LocalhostClientID, clienttypes.ZeroHeight(), 0, 0, // use zero values for delay periods @@ -217,15 +218,15 @@ func (s *LocalhostTestSuite) TestVerifyMembership() { ) if tc.expPass { - s.Require().NoError(err) + suite.Require().NoError(err) } else { - s.Require().Error(err) + suite.Require().Error(err) } }) } } -func (s *LocalhostTestSuite) TestVerifyNonMembership() { +func (suite *LocalhostTestSuite) TestVerifyNonMembership() { var path exported.Path testCases := []struct { @@ -237,8 +238,8 @@ func (s *LocalhostTestSuite) TestVerifyNonMembership() { "success: packet receipt absence verification", func() { merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(mock.PortID, ibctesting.FirstChannelID, 1)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath }, @@ -247,11 +248,11 @@ func (s *LocalhostTestSuite) TestVerifyNonMembership() { { "packet receipt absence verification fails", func() { - s.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketReceipt(s.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1) + suite.chain.GetSimApp().GetIBCKeeper().ChannelKeeper.SetPacketReceipt(suite.chain.GetContext(), mock.PortID, ibctesting.FirstChannelID, 1) merklePath := commitmenttypes.NewMerklePath(host.PacketReceiptPath(mock.PortID, ibctesting.FirstChannelID, 1)) - merklePath, err := commitmenttypes.ApplyPrefix(s.chain.GetPrefix(), merklePath) - s.Require().NoError(err) + merklePath, err := commitmenttypes.ApplyPrefix(suite.chain.GetPrefix(), merklePath) + suite.Require().NoError(err) path = merklePath }, @@ -276,16 +277,16 @@ func (s *LocalhostTestSuite) TestVerifyNonMembership() { for _, tc := range testCases { tc := tc - s.Run(tc.name, func() { - s.SetupTest() + suite.Run(tc.name, func() { + suite.SetupTest() tc.malleate() - lightClientModule, found := s.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) - s.Require().True(found) + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + suite.Require().True(found) err := lightClientModule.VerifyNonMembership( - s.chain.GetContext(), + suite.chain.GetContext(), exported.LocalhostClientID, clienttypes.ZeroHeight(), 0, 0, // use zero values for delay periods @@ -294,9 +295,9 @@ func (s *LocalhostTestSuite) TestVerifyNonMembership() { ) if tc.expPass { - s.Require().NoError(err) + suite.Require().NoError(err) } else { - s.Require().Error(err) + suite.Require().Error(err) } }) } diff --git a/modules/light-clients/09-localhost/store.go b/modules/light-clients/09-localhost/store.go index 0046ce0c093..b66674f7022 100644 --- a/modules/light-clients/09-localhost/store.go +++ b/modules/light-clients/09-localhost/store.go @@ -2,7 +2,9 @@ package localhost import ( storetypes "cosmossdk.io/store/types" + "github.com/cosmos/cosmos-sdk/codec" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) From daedbf65511806d2083c0212fe0cc08a5a25e3cc Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 8 Feb 2024 14:07:37 +0100 Subject: [PATCH 37/74] 02-client routing: pass client ID to get route instead of client type (#5817) * pass client ID to get route instead of client type * rename variable * Update modules/core/02-client/keeper/keeper.go --------- Co-authored-by: Damian Nolan --- modules/core/02-client/keeper/client.go | 8 +- modules/core/02-client/keeper/keeper.go | 14 +-- modules/core/02-client/types/router.go | 14 ++- modules/core/03-connection/keeper/verify.go | 101 +++++------------- .../09-localhost/light_client_module_test.go | 6 +- 5 files changed, 52 insertions(+), 91 deletions(-) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index 53ed40d2b92..a21f4646377 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -33,9 +33,9 @@ func (k Keeper) CreateClient( clientID := k.GenerateClientIdentifier(ctx, clientType) - lightClientModule, found := k.router.GetRoute(clientType) + lightClientModule, found := k.router.GetRoute(clientID) if !found { - return "", errorsmod.Wrap(types.ErrRouteNotFound, clientType) + return "", errorsmod.Wrap(types.ErrRouteNotFound, clientID) } if err := lightClientModule.Initialize(ctx, clientID, clientState, consensusState); err != nil { @@ -70,9 +70,9 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) } - lightClientModule, found := k.router.GetRoute(clientType) + lightClientModule, found := k.router.GetRoute(clientID) if !found { - return errorsmod.Wrap(types.ErrRouteNotFound, clientType) + return errorsmod.Wrap(types.ErrRouteNotFound, clientID) } if err := lightClientModule.VerifyClientMessage(ctx, clientID, clientMsg); err != nil { diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 657c76672a6..b18821cbb3d 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -64,19 +64,19 @@ func (k Keeper) GetRouter() *types.Router { // CreateLocalhostClient initialises the 09-localhost client state and sets it in state. func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - localhostModule, found := k.router.GetRoute(exported.Localhost) + lightClientModule, found := k.router.GetRoute(exported.LocalhostClientID) if !found { - return errorsmod.Wrap(types.ErrRouteNotFound, exported.Localhost) + return errorsmod.Wrap(types.ErrRouteNotFound, exported.LocalhostClientID) } - return localhostModule.Initialize(ctx, exported.LocalhostClientID, nil, nil) + return lightClientModule.Initialize(ctx, exported.LocalhostClientID, nil, 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 { - lightClientModule, found := k.router.GetRoute(exported.Localhost) + lightClientModule, found := k.router.GetRoute(exported.LocalhostClientID) if !found { - panic(errorsmod.Wrap(types.ErrRouteNotFound, exported.Localhost)) + panic(errorsmod.Wrap(types.ErrRouteNotFound, exported.LocalhostClientID)) } return lightClientModule.UpdateState(ctx, exported.LocalhostClientID, nil) @@ -438,7 +438,7 @@ func (k Keeper) GetClientStatus(ctx sdk.Context, clientID string) exported.Statu return exported.Unauthorized } - lightClientModule, found := k.router.GetRoute(clientType) + lightClientModule, found := k.router.GetRoute(clientID) if !found { return exported.Unauthorized } @@ -458,7 +458,7 @@ func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, clientID string, height ex return 0, errorsmod.Wrapf(types.ErrInvalidClientType, "client state type %s is not registered in the allowlist", clientType) } - lightClientModule, found := k.router.GetRoute(clientType) + lightClientModule, found := k.router.GetRoute(clientID) if !found { return 0, errorsmod.Wrap(types.ErrRouteNotFound, clientType) } diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index bd41e3925e3..405c12a68ff 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -44,10 +44,16 @@ func (rtr *Router) HasRoute(module string) bool { return ok } -// GetRoute returns a LightClientModule for a given module. -func (rtr *Router) GetRoute(module string) (exported.LightClientModule, bool) { - if !rtr.HasRoute(module) { +// GetRoute returns the LightClientModule registered for the client type +// associated with the clientID. +func (rtr *Router) GetRoute(clientID string) (exported.LightClientModule, bool) { + clientType, _, err := ParseClientIdentifier(clientID) + if err != nil { return nil, false } - return rtr.routes[module], true + + if !rtr.HasRoute(clientType) { + return nil, false + } + return rtr.routes[clientType], true } diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 4556ab3f46a..61c99dc21f2 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -29,18 +29,13 @@ func (k Keeper) VerifyClientState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } merklePath := commitmenttypes.NewMerklePath(host.FullClientStatePath(connection.Counterparty.ClientId)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -76,18 +71,13 @@ func (k Keeper) VerifyClientConsensusState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } merklePath := commitmenttypes.NewMerklePath(host.FullConsensusStatePath(connection.Counterparty.ClientId, consensusHeight)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -123,18 +113,13 @@ func (k Keeper) VerifyConnectionState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } merklePath := commitmenttypes.NewMerklePath(host.ConnectionPath(connectionID)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -171,18 +156,13 @@ func (k Keeper) VerifyChannelState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } merklePath := commitmenttypes.NewMerklePath(host.ChannelPath(portID, channelID)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -220,14 +200,9 @@ func (k Keeper) VerifyPacketCommitment( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } // get time and block delays @@ -235,7 +210,7 @@ func (k Keeper) VerifyPacketCommitment( blockDelay := k.getBlockDelay(ctx, connection) merklePath := commitmenttypes.NewMerklePath(host.PacketCommitmentPath(portID, channelID, sequence)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -266,14 +241,9 @@ func (k Keeper) VerifyPacketAcknowledgement( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } // get time and block delays @@ -281,7 +251,7 @@ func (k Keeper) VerifyPacketAcknowledgement( blockDelay := k.getBlockDelay(ctx, connection) merklePath := commitmenttypes.NewMerklePath(host.PacketAcknowledgementPath(portID, channelID, sequence)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -318,7 +288,7 @@ func (k Keeper) VerifyPacketReceiptAbsence( return err } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } @@ -358,14 +328,9 @@ func (k Keeper) VerifyNextSequenceRecv( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } // get time and block delays @@ -373,7 +338,7 @@ func (k Keeper) VerifyNextSequenceRecv( blockDelay := k.getBlockDelay(ctx, connection) merklePath := commitmenttypes.NewMerklePath(host.NextSequenceRecvPath(portID, channelID)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -404,18 +369,13 @@ func (k Keeper) VerifyChannelUpgradeError( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradeErrorPath(portID, channelID)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } @@ -451,18 +411,13 @@ func (k Keeper) VerifyChannelUpgrade( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientType) + lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { - return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) + return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } merklePath := commitmenttypes.NewMerklePath(host.ChannelUpgradePath(portID, channelID)) - merklePath, err = commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) + merklePath, err := commitmenttypes.ApplyPrefix(connection.Counterparty.Prefix, merklePath) if err != nil { return err } diff --git a/modules/light-clients/09-localhost/light_client_module_test.go b/modules/light-clients/09-localhost/light_client_module_test.go index c56c76fa0a8..97a5df1306e 100644 --- a/modules/light-clients/09-localhost/light_client_module_test.go +++ b/modules/light-clients/09-localhost/light_client_module_test.go @@ -15,7 +15,7 @@ import ( ) func (suite *LocalhostTestSuite) TestStatus() { - lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.LocalhostClientID) suite.Require().True(found) suite.Require().Equal(exported.Active, lightClientModule.Status(suite.chain.GetContext(), exported.LocalhostClientID)) } @@ -204,7 +204,7 @@ func (suite *LocalhostTestSuite) TestVerifyMembership() { tc.malleate() - lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.LocalhostClientID) suite.Require().True(found) err := lightClientModule.VerifyMembership( @@ -282,7 +282,7 @@ func (suite *LocalhostTestSuite) TestVerifyNonMembership() { tc.malleate() - lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.Localhost) + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.LocalhostClientID) suite.Require().True(found) err := lightClientModule.VerifyNonMembership( From 2f9186cfcd2a22869090b56312c84f100c0266ad Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 8 Feb 2024 22:58:41 +0100 Subject: [PATCH 38/74] use localhost client ID --- modules/core/02-client/abci.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/02-client/abci.go b/modules/core/02-client/abci.go index f15f92857ff..4fbfc7fec1c 100644 --- a/modules/core/02-client/abci.go +++ b/modules/core/02-client/abci.go @@ -35,7 +35,7 @@ func BeginBlocker(ctx sdk.Context, k keeper.Keeper) { // update the localhost client with the latest block height if it is active. if clientState, found := k.GetClientState(ctx, exported.Localhost); found { - if k.GetClientStatus(ctx, exported.Localhost) == exported.Active { + if k.GetClientStatus(ctx, exported.LocalhostClientID) == exported.Active { k.UpdateLocalhostClient(ctx, clientState) } } From 61937ea305d3c6b764cb59e50fc23e2b9e256908 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 15 Feb 2024 13:49:25 +0100 Subject: [PATCH 39/74] 02-client routing: function in store provider to return client store (#5824) * add function to return 02-client module store * review comment --- modules/core/02-client/types/store.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/modules/core/02-client/types/store.go b/modules/core/02-client/types/store.go index 10c7be7f7ac..825be33ad27 100644 --- a/modules/core/02-client/types/store.go +++ b/modules/core/02-client/types/store.go @@ -30,3 +30,8 @@ func (s storeProvider) ClientStore(ctx sdk.Context, clientID string) storetypes. clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) return prefix.NewStore(ctx.KVStore(s.storeKey), clientPrefix) } + +// ModuleStore returns the 02-client module store +func (s storeProvider) ModuleStore(ctx sdk.Context, clientType string) storetypes.KVStore { + return prefix.NewStore(ctx.KVStore(s.storeKey), host.PrefixedClientStoreKey([]byte(clientType))) +} From b715710f074dafe1abed7a5c628697a04934bf72 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 15 Feb 2024 15:27:08 +0100 Subject: [PATCH 40/74] 02-client routing: implement `RecoverClient` in light client modules (#5822) * implement recover client in light client modules * add tests for wasm light client module recover client function * missing file * add tests for tendermint light client module recover client * add tests for solomachine light client module recover client * clean up 02-client recover client test cases * fix test * fix linter warning * format client IDs --- modules/core/02-client/keeper/client.go | 32 ++-- modules/core/02-client/keeper/client_test.go | 24 +-- modules/core/exported/client.go | 7 +- .../06-solomachine/light_client_module.go | 43 ++++- .../light_client_module_test.go | 148 ++++++++++++++++++ .../07-tendermint/light_client_module.go | 15 +- .../07-tendermint/light_client_module_test.go | 139 ++++++++++++++++ .../08-wasm/light_client_module.go | 45 +++++- .../08-wasm/light_client_module_test.go | 139 ++++++++++++++++ .../08-wasm/types/proposal_handle_test.go | 2 +- modules/light-clients/08-wasm/wasm_test.go | 126 +++++++++++++++ 11 files changed, 660 insertions(+), 60 deletions(-) create mode 100644 modules/light-clients/06-solomachine/light_client_module_test.go create mode 100644 modules/light-clients/07-tendermint/light_client_module_test.go create mode 100644 modules/light-clients/08-wasm/light_client_module_test.go create mode 100644 modules/light-clients/08-wasm/wasm_test.go diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index a21f4646377..e33f09ea90e 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -174,34 +174,26 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e // the necessary consensus states from the substitute to the subject client // store. The substitute must be Active and the subject must not be Active. func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClientID string) error { - subjectClientState, found := k.GetClientState(ctx, subjectClientID) - if !found { - return errorsmod.Wrapf(types.ErrClientNotFound, "subject client with ID %s", subjectClientID) - } - - subjectClientStore := k.ClientStore(ctx, subjectClientID) - if status := k.GetClientStatus(ctx, subjectClientID); status == exported.Active { return errorsmod.Wrapf(types.ErrInvalidRecoveryClient, "cannot recover %s subject client", exported.Active) } - substituteClientState, found := k.GetClientState(ctx, substituteClientID) - if !found { - return errorsmod.Wrapf(types.ErrClientNotFound, "substitute client with ID %s", substituteClientID) + if status := k.GetClientStatus(ctx, substituteClientID); status != exported.Active { + return errorsmod.Wrapf(types.ErrClientNotActive, "substitute client is not %s, status is %s", exported.Active, status) } - if subjectClientState.GetLatestHeight().GTE(substituteClientState.GetLatestHeight()) { - return errorsmod.Wrapf(types.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", subjectClientState.GetLatestHeight(), substituteClientState.GetLatestHeight()) + clientType, _, err := types.ParseClientIdentifier(subjectClientID) + if err != nil { + return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", subjectClientID) } - substituteClientStore := k.ClientStore(ctx, substituteClientID) - - if status := k.GetClientStatus(ctx, substituteClientID); status != exported.Active { - return errorsmod.Wrapf(types.ErrClientNotActive, "substitute client is not %s, status is %s", exported.Active, status) + lightClientModule, found := k.router.GetRoute(subjectClientID) + if !found { + return errorsmod.Wrap(types.ErrRouteNotFound, subjectClientID) } - if err := subjectClientState.CheckSubstituteAndUpdateState(ctx, k.cdc, subjectClientStore, substituteClientStore, substituteClientState); err != nil { - return errorsmod.Wrap(err, "failed to validate substitute client") + if err := lightClientModule.RecoverClient(ctx, subjectClientID, substituteClientID); err != nil { + return err } k.Logger(ctx).Info("client recovered", "client-id", subjectClientID) @@ -210,14 +202,14 @@ func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClient []string{"ibc", "client", "update"}, 1, []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, substituteClientState.ClientType()), + telemetry.NewLabel(types.LabelClientType, clientType), telemetry.NewLabel(types.LabelClientID, subjectClientID), telemetry.NewLabel(types.LabelUpdateType, "recovery"), }, ) // emitting events in the keeper for recovering clients - emitRecoverClientEvent(ctx, subjectClientID, substituteClientState.ClientType()) + emitRecoverClientEvent(ctx, subjectClientID, clientType) return nil } diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 1985fecce01..d2073e63047 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -591,27 +591,7 @@ func (suite *KeeperTestSuite) TestRecoverClient() { func() { substitute = ibctesting.InvalidID }, - clienttypes.ErrClientNotFound, - }, - { - "subject and substitute have equal latest height", - func() { - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(clienttypes.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - }, - clienttypes.ErrInvalidHeight, - }, - { - "subject height is greater than substitute height", - func() { - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.LatestHeight = substituteClientState.GetLatestHeight().Increment().(clienttypes.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) - }, - clienttypes.ErrInvalidHeight, + clienttypes.ErrClientNotActive, }, { "substitute is frozen", @@ -624,7 +604,7 @@ func (suite *KeeperTestSuite) TestRecoverClient() { clienttypes.ErrClientNotActive, }, { - "CheckSubstituteAndUpdateState fails, substitute client trust level doesn't match subject client trust level", + "light client module RecoverClient fails, substitute client trust level doesn't match subject client trust level", func() { tmClientState, ok := substituteClientState.(*ibctm.ClientState) suite.Require().True(ok) diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index b1bc51f1eab..2c1dc921302 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -110,9 +110,8 @@ type LightClientModule interface { height Height, // TODO: change to concrete type ) (uint64, error) - // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. + // RecoverClient must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. - // Deprecated: will be removed as performs internal functionality RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error // Upgrade functions @@ -149,10 +148,6 @@ type ClientState interface { // Used to verify upgrades ZeroCustomFields() ClientState - // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. - // The light client must set the updated client and consensus states within the clientStore for the subject client. - CheckSubstituteAndUpdateState(ctx sdk.Context, cdc codec.BinaryCodec, subjectClientStore, substituteClientStore storetypes.KVStore, substituteClient ClientState) error - // Upgrade functions // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last // height committed by the current revision. Clients are responsible for ensuring that the planned last diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 68941c1e478..a0bf9f50f27 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -215,11 +215,44 @@ func validateClientID(clientID string) error { return nil } -// // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. -// // The light client must set the updated client and consensus states within the clientStore for the subject client. -// // Deprecated: will be removed as performs internal functionality -func (LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { - return nil +// RecoverClient must verify that the provided substitute may be used to update the subject client. +// The light client must set the updated client and consensus states within the clientStore for the subject client. +func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != exported.Solomachine { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Solomachine, clientType) + } + + substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) + if err != nil { + return err + } + + if substituteClientType != exported.Solomachine { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Solomachine, substituteClientType) + } + + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, lcm.cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + substituteClientStore := lcm.storeProvider.ClientStore(ctx, substituteClientID) + substituteClient, found := getClientState(substituteClientStore, lcm.cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) + } + + if clientState.GetLatestHeight().GTE(substituteClient.GetLatestHeight()) { + return errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", clientState.GetLatestHeight(), substituteClient.GetLatestHeight()) + } + + return clientState.CheckSubstituteAndUpdateState(ctx, lcm.cdc, clientStore, substituteClientStore, substituteClient) } // // Upgrade functions diff --git a/modules/light-clients/06-solomachine/light_client_module_test.go b/modules/light-clients/06-solomachine/light_client_module_test.go new file mode 100644 index 00000000000..ce9cca27e8b --- /dev/null +++ b/modules/light-clients/06-solomachine/light_client_module_test.go @@ -0,0 +1,148 @@ +package solomachine_test + +import ( + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + solomachine "github.com/cosmos/ibc-go/v8/modules/light-clients/06-solomachine" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +const ( + smClientID = "06-solomachine-100" + wasmClientID = "08-wasm-0" +) + +func (suite *SoloMachineTestSuite) TestRecoverClient() { + var ( + subjectClientID, substituteClientID string + subjectClientState, substituteClientState exported.ClientState + ) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() { + }, + nil, + }, + { + "cannot parse malformed subject client ID", + func() { + subjectClientID = ibctesting.InvalidID + }, + host.ErrInvalidID, + }, + { + "subject client ID does not contain 06-machine prefix", + func() { + subjectClientID = wasmClientID + }, + clienttypes.ErrInvalidClientType, + }, + { + "cannot parse malformed substitute client ID", + func() { + substituteClientID = ibctesting.InvalidID + }, + host.ErrInvalidID, + }, + { + "substitute client ID does not contain 06-solomachine prefix", + func() { + substituteClientID = wasmClientID + }, + clienttypes.ErrInvalidClientType, + }, + { + "cannot find subject client state", + func() { + subjectClientID = smClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "cannot find substitute client state", + func() { + substituteClientID = smClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "subject and substitute have equal latest height", + func() { + smClientState, ok := subjectClientState.(*solomachine.ClientState) + suite.Require().True(ok) + smClientState.Sequence = substituteClientState.GetLatestHeight().GetRevisionHeight() + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, smClientState) + }, + clienttypes.ErrInvalidHeight, + }, + { + "subject height is greater than substitute height", + func() { + smClientState, ok := subjectClientState.(*solomachine.ClientState) + suite.Require().True(ok) + smClientState.Sequence = substituteClientState.GetLatestHeight().GetRevisionHeight() + 1 + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, smClientState) + }, + clienttypes.ErrInvalidHeight, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupTest() // reset + cdc := suite.chainA.Codec + ctx := suite.chainA.GetContext() + + subjectClientID = suite.chainA.App.GetIBCKeeper().ClientKeeper.GenerateClientIdentifier(ctx, exported.Solomachine) + subject := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, substituteClientID, "testing", 1) + subjectClientState = subject.ClientState() + + substituteClientID = suite.chainA.App.GetIBCKeeper().ClientKeeper.GenerateClientIdentifier(ctx, exported.Solomachine) + substitute := ibctesting.NewSolomachine(suite.T(), suite.chainA.Codec, substituteClientID, "testing", 1) + substitute.Sequence++ // increase sequence so that latest height of substitute is > than subject's latest height + substituteClientState = substitute.ClientState() + + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(ctx, substituteClientID) + clientStore.Get(host.ClientStateKey()) + bz := clienttypes.MustMarshalClientState(cdc, substituteClientState) + clientStore.Set(host.ClientStateKey(), bz) + + smClientState, ok := subjectClientState.(*solomachine.ClientState) + suite.Require().True(ok) + smClientState.IsFrozen = true + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(ctx, subjectClientID, smClientState) + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetRouter().GetRoute(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) + bz = clientStore.Get(host.ClientStateKey()) + smClientState := clienttypes.MustUnmarshalClientState(cdc, bz).(*solomachine.ClientState) + + suite.Require().Equal(substituteClientState.(*solomachine.ClientState).ConsensusState, smClientState.ConsensusState) + suite.Require().Equal(substituteClientState.(*solomachine.ClientState).Sequence, smClientState.Sequence) + suite.Require().Equal(exported.Active, smClientState.Status(ctx, clientStore, cdc)) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 98625ef3ab3..7a549d4329d 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -261,9 +261,18 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) + if err != nil { + return err + } + + if substituteClientType != exported.Tendermint { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, substituteClientType) + } + cdc := lcm.keeper.Codec() + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) @@ -275,6 +284,10 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) } + if clientState.GetLatestHeight().GTE(substituteClient.GetLatestHeight()) { + return errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", clientState.GetLatestHeight(), substituteClient.GetLatestHeight()) + } + return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } diff --git a/modules/light-clients/07-tendermint/light_client_module_test.go b/modules/light-clients/07-tendermint/light_client_module_test.go new file mode 100644 index 00000000000..d8b0af1515e --- /dev/null +++ b/modules/light-clients/07-tendermint/light_client_module_test.go @@ -0,0 +1,139 @@ +package tendermint_test + +import ( + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +var ( + tmClientID = clienttypes.FormatClientIdentifier(exported.Tendermint, 100) + solomachineClientID = clienttypes.FormatClientIdentifier(exported.Solomachine, 0) +) + +func (suite *TendermintTestSuite) TestRecoverClient() { + var ( + subjectClientID, substituteClientID string + subjectClientState, substituteClientState exported.ClientState + ) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() { + }, + nil, + }, + { + "cannot parse malformed subject client ID", + func() { + subjectClientID = ibctesting.InvalidID + }, + host.ErrInvalidID, + }, + { + "subject client ID does not contain 07-tendermint prefix", + func() { + subjectClientID = solomachineClientID + }, + clienttypes.ErrInvalidClientType, + }, + { + "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, + }, + { + "subject and substitute have equal latest height", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, tmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + { + "subject height is greater than substitute height", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.GetLatestHeight().Increment().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, tmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + } + + 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 + substituteClientState = suite.chainA.GetClientState(substituteClientID) + + 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.GetRouter().GetRoute(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 := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().Equal(exported.Active, tmClientState.Status(ctx, clientStore, suite.chainA.App.AppCodec())) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 141d78bfd38..65e0e785509 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -234,11 +234,46 @@ func validateClientID(clientID string) error { return nil } -// // CheckSubstituteAndUpdateState must verify that the provided substitute may be used to update the subject client. -// // The light client must set the updated client and consensus states within the clientStore for the subject client. -// // DEPRECATED: will be removed as performs internal functionality -func (LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { - return nil +// RecoverClient must verify that the provided substitute may be used to update the subject client. +// The light client must set the updated client and consensus states within the clientStore for the subject client. +func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { + clientType, _, err := clienttypes.ParseClientIdentifier(clientID) + if err != nil { + return err + } + + if clientType != types.Wasm { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", types.Wasm, clientType) + } + + substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) + if err != nil { + return err + } + + if substituteClientType != types.Wasm { + return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", types.Wasm, substituteClientType) + } + + cdc := lcm.keeper.Codec() + + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + substituteClientStore := lcm.storeProvider.ClientStore(ctx, substituteClientID) + substituteClient, found := types.GetClientState(substituteClientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) + } + + if clientState.GetLatestHeight().GTE(substituteClient.GetLatestHeight()) { + return errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", clientState.GetLatestHeight(), substituteClient.GetLatestHeight()) + } + + return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } // // Upgrade functions diff --git a/modules/light-clients/08-wasm/light_client_module_test.go b/modules/light-clients/08-wasm/light_client_module_test.go new file mode 100644 index 00000000000..aad9c8c308d --- /dev/null +++ b/modules/light-clients/08-wasm/light_client_module_test.go @@ -0,0 +1,139 @@ +package wasm_test + +import ( + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" + wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +const ( + tmClientID = "07-tendermint-0" + wasmClientID = "08-wasm-100" +) + +func (suite *WasmTestSuite) TestRecoverClient() { + var ( + expectedClientStateBz []byte + subjectClientID, substituteClientID string + subjectClientState, substituteClientState exported.ClientState + ) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + // TODO(02-client routing): add successful test when light client module does not call into 08-wasm ClientState + // { + // "success", + // func() { + // }, + // nil, + // }, + { + "cannot parse malformed subject client ID", + func() { + subjectClientID = ibctesting.InvalidID + }, + host.ErrInvalidID, + }, + { + "subject client ID does not contain 08-wasm prefix", + func() { + subjectClientID = tmClientID + }, + clienttypes.ErrInvalidClientType, + }, + { + "cannot parse malformed substitute client ID", + func() { + substituteClientID = ibctesting.InvalidID + }, + host.ErrInvalidID, + }, + { + "substitute client ID does not contain 08-wasm prefix", + func() { + substituteClientID = tmClientID + }, + clienttypes.ErrInvalidClientType, + }, + { + "cannot find subject client state", + func() { + subjectClientID = wasmClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "cannot find substitute client state", + func() { + substituteClientID = wasmClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "subject and substitute have equal latest height", + func() { + wasmClientState, ok := subjectClientState.(*wasmtypes.ClientState) + suite.Require().True(ok) + wasmClientState.LatestHeight = substituteClientState.GetLatestHeight().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, wasmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + { + "subject height is greater than substitute height", + func() { + wasmClientState, ok := subjectClientState.(*wasmtypes.ClientState) + suite.Require().True(ok) + wasmClientState.LatestHeight = substituteClientState.GetLatestHeight().Increment().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, wasmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupWasmWithMockVM() + expectedClientStateBz = nil + + subjectEndpoint := wasmtesting.NewWasmEndpoint(suite.chainA) + err := subjectEndpoint.CreateClient() + suite.Require().NoError(err) + subjectClientID = subjectEndpoint.ClientID + + subjectClientState = subjectEndpoint.GetClientState() + subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectClientID) + + substituteEndpoint := wasmtesting.NewWasmEndpoint(suite.chainA) + err = substituteEndpoint.CreateClient() + suite.Require().NoError(err) + substituteClientID = substituteEndpoint.ClientID + + substituteClientState = substituteEndpoint.GetClientState() + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetRouter().GetRoute(subjectClientID) + suite.Require().True(found) + + tc.malleate() + + err = lightClientModule.RecoverClient(suite.chainA.GetContext(), subjectClientID, substituteClientID) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + clientStateBz := subjectClientStore.Get(host.ClientStateKey()) + suite.Require().Equal(expectedClientStateBz, clientStateBz) + } else { + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} diff --git a/modules/light-clients/08-wasm/types/proposal_handle_test.go b/modules/light-clients/08-wasm/types/proposal_handle_test.go index 7e4ba10aa96..400e997e8f9 100644 --- a/modules/light-clients/08-wasm/types/proposal_handle_test.go +++ b/modules/light-clients/08-wasm/types/proposal_handle_test.go @@ -95,7 +95,7 @@ func (suite *TypesTestSuite) TestCheckSubstituteAndUpdateState() { suite.Require().NoError(err) subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpointA.ClientID) - subjectClientState := endpointA.GetClientState() + subjectClientState := endpointA.GetClientState().(*types.ClientState) substituteEndpoint := wasmtesting.NewWasmEndpoint(suite.chainA) err = substituteEndpoint.CreateClient() diff --git a/modules/light-clients/08-wasm/wasm_test.go b/modules/light-clients/08-wasm/wasm_test.go new file mode 100644 index 00000000000..79702fa860c --- /dev/null +++ b/modules/light-clients/08-wasm/wasm_test.go @@ -0,0 +1,126 @@ +package wasm_test + +import ( + "encoding/json" + "errors" + "testing" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + dbm "github.com/cosmos/cosmos-db" + testifysuite "github.com/stretchr/testify/suite" + + "cosmossdk.io/log" + storetypes "cosmossdk.io/store/types" + + simtestutil "github.com/cosmos/cosmos-sdk/testutil/sims" + authtypes "github.com/cosmos/cosmos-sdk/x/auth/types" + govtypes "github.com/cosmos/cosmos-sdk/x/gov/types" + + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" + simapp "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing/simapp" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctesting "github.com/cosmos/ibc-go/v8/testing" +) + +type WasmTestSuite struct { + testifysuite.Suite + coordinator *ibctesting.Coordinator + chainA *ibctesting.TestChain + mockVM *wasmtesting.MockWasmEngine + + checksum types.Checksum +} + +func TestWasmTestSuite(t *testing.T) { + testifysuite.Run(t, new(WasmTestSuite)) +} + +func (suite *WasmTestSuite) SetupTest() { + ibctesting.DefaultTestingAppInit = setupTestingApp + + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 1) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) +} + +func init() { + ibctesting.DefaultTestingAppInit = setupTestingApp +} + +// GetSimApp returns the duplicated SimApp from within the 08-wasm directory. +// This must be used instead of chain.GetSimApp() for tests within this directory. +func GetSimApp(chain *ibctesting.TestChain) *simapp.SimApp { + app, ok := chain.App.(*simapp.SimApp) + if !ok { + panic(errors.New("chain is not a simapp.SimApp")) + } + return app +} + +// setupTestingApp provides the duplicated simapp which is specific to the 08-wasm module on chain creation. +func setupTestingApp() (ibctesting.TestingApp, map[string]json.RawMessage) { + db := dbm.NewMemDB() + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{}, nil) + return app, app.DefaultGenesis() +} + +// SetupWasmWithMockVM sets up mock cometbft chain with a mock vm. +func (suite *WasmTestSuite) SetupWasmWithMockVM() { + ibctesting.DefaultTestingAppInit = suite.setupWasmWithMockVM + + suite.coordinator = ibctesting.NewCoordinator(suite.T(), 1) + suite.chainA = suite.coordinator.GetChain(ibctesting.GetChainID(1)) + suite.checksum = storeWasmCode(suite, wasmtesting.Code) +} + +func (suite *WasmTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[string]json.RawMessage) { + suite.mockVM = wasmtesting.NewMockWasmEngine() + + suite.mockVM.InstantiateFn = func(checksum wasmvm.Checksum, env wasmvmtypes.Env, info wasmvmtypes.MessageInfo, initMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + var payload types.InstantiateMessage + err := json.Unmarshal(initMsg, &payload) + suite.Require().NoError(err) + + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) + + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.GetLatestHeight().(clienttypes.Height)) + clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) + store.Set(host.ClientStateKey(), clientStateBz) + + consensusState := types.NewConsensusState(payload.ConsensusState) + consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) + store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) + + resp, err := json.Marshal(types.EmptyResult{}) + suite.Require().NoError(err) + + return &wasmvmtypes.Response{Data: resp}, 0, nil + } + + suite.mockVM.RegisterQueryCallback(types.StatusMsg{}, func(checksum wasmvm.Checksum, env wasmvmtypes.Env, queryMsg []byte, store wasmvm.KVStore, goapi wasmvm.GoAPI, querier wasmvm.Querier, gasMeter wasmvm.GasMeter, gasLimit uint64, deserCost wasmvmtypes.UFraction) ([]byte, uint64, error) { + resp, err := json.Marshal(types.StatusResult{Status: exported.Active.String()}) + suite.Require().NoError(err) + return resp, wasmtesting.DefaultGasUsed, nil + }) + + db := dbm.NewMemDB() + app := simapp.NewSimApp(log.NewNopLogger(), db, nil, true, simtestutil.EmptyAppOptions{}, suite.mockVM) + + // reset DefaultTestingAppInit to its original value + ibctesting.DefaultTestingAppInit = setupTestingApp + return app, app.DefaultGenesis() +} + +// storeWasmCode stores the wasm code on chain and returns the checksum. +func storeWasmCode(suite *WasmTestSuite, wasmCode []byte) types.Checksum { + ctx := suite.chainA.GetContext().WithBlockGasMeter(storetypes.NewInfiniteGasMeter()) + + msg := types.NewMsgStoreCode(authtypes.NewModuleAddress(govtypes.ModuleName).String(), wasmCode) + response, err := GetSimApp(suite.chainA).WasmClientKeeper.StoreCode(ctx, msg) + suite.Require().NoError(err) + suite.Require().NotNil(response.Checksum) + return response.Checksum +} From 1225ce063de45d80e0e52dfa61efcff2c3fc9f3e Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Sun, 18 Feb 2024 23:15:26 +0100 Subject: [PATCH 41/74] fixes from merge of main --- modules/core/02-client/keeper/grpc_query.go | 6 +++--- modules/core/02-client/keeper/grpc_query_test.go | 8 +++++--- modules/core/exported/client.go | 8 -------- 3 files changed, 8 insertions(+), 14 deletions(-) diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index 3e69d08ec7d..981152818d3 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -358,12 +358,12 @@ func (k Keeper) VerifyMembership(c context.Context, req *types.QueryVerifyMember ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "verify membership query") }() - clientState, found := k.GetClientState(cachedCtx, req.ClientId) + lightClientModule, found := k.GetRouter().GetRoute(req.ClientId) if !found { - return nil, status.Error(codes.NotFound, errorsmod.Wrap(types.ErrClientNotFound, req.ClientId).Error()) + return nil, status.Error(codes.NotFound, req.ClientId) } - if err := clientState.VerifyMembership(cachedCtx, k.ClientStore(cachedCtx, req.ClientId), k.cdc, req.ProofHeight, req.TimeDelay, req.BlockDelay, req.Proof, req.MerklePath, req.Value); err != nil { + if err := lightClientModule.VerifyMembership(cachedCtx, req.ClientId, req.ProofHeight, req.TimeDelay, req.BlockDelay, req.Proof, req.MerklePath, req.Value); err != nil { k.Logger(ctx).Debug("proof verification failed", "key", req.MerklePath, "error", err) return &types.QueryVerifyMembershipResponse{ Success: false, diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 73500ecb096..eb6d92759b4 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -776,6 +776,8 @@ func (suite *KeeperTestSuite) TestQueryClientParams() { } func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() { + const wasmClientID = "08-wasm-0" + var ( path *ibctesting.Path req *types.QueryVerifyMembershipRequest @@ -870,17 +872,17 @@ func (suite *KeeperTestSuite) TestQueryVerifyMembershipProof() { errors.New("empty value"), }, { - "client not found", + "light client module not found", func() { req = &types.QueryVerifyMembershipRequest{ - ClientId: types.FormatClientIdentifier(exported.Tendermint, 100), // use a sequence which hasn't been created yet + ClientId: wasmClientID, // use a client type that is not registered Proof: []byte{0x01}, ProofHeight: types.NewHeight(1, 100), MerklePath: commitmenttypes.NewMerklePath("/ibc", host.ChannelPath(mock.PortID, ibctesting.FirstChannelID)), Value: []byte{0x01}, } }, - types.ErrClientNotFound, + errors.New(wasmClientID), }, } diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 2c1dc921302..93a7f039625 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -140,14 +140,6 @@ type ClientState interface { GetLatestHeight() Height Validate() error - // ExportMetadata must export metadata stored within the clientStore for genesis export - ExportMetadata(clientStore storetypes.KVStore) []GenesisMetadata - - // ZeroCustomFields zeroes out any client customizable fields in client state - // Ledger enforced fields are maintained while all custom fields are zero values - // Used to verify upgrades - ZeroCustomFields() ClientState - // Upgrade functions // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last // height committed by the current revision. Clients are responsible for ensuring that the planned last From f9eaf91020087cd2259c4a59b46ef12b4b695766 Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 27 Feb 2024 12:54:34 +0100 Subject: [PATCH 42/74] 02-client routing: remove client ID validation (#5897) * chore: remove client ID validation in light client module functions * add contract documentation * Update light_client_module.go * 02-client routing: add godoc to `LightClientModule` functions (#5900) * add godoc for light client module functions * linter * fix localhost client ID in godoc --- .../06-solomachine/light_client_module.go | 96 ++++-------- .../light_client_module_test.go | 14 -- .../07-tendermint/light_client_module.go | 144 ++++++------------ .../07-tendermint/light_client_module_test.go | 14 -- .../08-wasm/light_client_module.go | 99 ++++-------- .../08-wasm/light_client_module_test.go | 14 -- .../09-localhost/light_client_module.go | 118 +++++--------- 7 files changed, 140 insertions(+), 359 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index a0bf9f50f27..7e294693067 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -12,7 +12,7 @@ import ( var _ exported.LightClientModule = (*LightClientModule)(nil) -// LightClientModule implements the core IBC api.LightClientModule interface? +// LightClientModule implements the core IBC api.LightClientModule interface type LightClientModule struct { cdc codec.BinaryCodec storeProvider exported.ClientStoreProvider @@ -25,17 +25,18 @@ func NewLightClientModule(cdc codec.BinaryCodec) LightClientModule { } } +// RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. +// It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores +// to IBC light client instances. func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { lcm.storeProvider = storeProvider } // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { - if err := validateClientID(clientID); err != nil { - return err - } - var clientState ClientState if err := lcm.cdc.Unmarshal(clientStateBz, &clientState); err != nil { return err @@ -62,11 +63,9 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client // It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour // will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned // if the ClientMessage fails to verify. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - if err := validateClientID(clientID); err != nil { - return err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -78,11 +77,9 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage // has already been verified. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - if err := validateClientID(clientID); err != nil { - panic(err) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -92,12 +89,10 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri return clientState.CheckForMisbehaviour(ctx, lcm.cdc, clientStore, clientMsg) } -// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified +// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - if err := validateClientID(clientID); err != nil { - panic(err) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -109,11 +104,9 @@ func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID // 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. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - if err := validateClientID(clientID); err != nil { - panic(err) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -125,6 +118,8 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, @@ -135,10 +130,6 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, // TODO: change to conrete type value []byte, ) error { - if err := validateClientID(clientID); err != nil { - return err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -150,6 +141,8 @@ func (lcm LightClientModule) VerifyMembership( // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, @@ -159,10 +152,6 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - if err := validateClientID(clientID); err != nil { - return err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -173,11 +162,9 @@ func (lcm LightClientModule) VerifyNonMembership( } // Status must return the status of the client. Only Active clients are allowed to process packets. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - if err := validateClientID(clientID); err != nil { - return exported.Unknown // TODO: or panic - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -188,11 +175,9 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { - if err := validateClientID(clientID); err != nil { - return 0, err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, lcm.cdc) if !found { @@ -202,31 +187,11 @@ func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, return clientState.GetTimestampAtHeight(ctx, clientStore, lcm.cdc, height) } -func validateClientID(clientID string) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Solomachine { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Solomachine, clientType) - } - - return nil -} - // RecoverClient must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Solomachine { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Solomachine, clientType) - } - substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) if err != nil { return err @@ -255,14 +220,9 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return clientState.CheckSubstituteAndUpdateState(ctx, lcm.cdc, clientStore, substituteClientStore, substituteClient) } -// // Upgrade functions -// // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last -// // height committed by the current revision. Clients are responsible for ensuring that the planned last -// // height of the current revision is somehow encoded in the proof verification process. -// // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty -// // may be cancelled or modified before the last planned height. -// // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. -// // Deprecated: will be removed as performs internal functionality +// VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { return nil } diff --git a/modules/light-clients/06-solomachine/light_client_module_test.go b/modules/light-clients/06-solomachine/light_client_module_test.go index ce9cca27e8b..dbe423734ee 100644 --- a/modules/light-clients/06-solomachine/light_client_module_test.go +++ b/modules/light-clients/06-solomachine/light_client_module_test.go @@ -30,20 +30,6 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { }, nil, }, - { - "cannot parse malformed subject client ID", - func() { - subjectClientID = ibctesting.InvalidID - }, - host.ErrInvalidID, - }, - { - "subject client ID does not contain 06-machine prefix", - func() { - subjectClientID = wasmClientID - }, - clienttypes.ErrInvalidClientType, - }, { "cannot parse malformed substitute client ID", func() { diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 7a549d4329d..123d2b7d414 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -13,33 +13,31 @@ import ( var _ exported.LightClientModule = (*LightClientModule)(nil) +// LightClientModule implements the core IBC api.LightClientModule interface. type LightClientModule struct { keeper keeper.Keeper storeProvider exported.ClientStoreProvider } +// NewLightClientModule creates and returns a new 08-wasm LightClientModule. func NewLightClientModule(cdc codec.BinaryCodec, authority string) LightClientModule { return LightClientModule{ keeper: keeper.NewKeeper(cdc, authority), } } +// RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. +// It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores +// to IBC light client instances. func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { lcm.storeProvider = storeProvider } // Initialize checks that the initial consensus state is an 07-tendermint consensus state and // sets the client state, consensus state and associated metadata in the provided client store. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - var clientState ClientState if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { return err @@ -63,16 +61,13 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, &consensusState) } +// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. +// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour +// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned +// if the ClientMessage fails to verify. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -84,16 +79,11 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin return clientState.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) } +// CheckForMisbehaviour checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage +// has already been verified. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - panic(err) - } - - if clientType != exported.Tendermint { - panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -105,16 +95,10 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri return clientState.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) } +// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - panic(err) - } - - if clientType != exported.Tendermint { - panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -126,15 +110,11 @@ func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID clientState.UpdateStateOnMisbehaviour(ctx, cdc, clientStore, clientMsg) } +// 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. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - panic(err) - } - - if clientType != exported.Tendermint { - panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType)) - } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -146,6 +126,10 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } +// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, @@ -156,15 +140,6 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, value []byte, ) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -176,6 +151,10 @@ func (lcm LightClientModule) VerifyMembership( return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } +// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, @@ -185,15 +164,6 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -205,16 +175,10 @@ func (lcm LightClientModule) VerifyNonMembership( return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } +// Status must return the status of the client. Only Active clients are allowed to process packets. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return exported.Unknown - } - - if clientType != exported.Tendermint { - return exported.Unknown - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -226,20 +190,14 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S return clientState.Status(ctx, clientStore, cdc) } +// TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) TimestampAtHeight( ctx sdk.Context, clientID string, height exported.Height, ) (uint64, error) { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return 0, err - } - - if clientType != exported.Tendermint { - return 0, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -251,16 +209,11 @@ func (lcm LightClientModule) TimestampAtHeight( return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } +// RecoverClient must verify that the provided substitute may be used to update the subject client. +// The light client must set the updated client and consensus states within the clientStore for the subject client. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) if err != nil { return err @@ -291,6 +244,10 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } +// VerifyUpgradeAndUpdateState, on a successful verification expects the contract to update +// the new client state, consensus state, and any other client metadata. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, @@ -299,15 +256,6 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( upgradeClientProof, upgradeConsensusStateProof []byte, ) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Tendermint { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, clientType) - } - var newClientState ClientState if err := lcm.keeper.Codec().Unmarshal(newClient, &newClientState); err != nil { return err 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 d8b0af1515e..708875f4456 100644 --- a/modules/light-clients/07-tendermint/light_client_module_test.go +++ b/modules/light-clients/07-tendermint/light_client_module_test.go @@ -30,20 +30,6 @@ func (suite *TendermintTestSuite) TestRecoverClient() { }, nil, }, - { - "cannot parse malformed subject client ID", - func() { - subjectClientID = ibctesting.InvalidID - }, - host.ErrInvalidID, - }, - { - "subject client ID does not contain 07-tendermint prefix", - func() { - subjectClientID = solomachineClientID - }, - clienttypes.ErrInvalidClientType, - }, { "cannot parse malformed substitute client ID", func() { diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 65e0e785509..7f0b5284636 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -13,7 +13,7 @@ import ( var _ exported.LightClientModule = (*LightClientModule)(nil) -// LightClientModule implements the core IBC api.LightClientModule interface? +// LightClientModule implements the core IBC api.LightClientModule interface. type LightClientModule struct { keeper wasmkeeper.Keeper storeProvider exported.ClientStoreProvider @@ -26,17 +26,18 @@ func NewLightClientModule(keeper wasmkeeper.Keeper) LightClientModule { } } +// RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. +// It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores +// to IBC light client instances. func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { lcm.storeProvider = storeProvider } // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { - if err := validateClientID(clientID); err != nil { - return err - } - var clientState types.ClientState if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { return err @@ -65,11 +66,9 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client // It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour // will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned // if the ClientMessage fails to verify. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - if err := validateClientID(clientID); err != nil { - return err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -81,13 +80,11 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin return clientState.VerifyClientMessage(ctx, lcm.keeper.Codec(), clientStore, clientMsg) } -// Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage +// CheckForMisbehaviour checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage // has already been verified. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - if err := validateClientID(clientID); err != nil { - panic(err) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -99,12 +96,10 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri return clientState.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) } -// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified +// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - if err := validateClientID(clientID); err != nil { - panic(err) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -118,11 +113,9 @@ func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID // 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. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - if err := validateClientID(clientID); err != nil { - panic(err) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -136,6 +129,8 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, @@ -146,10 +141,6 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, // TODO: change to conrete type value []byte, ) error { - if err := validateClientID(clientID); err != nil { - return err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -163,6 +154,8 @@ func (lcm LightClientModule) VerifyMembership( // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, @@ -172,10 +165,6 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - if err := validateClientID(clientID); err != nil { - return err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -188,11 +177,9 @@ func (lcm LightClientModule) VerifyNonMembership( } // Status must return the status of the client. Only Active clients are allowed to process packets. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - if err := validateClientID(clientID); err != nil { - return exported.Unknown // TODO: or panic - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -205,11 +192,9 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S } // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { - if err := validateClientID(clientID); err != nil { - return 0, err - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.keeper.Codec() @@ -221,31 +206,11 @@ func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } -func validateClientID(clientID string) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != types.Wasm { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", types.Wasm, clientType) - } - - return nil -} - // RecoverClient must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != types.Wasm { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", types.Wasm, clientType) - } - substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) if err != nil { return err @@ -276,14 +241,10 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } -// // Upgrade functions -// // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last -// // height committed by the current revision. Clients are responsible for ensuring that the planned last -// // height of the current revision is somehow encoded in the proof verification process. -// // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty -// // may be cancelled or modified before the last planned height. -// // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. -// // DEPRECATED: will be removed as performs internal functionality +// VerifyUpgradeAndUpdateState, on a successful verification expects the contract to update +// the new client state, consensus state, and any other client metadata. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { return nil } diff --git a/modules/light-clients/08-wasm/light_client_module_test.go b/modules/light-clients/08-wasm/light_client_module_test.go index aad9c8c308d..120b40ce2e3 100644 --- a/modules/light-clients/08-wasm/light_client_module_test.go +++ b/modules/light-clients/08-wasm/light_client_module_test.go @@ -33,20 +33,6 @@ func (suite *WasmTestSuite) TestRecoverClient() { // }, // nil, // }, - { - "cannot parse malformed subject client ID", - func() { - subjectClientID = ibctesting.InvalidID - }, - host.ErrInvalidID, - }, - { - "subject client ID does not contain 08-wasm prefix", - func() { - subjectClientID = tmClientID - }, - clienttypes.ErrInvalidClientType, - }, { "cannot parse malformed substitute client ID", func() { diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index 87dce96aa55..9fb0f7a349f 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -14,12 +14,14 @@ import ( var _ exported.LightClientModule = (*LightClientModule)(nil) +// LightClientModule implements the core IBC api.LightClientModule interface. type LightClientModule struct { cdc codec.BinaryCodec key storetypes.StoreKey storeProvider exported.ClientStoreProvider } +// NewLightClientModule creates and returns a new 09-localhost LightClientModule. func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) *LightClientModule { return &LightClientModule{ cdc: cdc, @@ -27,20 +29,17 @@ func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) *Light } } +// RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. +// It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores +// to IBC light client instances. func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { lcm.storeProvider = storeProvider } -func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Localhost { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) - } - +// Initialize ensures that initial consensus state for localhost is nil. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. +func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, _, consensusStateBz []byte) error { if len(consensusStateBz) != 0 { return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") } @@ -54,60 +53,28 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return nil } -func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Localhost { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) - } - - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.cdc - - clientState, found := getClientState(clientStore, cdc) - if !found { - return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) - } - - return clientState.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) +// VerifyClientMessage is unsupported by the 09-localhost client type and returns an error. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. +func (LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "client message verification is unsupported by the localhost client") } +// CheckForMisbehaviour is unsupported by the 09-localhost client type and performs a no-op, returning false. func (LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - panic(err) - } - - if clientType != exported.Localhost { - panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) - } - return false } +// UpdateStateOnMisbehaviour is unsupported by the 09-localhost client type and performs a no-op. func (LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - panic(err) - } - - if clientType != exported.Localhost { - panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) - } + // no-op } +// 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. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - panic(err) - } - - if clientType != exported.Localhost { - panic(errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType)) - } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) cdc := lcm.cdc @@ -119,6 +86,11 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } +// VerifyMembership is a generic proof verification method which verifies the existence of a given key and value within the IBC store. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// The caller must provide the full IBC store. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. func (lcm LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, @@ -129,15 +101,6 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, value []byte, ) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Localhost { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) ibcStore := ctx.KVStore(lcm.key) cdc := lcm.cdc @@ -150,6 +113,11 @@ func (lcm LightClientModule) VerifyMembership( return clientState.VerifyMembership(ctx, ibcStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } +// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath within the IBC store. +// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// The caller must provide the full IBC store. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. func (lcm LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, @@ -159,15 +127,6 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return err - } - - if clientType != exported.Localhost { - return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) - } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) ibcStore := ctx.KVStore(lcm.key) cdc := lcm.cdc @@ -185,27 +144,22 @@ func (LightClientModule) Status(ctx sdk.Context, clientID string) exported.Statu return exported.Active } +// TimestampAtHeight returns the current block time retrieved from the application context. The localhost client does not store consensus states and thus +// cannot provide a timestamp for the provided height. func (LightClientModule) TimestampAtHeight( ctx sdk.Context, clientID string, height exported.Height, ) (uint64, error) { - clientType, _, err := clienttypes.ParseClientIdentifier(clientID) - if err != nil { - return 0, err - } - - if clientType != exported.Localhost { - return 0, errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Localhost, clientType) - } - return uint64(ctx.BlockTime().UnixNano()), nil } -func (LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +// RecoverClient returns an error. The localhost cannot be modified by proposals. +func (LightClientModule) RecoverClient(_ sdk.Context, _, _ string) error { return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") } +// VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded. func (LightClientModule) VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, From 68bb9f24e1452e3acf6a73f8bc9a45a562b5908f Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 7 Mar 2024 21:26:33 +0100 Subject: [PATCH 43/74] docs: add removal of `ClientState` interface functions to migration docs (#5943) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs: add removal of client state functions to migration docs * test formating * add comment about tendermint light client module implementation * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * mention removal of ZeroCustomFields * Update docs/docs/05-migrations/13-v8-to-v9.md Co-authored-by: DimitrisJim --------- Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> Co-authored-by: DimitrisJim --- docs/docs/05-migrations/13-v8-to-v9.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/docs/docs/05-migrations/13-v8-to-v9.md b/docs/docs/05-migrations/13-v8-to-v9.md index ba6bd719a45..d031c9fcb44 100644 --- a/docs/docs/05-migrations/13-v8-to-v9.md +++ b/docs/docs/05-migrations/13-v8-to-v9.md @@ -55,6 +55,29 @@ Please use the new functions `path.Setup`, `path.SetupClients`, `path.SetupConne The `ExportMetadata` interface function has been removed from the `ClientState` interface. Core IBC will export all key/value's within the 02-client store. +The `ZeroCustomFields` interface function has been removed from the `ClientState` interface. + +The following functions have also been removed from the `ClientState` interface: `Initialize`, `Status`, `GetLatestHeight`, `GetTimestampAtHeight`, `VerifyClientMessage`, `VerifyMembership`, `VerifyNonMembership`, `CheckForMisbehaviour`, `UpdateState`, `UpdateStateOnMisbehaviour`, `CheckSubstituteAndUpdateState` and `VerifyUpgradeAndUpdateState`. ibc-go v9 decouples routing at the `02-client` layer from the light clients' encoding structure (i.e. every light client implementation of the `ClientState` interface is not used anymore to route the requests to the right light client at the `02-client` layer, instead a _light client module_ is registered for every light client type and `02-client` routes the requests to the right light client module based on the client ID). Light client developers must implement the newly introduced `LightClientModule` interface and are encouraged to move the logic implemented in the functions of their light client's implementation of the `ClientState` interface to the equivalent function in the `LightClientModule` interface. The table below shows the equivalence between the `ClientState` interface functions that have been removed and the functions in the `LightClientModule` interface: + +|`ClientState` interface|`LightClientModule` interface| +|-----------------------|-----------------------------| +|`Initialize` |`Initialize` | +|`Status` |`Status` | +|`GetLatestHeight` |`LatestHeight` | +|`GetTimestampAtHeight` |`TimestampAtHeight` | +|`VerifyClientMessage` |`VerifyClientMessage` | +|`VerifyMembership` |`VerifyMembership` | +|`VerifyNonMembership` |`VerifyNonMembership` | +|`CheckForMisbehaviour` |`CheckForMisbehaviour` | +|`UpdateState` |`UpdateState` | +|`UpdateStateOnMisbehaviour` |`UpdateStateOnMisbehaviour` | +|`CheckSubstituteAndUpdateState`|`RecoverClient` | +|`VerifyUpgradeAndUpdateState` |`VerifyUpgradeAndUpdateState`| +|`ExportMetadata` | | +|`ZeroCustomFields` | | + +Please check also the [light client developer guide](../03-light-clients/01-developer-guide/01-overview.md) for more information. The light client module implementation for `07-tendermint` may also be useful as reference. + ### 07-tendermint The `IterateConsensusMetadata` function has been removed. From 501a8462345da099144efe91d495bfcfa18d760d Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Mon, 11 Mar 2024 16:43:40 +0100 Subject: [PATCH 44/74] 02-client routing: remove `GetLatestHeight` from `ClientState` interface and add it to `LightClientModule` (#5866) * wip: remove GetLatestHeight from ClientState interface and add it to light client module * chore: add godoc for GetLatestHeight in 02-client keeper * chore: add args to event emission funcs in 02-client * chore: add args to usage in 02-client event emissions * chore: put back logging in upgrade client * chore: deprecate and refactor 04-channel client utils QueryLatestConsensusState func * chore: rename lightClientModule to clientModule in core * chore: undo faulty renames * fix: godoc for LatestHeight * chore: add godocs * chore: readding sequence checking in solomachine RecoverClient * fix: testing chain helper to use keeper getter for latest height * chore: fix compilation errors in tests * fix: import ordering waaah * imp: adding GetClientLatestHeight to testing endpoint/chain * test: cleanup test funcs with path.Endpoint.GetClientLatestHeight * test: cleanup tests in 04-channel to use path.Endpoint.GetClientLatestHeight * test: cleanup ante_test * chore: add godocs for light client modules LatestHeight method * chore: update endpoint.go to use the new GetClientLatestHeight helper fn * test: usage of path.Endpoint.GetClientLatestHeight in core/keeper and 07-tendermint tests * test: another one * chore: rm GetLatestHeight from solomachine ClientState * test: update QueryConsensusStateProof in testing lib to use test helper * Update testing/chain.go * fix typo in variable name * chore: consolidate two calls to LatestHeight to initialHeight var on createClient * chore: extract to latestHeight var in VerifyUpgradeAndUpdateState to reduce disk reads * chore: rm greater than or equal height check in solomachine as already done in 02-client * chore: address todo on GetLatestHeight in 02-client keeper --------- Co-authored-by: Damian Nolan Co-authored-by: chatton --- .../01-developer-guide/02-client-state.md | 4 - e2e/tests/core/02-client/client_test.go | 8 +- e2e/tests/transfer/localhost_test.go | 4 +- modules/core/02-client/keeper/client.go | 46 ++++---- modules/core/02-client/keeper/client_test.go | 98 ++++++++++------ modules/core/02-client/keeper/events.go | 10 +- modules/core/02-client/keeper/events_test.go | 9 +- modules/core/02-client/keeper/grpc_query.go | 4 +- .../core/02-client/keeper/grpc_query_test.go | 16 +-- modules/core/02-client/keeper/keeper.go | 45 ++++++-- modules/core/02-client/keeper/keeper_test.go | 19 ++-- modules/core/02-client/types/client_test.go | 7 +- modules/core/02-client/types/router.go | 3 - modules/core/02-client/types/store.go | 2 + .../03-connection/keeper/grpc_query_test.go | 8 +- .../03-connection/keeper/handshake_test.go | 10 +- .../core/03-connection/keeper/keeper_test.go | 4 +- modules/core/03-connection/keeper/verify.go | 40 +++---- .../core/03-connection/keeper/verify_test.go | 4 +- modules/core/04-channel/client/utils/utils.go | 14 ++- .../core/04-channel/keeper/grpc_query_test.go | 7 +- modules/core/04-channel/keeper/packet.go | 11 +- modules/core/04-channel/keeper/packet_test.go | 11 +- .../core/04-channel/types/expected_keepers.go | 4 +- modules/core/ante/ante_test.go | 4 +- modules/core/exported/client.go | 4 +- modules/core/keeper/msg_server_test.go | 12 +- .../06-solomachine/client_state.go | 9 +- .../06-solomachine/client_state_test.go | 2 +- .../06-solomachine/light_client_module.go | 20 +++- .../light_client_module_test.go | 32 +----- .../06-solomachine/solomachine_test.go | 4 +- .../07-tendermint/client_state.go | 19 ++-- .../07-tendermint/client_state_test.go | 24 ++-- .../07-tendermint/light_client_module.go | 19 +++- .../07-tendermint/light_client_module_test.go | 25 +---- .../migrations/migrations_test.go | 8 +- .../07-tendermint/misbehaviour_handle_test.go | 100 ++++++++--------- .../07-tendermint/proposal_handle.go | 2 +- .../07-tendermint/proposal_handle_test.go | 26 ++--- .../light-clients/07-tendermint/store_test.go | 12 +- .../07-tendermint/update_test.go | 92 +++++++-------- .../light-clients/07-tendermint/upgrade.go | 2 +- .../07-tendermint/upgrade_test.go | 106 ++++++++++++------ .../08-wasm/keeper/keeper_test.go | 7 +- .../08-wasm/light_client_module.go | 20 +++- .../08-wasm/light_client_module_test.go | 30 +---- .../light-clients/08-wasm/testing/values.go | 2 +- .../08-wasm/types/client_state.go | 13 +-- .../08-wasm/types/client_state_test.go | 13 ++- .../light-clients/08-wasm/types/types_test.go | 7 +- .../08-wasm/types/upgrade_test.go | 6 +- .../light-clients/08-wasm/types/vm_test.go | 11 +- modules/light-clients/08-wasm/wasm_test.go | 7 +- .../09-localhost/client_state.go | 5 - .../09-localhost/client_state_test.go | 4 +- .../09-localhost/light_client_module.go | 15 +++ testing/chain.go | 12 +- testing/endpoint.go | 25 +++-- testing/solomachine.go | 2 +- 60 files changed, 573 insertions(+), 516 deletions(-) diff --git a/docs/docs/03-light-clients/01-developer-guide/02-client-state.md b/docs/docs/03-light-clients/01-developer-guide/02-client-state.md index cad1982fc97..58649b6f825 100644 --- a/docs/docs/03-light-clients/01-developer-guide/02-client-state.md +++ b/docs/docs/03-light-clients/01-developer-guide/02-client-state.md @@ -15,10 +15,6 @@ Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob `ClientType` should return a unique string identifier of the light client. This will be used when generating a client identifier. The format is created as follows: `ClientType-{N}` where `{N}` is the unique global nonce associated with a specific client. -## `GetLatestHeight` method - -`GetLatestHeight` should return the latest block height that the client state represents. - ## `Validate` method `Validate` should validate every client state field and should return an error if any value is invalid. The light client diff --git a/e2e/tests/core/02-client/client_test.go b/e2e/tests/core/02-client/client_test.go index 784ced70e4f..83186f87098 100644 --- a/e2e/tests/core/02-client/client_test.go +++ b/e2e/tests/core/02-client/client_test.go @@ -361,8 +361,8 @@ func (s *ClientTestSuite) TestClient_Update_Misbehaviour() { tmClientState, ok := clientState.(*ibctm.ClientState) s.Require().True(ok) - trustedHeight, ok = tmClientState.GetLatestHeight().(clienttypes.Height) - s.Require().True(ok) + trustedHeight := tmClientState.LatestHeight + s.Require().True(trustedHeight.GT(clienttypes.ZeroHeight())) }) t.Run("update clients", func(t *testing.T) { @@ -377,8 +377,8 @@ func (s *ClientTestSuite) TestClient_Update_Misbehaviour() { tmClientState, ok := clientState.(*ibctm.ClientState) s.Require().True(ok) - latestHeight, ok = tmClientState.GetLatestHeight().(clienttypes.Height) - s.Require().True(ok) + latestHeight := tmClientState.LatestHeight + s.Require().True(latestHeight.GT(clienttypes.ZeroHeight())) }) t.Run("create validator set", func(t *testing.T) { diff --git a/e2e/tests/transfer/localhost_test.go b/e2e/tests/transfer/localhost_test.go index 00825c266ed..57ad937cd75 100644 --- a/e2e/tests/transfer/localhost_test.go +++ b/e2e/tests/transfer/localhost_test.go @@ -55,13 +55,13 @@ func (s *LocalhostTransferTestSuite) TestMsgTransfer_Localhost() { t.Run("verify begin blocker was executed", func(t *testing.T) { cs, err := s.QueryClientState(ctx, chainA, exported.LocalhostClientID) s.Require().NoError(err) - originalHeight := cs.GetLatestHeight() + originalHeight := cs.(*localhost.ClientState).LatestHeight s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA), "failed to wait for blocks") cs, err = s.QueryClientState(ctx, chainA, exported.LocalhostClientID) s.Require().NoError(err) - s.Require().True(cs.GetLatestHeight().GT(originalHeight), "client state height was not incremented") + s.Require().True(cs.(*localhost.ClientState).LatestHeight.GT(originalHeight), "client state height was not incremented") }) t.Run("channel open init localhost", func(t *testing.T) { diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index e33f09ea90e..b47d75b260d 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -9,7 +9,6 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" - ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -33,12 +32,12 @@ func (k Keeper) CreateClient( clientID := k.GenerateClientIdentifier(ctx, clientType) - lightClientModule, found := k.router.GetRoute(clientID) + clientModule, found := k.router.GetRoute(clientID) if !found { return "", errorsmod.Wrap(types.ErrRouteNotFound, clientID) } - if err := lightClientModule.Initialize(ctx, clientID, clientState, consensusState); err != nil { + if err := clientModule.Initialize(ctx, clientID, clientState, consensusState); err != nil { return "", err } @@ -46,7 +45,8 @@ func (k Keeper) CreateClient( return "", errorsmod.Wrapf(types.ErrClientNotActive, "cannot create client (%s) with status %s", clientID, status) } - // k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String()) + initialHeight := clientModule.LatestHeight(ctx, clientID) + k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", initialHeight.String()) defer telemetry.IncrCounterWithLabels( []string{"ibc", "client", "create"}, @@ -54,7 +54,7 @@ func (k Keeper) CreateClient( []metrics.Label{telemetry.NewLabel(types.LabelClientType, clientType)}, ) - emitCreateClientEvent(ctx, clientID, clientType) + emitCreateClientEvent(ctx, clientID, clientType, initialHeight) return clientID, nil } @@ -70,18 +70,18 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) } - lightClientModule, found := k.router.GetRoute(clientID) + clientModule, found := k.router.GetRoute(clientID) if !found { return errorsmod.Wrap(types.ErrRouteNotFound, clientID) } - if err := lightClientModule.VerifyClientMessage(ctx, clientID, clientMsg); err != nil { + if err := clientModule.VerifyClientMessage(ctx, clientID, clientMsg); err != nil { return err } - foundMisbehaviour := lightClientModule.CheckForMisbehaviour(ctx, clientID, clientMsg) + foundMisbehaviour := clientModule.CheckForMisbehaviour(ctx, clientID, clientMsg) if foundMisbehaviour { - lightClientModule.UpdateStateOnMisbehaviour(ctx, clientID, clientMsg) + clientModule.UpdateStateOnMisbehaviour(ctx, clientID, clientMsg) k.Logger(ctx).Info("client frozen due to misbehaviour", "client-id", clientID) @@ -100,7 +100,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte return nil } - consensusHeights := lightClientModule.UpdateState(ctx, clientID, clientMsg) + consensusHeights := clientModule.UpdateState(ctx, clientID, clientMsg) k.Logger(ctx).Info("client state updated", "client-id", clientID, "heights", consensusHeights) @@ -136,13 +136,14 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e return errorsmod.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status) } + // TODO: This code is removed in https://github.com/cosmos/ibc-go/pull/5827 // last height of current counterparty chain must be client's latest height - lastHeight := clientState.GetLatestHeight() + // lastHeight := k.GetLatestHeight(ctx, clientID) - if !upgradedClient.GetLatestHeight().GT(lastHeight) { - return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", - upgradedClient.GetLatestHeight(), lastHeight) - } + // if !upgradedClient.GetLatestHeight().GT(lastHeight) { + // return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", + // upgradedClient.GetLatestHeight(), lastHeight) + // } if err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore, upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof, @@ -150,7 +151,8 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e return errorsmod.Wrapf(err, "cannot upgrade client with ID %s", clientID) } - k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", upgradedClient.GetLatestHeight().String()) + latestHeight := k.GetLatestHeight(ctx, clientID) // TODO: use clientModule when addressing this func in https://github.com/cosmos/ibc-go/pull/5827 + k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", latestHeight.String()) defer telemetry.IncrCounterWithLabels( []string{"ibc", "client", "upgrade"}, @@ -161,7 +163,7 @@ func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient e }, ) - emitUpgradeClientEvent(ctx, clientID, upgradedClient) + emitUpgradeClientEvent(ctx, clientID, upgradedClient.ClientType(), latestHeight) return nil } @@ -187,12 +189,18 @@ func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClient return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", subjectClientID) } - lightClientModule, found := k.router.GetRoute(subjectClientID) + clientModule, found := k.router.GetRoute(subjectClientID) if !found { return errorsmod.Wrap(types.ErrRouteNotFound, subjectClientID) } - if err := lightClientModule.RecoverClient(ctx, subjectClientID, substituteClientID); err != nil { + subjectLatestHeight := clientModule.LatestHeight(ctx, subjectClientID) + substituteLatestHeight := clientModule.LatestHeight(ctx, substituteClientID) + if subjectLatestHeight.GTE(substituteLatestHeight) { + return errorsmod.Wrapf(types.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", subjectLatestHeight, substituteLatestHeight) + } + + if err := clientModule.RecoverClient(ctx, subjectClientID, substituteClientID); err != nil { return err } diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index f7ca875d4f7..31e0589acdb 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -127,21 +127,19 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { expFreeze bool }{ {"valid update", func() { - clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) - trustHeight := clientState.GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight() // store intermediate consensus state to check that trustedHeight does not need to be highest consensus state before header height err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - updateHeader = createFutureUpdateFn(trustHeight) + updateHeader = createFutureUpdateFn(trustedHeight.(clienttypes.Height)) }, true, false}, {"valid past update", func() { - clientState := path.EndpointA.GetClientState() - trustedHeight := clientState.GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight() currHeight := suite.chainB.ProposedHeader.Height - fillHeight := clienttypes.NewHeight(clientState.GetLatestHeight().GetRevisionNumber(), uint64(currHeight)) + fillHeight := clienttypes.NewHeight(trustedHeight.GetRevisionNumber(), uint64(currHeight)) // commit a couple blocks to allow client to fill in gaps suite.coordinator.CommitBlock(suite.chainB) // this height is not filled in yet @@ -156,7 +154,7 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { // updateHeader will fill in consensus state between prevConsState and suite.consState // clientState should not be updated - updateHeader = createPastUpdateFn(fillHeight, trustedHeight) + updateHeader = createPastUpdateFn(fillHeight, trustedHeight.(clienttypes.Height)) }, true, false}, {"valid duplicate update", func() { height1 := clienttypes.NewHeight(1, 1) @@ -219,11 +217,11 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { {"misbehaviour detection: monotonic time violation", func() { clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientID := path.EndpointA.ClientID - trustedHeight := clientState.GetLatestHeight().(clienttypes.Height) + trustedHeight := clientState.LatestHeight // store intermediate consensus state at a time greater than updateHeader time // this will break time monotonicity - incrementedClientHeight := clientState.GetLatestHeight().Increment().(clienttypes.Height) + incrementedClientHeight := clientState.LatestHeight.Increment().(clienttypes.Height) intermediateConsState := &ibctm.ConsensusState{ Timestamp: suite.coordinator.CurrentTime.Add(2 * time.Hour), NextValidatorsHash: suite.chainB.Vals.Hash(), @@ -239,7 +237,8 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { updateHeader = createFutureUpdateFn(trustedHeight) }, true, true}, {"client state not found", func() { - updateHeader = createFutureUpdateFn(path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height)) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + updateHeader = createFutureUpdateFn(clientState.LatestHeight) path.EndpointA.ClientID = ibctesting.InvalidID }, false, false}, @@ -250,16 +249,17 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { tmClient.LatestHeight = tmClient.LatestHeight.Increment().(clienttypes.Height) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientState) - updateHeader = createFutureUpdateFn(clientState.GetLatestHeight().(clienttypes.Height)) + updateHeader = createFutureUpdateFn(tmClient.LatestHeight) }, false, false}, {"client is not active", func() { clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) clientState.FrozenHeight = clienttypes.NewHeight(1, 1) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), path.EndpointA.ClientID, clientState) - updateHeader = createFutureUpdateFn(clientState.GetLatestHeight().(clienttypes.Height)) + updateHeader = createFutureUpdateFn(clientState.LatestHeight) }, false, false}, {"invalid header", func() { - updateHeader = createFutureUpdateFn(path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height)) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + updateHeader = createFutureUpdateFn(clientState.LatestHeight) updateHeader.TrustedHeight = updateHeader.TrustedHeight.Increment().(clienttypes.Height) }, false, false}, } @@ -273,9 +273,9 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { tc.malleate() - var clientState exported.ClientState + var clientState *ibctm.ClientState if tc.expPass { - clientState = path.EndpointA.GetClientState() + clientState = path.EndpointA.GetClientState().(*ibctm.ClientState) } err := suite.chainA.App.GetIBCKeeper().ClientKeeper.UpdateClient(suite.chainA.GetContext(), path.EndpointA.ClientID, updateHeader) @@ -283,10 +283,10 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { if tc.expPass { suite.Require().NoError(err, err) - newClientState := path.EndpointA.GetClientState() + newClientState := path.EndpointA.GetClientState().(*ibctm.ClientState) if tc.expFreeze { - suite.Require().True(!newClientState.(*ibctm.ClientState).FrozenHeight.IsZero(), "client did not freeze after conflicting header was submitted to UpdateClient") + suite.Require().True(!newClientState.FrozenHeight.IsZero(), "client did not freeze after conflicting header was submitted to UpdateClient") } else { expConsensusState := &ibctm.ConsensusState{ Timestamp: updateHeader.GetTime(), @@ -298,12 +298,12 @@ func (suite *KeeperTestSuite) TestUpdateClientTendermint() { suite.Require().True(found) // Determine if clientState should be updated or not - if updateHeader.GetHeight().GT(clientState.GetLatestHeight()) { + if updateHeader.GetHeight().GT(clientState.LatestHeight) { // Header Height is greater than clientState latest Height, clientState should be updated with header.GetHeight() - suite.Require().Equal(updateHeader.GetHeight(), newClientState.GetLatestHeight(), "clientstate height did not update") + suite.Require().Equal(updateHeader.GetHeight(), newClientState.LatestHeight, "clientstate height did not update") } else { // Update will add past consensus state, clientState should not be updated at all - suite.Require().Equal(clientState.GetLatestHeight(), newClientState.GetLatestHeight(), "client state height updated for past header") + suite.Require().Equal(clientState.LatestHeight, newClientState.LatestHeight, "client state height updated for past header") } suite.Require().NoError(err) @@ -350,9 +350,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -376,9 +378,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) path.EndpointA.ClientID = "wrongclientid" }, @@ -406,9 +410,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) // set frozen client in store tmClient, ok := cs.(*ibctm.ClientState) @@ -439,9 +445,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -466,9 +474,11 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -485,7 +495,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) suite.Require().NoError(err) - upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.GetLatestHeight().GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) upgradedClient = upgradedClient.ZeroCustomFields() upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -512,7 +522,7 @@ func (suite *KeeperTestSuite) TestUpdateClientEventEmission() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientState().(*ibctm.ClientState).LatestHeight header, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) @@ -552,9 +562,9 @@ func (suite *KeeperTestSuite) TestRecoverClient() { suite.Require().True(ok) consState, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight) suite.Require().True(found) - newRevisionNumber := tmClientState.GetLatestHeight().GetRevisionNumber() + 1 + newRevisionNumber := tmClientState.LatestHeight.GetRevisionNumber() + 1 - tmClientState.LatestHeight = clienttypes.NewHeight(newRevisionNumber, tmClientState.GetLatestHeight().GetRevisionHeight()) + tmClientState.LatestHeight = clienttypes.NewHeight(newRevisionNumber, tmClientState.LatestHeight.GetRevisionHeight()) suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), substitute, tmClientState.LatestHeight, consState) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitute) @@ -589,6 +599,26 @@ func (suite *KeeperTestSuite) TestRecoverClient() { }, clienttypes.ErrClientNotActive, }, + { + "subject and substitute have equal latest height", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.(*ibctm.ClientState).LatestHeight + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + }, + clienttypes.ErrInvalidHeight, + }, + { + "subject height is greater than substitute height", + func() { + tmClientState, ok := subjectClientState.(*ibctm.ClientState) + suite.Require().True(ok) + tmClientState.LatestHeight = substituteClientState.(*ibctm.ClientState).LatestHeight.Increment().(clienttypes.Height) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subject, tmClientState) + }, + clienttypes.ErrInvalidHeight, + }, { "substitute is frozen", func() { diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index 3c57db7ef2e..828aa4820ba 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -15,13 +15,13 @@ import ( ) // emitCreateClientEvent emits a create client event -func emitCreateClientEvent(ctx sdk.Context, clientID, clientType string) { +func emitCreateClientEvent(ctx sdk.Context, clientID, clientType string, latestHeight exported.Height) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeCreateClient, sdk.NewAttribute(types.AttributeKeyClientID, clientID), sdk.NewAttribute(types.AttributeKeyClientType, clientType), - // sdk.NewAttribute(types.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), + sdk.NewAttribute(types.AttributeKeyConsensusHeight, latestHeight.String()), ), sdk.NewEvent( sdk.EventTypeMessage, @@ -60,13 +60,13 @@ func emitUpdateClientEvent(ctx sdk.Context, clientID string, clientType string, } // emitUpgradeClientEvent emits an upgrade client event -func emitUpgradeClientEvent(ctx sdk.Context, clientID string, clientState exported.ClientState) { +func emitUpgradeClientEvent(ctx sdk.Context, clientID, clientType string, latestHeight exported.Height) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeUpgradeClient, sdk.NewAttribute(types.AttributeKeyClientID, clientID), - sdk.NewAttribute(types.AttributeKeyClientType, clientState.ClientType()), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), + sdk.NewAttribute(types.AttributeKeyClientType, clientType), + sdk.NewAttribute(types.AttributeKeyConsensusHeight, latestHeight.String()), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/core/02-client/keeper/events_test.go b/modules/core/02-client/keeper/events_test.go index a1dcbe9ffa9..45423239e98 100644 --- a/modules/core/02-client/keeper/events_test.go +++ b/modules/core/02-client/keeper/events_test.go @@ -39,7 +39,7 @@ func (suite *KeeperTestSuite) TestMsgCreateClientEvents() { clienttypes.EventTypeCreateClient, sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID), sdk.NewAttribute(clienttypes.AttributeKeyClientType, clientState.ClientType()), - // sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, clientState.GetLatestHeight().String()), + sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, clientState.LatestHeight.String()), ), }.ToABCIEvents() @@ -56,7 +56,8 @@ func (suite *KeeperTestSuite) TestMsgUpdateClientEvents() { suite.chainB.Coordinator.CommitBlock(suite.chainB) - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + trustedHeight := clientState.LatestHeight header, err := suite.chainB.IBCClientHeader(suite.chainB.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) suite.Require().NotNil(header) @@ -78,8 +79,8 @@ func (suite *KeeperTestSuite) TestMsgUpdateClientEvents() { clienttypes.EventTypeUpdateClient, sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID), sdk.NewAttribute(clienttypes.AttributeKeyClientType, path.EndpointA.GetClientState().ClientType()), - sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, path.EndpointA.GetClientState().GetLatestHeight().String()), - sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeights, path.EndpointA.GetClientState().GetLatestHeight().String()), + sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, path.EndpointA.GetClientLatestHeight().String()), + sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeights, path.EndpointA.GetClientLatestHeight().String()), ), }.ToABCIEvents() diff --git a/modules/core/02-client/keeper/grpc_query.go b/modules/core/02-client/keeper/grpc_query.go index 6f273499438..1d35b644159 100644 --- a/modules/core/02-client/keeper/grpc_query.go +++ b/modules/core/02-client/keeper/grpc_query.go @@ -369,7 +369,7 @@ func (k Keeper) VerifyMembership(c context.Context, req *types.QueryVerifyMember ctx.GasMeter().ConsumeGas(cachedCtx.GasMeter().GasConsumed(), "verify membership query") }() - lightClientModule, found := k.GetRouter().GetRoute(req.ClientId) + clientModule, found := k.GetRouter().GetRoute(req.ClientId) if !found { return nil, status.Error(codes.NotFound, req.ClientId) } @@ -378,7 +378,7 @@ func (k Keeper) VerifyMembership(c context.Context, req *types.QueryVerifyMember return nil, status.Error(codes.FailedPrecondition, errorsmod.Wrapf(types.ErrClientNotActive, "cannot verify membership using client (%s) with status %s", req.ClientId, clientStatus).Error()) } - if err := lightClientModule.VerifyMembership(cachedCtx, req.ClientId, req.ProofHeight, req.TimeDelay, req.BlockDelay, req.Proof, req.MerklePath, req.Value); err != nil { + if err := clientModule.VerifyMembership(cachedCtx, req.ClientId, req.ProofHeight, req.TimeDelay, req.BlockDelay, req.Proof, req.MerklePath, req.Value); err != nil { k.Logger(ctx).Debug("proof verification failed", "key", req.MerklePath, "error", err) return &types.QueryVerifyMembershipResponse{ Success: false, diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index af3fe15ddc8..2d7090d38a5 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -241,7 +241,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() { func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - cs := path.EndpointA.GetConsensusState(path.EndpointA.GetClientState().GetLatestHeight()) + cs := path.EndpointA.GetConsensusState(path.EndpointA.GetClientLatestHeight()) var err error expConsensusState, err = types.PackConsensusState(cs) @@ -259,7 +259,7 @@ func (suite *KeeperTestSuite) TestQueryConsensusState() { func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - height := path.EndpointA.GetClientState().GetLatestHeight() + height := path.EndpointA.GetClientLatestHeight() cs := path.EndpointA.GetConsensusState(height) var err error @@ -344,22 +344,22 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - height1 := path.EndpointA.GetClientState().GetLatestHeight().(types.Height) + height1 := path.EndpointA.GetClientLatestHeight() expConsensusStates = append( expConsensusStates, types.NewConsensusStateWithHeight( - height1, + height1.(types.Height), path.EndpointA.GetConsensusState(height1), )) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - height2 := path.EndpointA.GetClientState().GetLatestHeight().(types.Height) + height2 := path.EndpointA.GetClientLatestHeight() expConsensusStates = append( expConsensusStates, types.NewConsensusStateWithHeight( - height2, + height2.(types.Height), path.EndpointA.GetConsensusState(height2), )) @@ -449,12 +449,12 @@ func (suite *KeeperTestSuite) TestQueryConsensusStateHeights() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - expConsensusStateHeights = append(expConsensusStateHeights, path.EndpointA.GetClientState().GetLatestHeight().(types.Height)) + expConsensusStateHeights = append(expConsensusStateHeights, path.EndpointA.GetClientLatestHeight().(types.Height)) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - expConsensusStateHeights = append(expConsensusStateHeights, path.EndpointA.GetClientState().GetLatestHeight().(types.Height)) + expConsensusStateHeights = append(expConsensusStateHeights, path.EndpointA.GetClientLatestHeight().(types.Height)) req = &types.QueryConsensusStateHeightsRequest{ ClientId: path.EndpointA.ClientID, diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index d1ac7d45c24..4ae8d29af10 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -64,22 +64,22 @@ func (k Keeper) GetRouter() *types.Router { // CreateLocalhostClient initialises the 09-localhost client state and sets it in state. func (k Keeper) CreateLocalhostClient(ctx sdk.Context) error { - lightClientModule, found := k.router.GetRoute(exported.LocalhostClientID) + clientModule, found := k.router.GetRoute(exported.LocalhostClientID) if !found { return errorsmod.Wrap(types.ErrRouteNotFound, exported.LocalhostClientID) } - return lightClientModule.Initialize(ctx, exported.LocalhostClientID, nil, nil) + return clientModule.Initialize(ctx, exported.LocalhostClientID, nil, 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 { - lightClientModule, found := k.router.GetRoute(exported.LocalhostClientID) + clientModule, found := k.router.GetRoute(exported.LocalhostClientID) if !found { panic(errorsmod.Wrap(types.ErrRouteNotFound, exported.LocalhostClientID)) } - return lightClientModule.UpdateState(ctx, exported.LocalhostClientID, nil) + return clientModule.UpdateState(ctx, exported.LocalhostClientID, nil) } // GenerateClientIdentifier returns the next client identifier. @@ -290,11 +290,12 @@ func (k Keeper) HasClientConsensusState(ctx sdk.Context, clientID string, height // GetLatestClientConsensusState gets the latest ConsensusState stored for a given client func (k Keeper) GetLatestClientConsensusState(ctx sdk.Context, clientID string) (exported.ConsensusState, bool) { - clientState, ok := k.GetClientState(ctx, clientID) - if !ok { + clientModule, found := k.router.GetRoute(clientID) + if !found { return nil, false } - return k.GetClientConsensusState(ctx, clientID, clientState.GetLatestHeight()) + + return k.GetClientConsensusState(ctx, clientID, clientModule.LatestHeight(ctx, clientID)) } // GetSelfConsensusState introspects the (self) past historical info at a given height @@ -455,7 +456,7 @@ func (k Keeper) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore return prefix.NewStore(ctx.KVStore(k.storeKey), clientPrefix) } -// GetClientStatus returns the status for a given clientState. If the client type is not in the allowed +// GetClientStatus returns the status for a client state given a client identifier. If the client type is not in the allowed // clients param field, Unauthorized is returned, otherwise the client state status is returned. func (k Keeper) GetClientStatus(ctx sdk.Context, clientID string) exported.Status { clientType, _, err := types.ParseClientIdentifier(clientID) @@ -467,12 +468,32 @@ func (k Keeper) GetClientStatus(ctx sdk.Context, clientID string) exported.Statu return exported.Unauthorized } - lightClientModule, found := k.router.GetRoute(clientID) + clientModule, found := k.router.GetRoute(clientID) if !found { return exported.Unauthorized } - return lightClientModule.Status(ctx, clientID) + return clientModule.Status(ctx, clientID) +} + +// GetLatestHeight returns the latest height of a client state for a given client identifier. If the client type is not in the allowed +// clients param field, a zero value height is returned, otherwise the client state latest height is returned. +func (k Keeper) GetLatestHeight(ctx sdk.Context, clientID string) types.Height { + clientType, _, err := types.ParseClientIdentifier(clientID) + if err != nil { + return types.ZeroHeight() + } + + if !k.GetParams(ctx).IsAllowedClient(clientType) { + return types.ZeroHeight() + } + + clientModule, found := k.router.GetRoute(clientID) + if !found { + return types.ZeroHeight() + } + + return clientModule.LatestHeight(ctx, clientID).(types.Height) } // GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. @@ -487,12 +508,12 @@ func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, clientID string, height ex return 0, errorsmod.Wrapf(types.ErrInvalidClientType, "client state type %s is not registered in the allowlist", clientType) } - lightClientModule, found := k.router.GetRoute(clientID) + clientModule, found := k.router.GetRoute(clientID) if !found { return 0, errorsmod.Wrap(types.ErrRouteNotFound, clientType) } - return lightClientModule.TimestampAtHeight(ctx, clientID, height) + return clientModule.TimestampAtHeight(ctx, clientID, height) } // GetParams returns the total set of ibc-client parameters. diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 2112dd76231..034500b55ac 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -229,7 +229,7 @@ func (suite *KeeperTestSuite) TestValidateSelfClient() { } } -func (suite KeeperTestSuite) TestGetAllGenesisClients() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllGenesisClients() { clientIDs := []string{ exported.LocalhostClientID, testClientID2, testClientID3, testClientID, } @@ -252,7 +252,7 @@ func (suite KeeperTestSuite) TestGetAllGenesisClients() { //nolint:govet // this suite.Require().Equal(expGenClients.Sort(), genClients) } -func (suite KeeperTestSuite) TestGetAllGenesisMetadata() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllGenesisMetadata() { clientA, clientB := "07-tendermint-1", "clientB" // create some starting state @@ -308,7 +308,7 @@ func (suite KeeperTestSuite) TestGetAllGenesisMetadata() { //nolint:govet // thi }) } -func (suite KeeperTestSuite) TestGetConsensusState() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetConsensusState() { suite.ctx = suite.ctx.WithBlockHeight(10) cases := []struct { name string @@ -336,12 +336,11 @@ func (suite KeeperTestSuite) TestGetConsensusState() { //nolint:govet // this is // 2 clients in total are created on chainA. The first client is updated so it contains an initial consensus state // and a consensus state at the update height. -func (suite KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllConsensusStates() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - clientState := path.EndpointA.GetClientState() - expConsensusHeight0 := clientState.GetLatestHeight() + expConsensusHeight0 := path.EndpointA.GetClientLatestHeight() consensusState0, ok := suite.chainA.GetConsensusState(path.EndpointA.ClientID, expConsensusHeight0) suite.Require().True(ok) @@ -349,8 +348,7 @@ func (suite KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // thi err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - clientState = path.EndpointA.GetClientState() - expConsensusHeight1 := clientState.GetLatestHeight() + expConsensusHeight1 := path.EndpointA.GetClientLatestHeight() suite.Require().True(expConsensusHeight1.GT(expConsensusHeight0)) consensusState1, ok := suite.chainA.GetConsensusState(path.EndpointA.ClientID, expConsensusHeight1) suite.Require().True(ok) @@ -363,9 +361,8 @@ func (suite KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // thi // create second client on chainA path2 := ibctesting.NewPath(suite.chainA, suite.chainB) path2.SetupClients() - clientState = path2.EndpointA.GetClientState() - expConsensusHeight2 := clientState.GetLatestHeight() + expConsensusHeight2 := path2.EndpointA.GetClientLatestHeight() consensusState2, ok := suite.chainA.GetConsensusState(path2.EndpointA.ClientID, expConsensusHeight2) suite.Require().True(ok) @@ -385,7 +382,7 @@ func (suite KeeperTestSuite) TestGetAllConsensusStates() { //nolint:govet // thi suite.Require().Equal(expConsensusStates, consStates, "%s \n\n%s", expConsensusStates, consStates) } -func (suite KeeperTestSuite) TestIterateClientStates() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestIterateClientStates() { paths := []*ibctesting.Path{ ibctesting.NewPath(suite.chainA, suite.chainB), ibctesting.NewPath(suite.chainA, suite.chainB), diff --git a/modules/core/02-client/types/client_test.go b/modules/core/02-client/types/client_test.go index a983672d386..960f8e785e9 100644 --- a/modules/core/02-client/types/client_test.go +++ b/modules/core/02-client/types/client_test.go @@ -26,11 +26,12 @@ func (suite *TypesTestSuite) TestMarshalConsensusStateWithHeight() { "tendermint client", func() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) - consensusState, ok := suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientState.GetLatestHeight()) + + latestHeight := path.EndpointA.GetClientLatestHeight().(types.Height) + consensusState, ok := suite.chainA.GetConsensusState(path.EndpointA.ClientID, latestHeight) suite.Require().True(ok) - cswh = types.NewConsensusStateWithHeight(clientState.GetLatestHeight().(types.Height), consensusState) + cswh = types.NewConsensusStateWithHeight(latestHeight, consensusState) }, }, } diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index 405c12a68ff..cfb37584ca1 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -25,9 +25,6 @@ func NewRouter(key storetypes.StoreKey) *Router { // AddRoute adds LightClientModule for a given module name. It returns the Router // so AddRoute calls can be linked. It will panic if the Router is sealed. func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule) *Router { - // if !sdk.IsAlphaNumeric(module) { - // panic(errors.New("route expressions can only contain alphanumeric characters")) - // } if rtr.HasRoute(clientType) { panic(fmt.Errorf("route %s has already been registered", module)) } diff --git a/modules/core/02-client/types/store.go b/modules/core/02-client/types/store.go index 825be33ad27..5d98cbe6901 100644 --- a/modules/core/02-client/types/store.go +++ b/modules/core/02-client/types/store.go @@ -14,10 +14,12 @@ import ( var _ exported.ClientStoreProvider = (*storeProvider)(nil) +// storeProvider implements the api.ClientStoreProvider interface and encapsulates the IBC core store key. type storeProvider struct { storeKey storetypes.StoreKey } +// NewStoreProvider creates and returns a new ClientStoreProvider. func NewStoreProvider(storeKey storetypes.StoreKey) exported.ClientStoreProvider { return storeProvider{ storeKey: storeKey, diff --git a/modules/core/03-connection/keeper/grpc_query_test.go b/modules/core/03-connection/keeper/grpc_query_test.go index f44c89b38f5..694ca794379 100644 --- a/modules/core/03-connection/keeper/grpc_query_test.go +++ b/modules/core/03-connection/keeper/grpc_query_test.go @@ -412,15 +412,15 @@ func (suite *KeeperTestSuite) TestQueryConnectionConsensusState() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupConnections() - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) - expConsensusState, _ = suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientState.GetLatestHeight()) + clientHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) + expConsensusState, _ = suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientHeight) suite.Require().NotNil(expConsensusState) expClientID = path.EndpointA.ClientID req = &types.QueryConnectionConsensusStateRequest{ ConnectionId: path.EndpointA.ConnectionID, - RevisionNumber: clientState.GetLatestHeight().GetRevisionNumber(), - RevisionHeight: clientState.GetLatestHeight().GetRevisionHeight(), + RevisionNumber: clientHeight.GetRevisionNumber(), + RevisionHeight: clientHeight.GetRevisionHeight(), } }, true, diff --git a/modules/core/03-connection/keeper/handshake_test.go b/modules/core/03-connection/keeper/handshake_test.go index 880ae768ab0..8636ed5f591 100644 --- a/modules/core/03-connection/keeper/handshake_test.go +++ b/modules/core/03-connection/keeper/handshake_test.go @@ -211,7 +211,7 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { suite.Require().True(ok) tmConsState.Timestamp = time.Now() - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, counterpartyClient.GetLatestHeight(), tmConsState) + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainA.GetContext(), path.EndpointA.ClientID, path.EndpointA.GetClientLatestHeight(), tmConsState) err := path.EndpointA.ConnOpenInit() suite.Require().NoError(err) @@ -242,8 +242,9 @@ func (suite *KeeperTestSuite) TestConnOpenTry() { if consensusHeight.IsZero() { // retrieve consensus state height to provide proof for - consensusHeight = counterpartyClient.GetLatestHeight() + consensusHeight = path.EndpointA.GetClientLatestHeight() } + consensusKey := host.FullConsensusStateKey(path.EndpointA.ClientID, consensusHeight) consensusProof, _ := suite.chainA.QueryProof(consensusKey) @@ -461,7 +462,7 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { suite.Require().True(ok) tmConsState.Timestamp = tmConsState.Timestamp.Add(time.Second) - suite.chainB.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID, counterpartyClient.GetLatestHeight(), tmConsState) + suite.chainB.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID, path.EndpointB.GetClientLatestHeight(), tmConsState) err = path.EndpointB.ConnOpenTry() suite.Require().NoError(err) @@ -488,8 +489,7 @@ func (suite *KeeperTestSuite) TestConnOpenAck() { if consensusHeight.IsZero() { // retrieve consensus state height to provide proof for - clientState := suite.chainB.GetClientState(path.EndpointB.ClientID) - consensusHeight = clientState.GetLatestHeight() + consensusHeight = path.EndpointB.GetClientLatestHeight() } consensusKey := host.FullConsensusStateKey(path.EndpointB.ClientID, consensusHeight) consensusProof, _ := suite.chainB.QueryProof(consensusKey) diff --git a/modules/core/03-connection/keeper/keeper_test.go b/modules/core/03-connection/keeper/keeper_test.go index 2069f611e43..7f2137e1e78 100644 --- a/modules/core/03-connection/keeper/keeper_test.go +++ b/modules/core/03-connection/keeper/keeper_test.go @@ -60,7 +60,7 @@ func (suite *KeeperTestSuite) TestSetAndGetClientConnectionPaths() { } // create 2 connections: A0 - B0, A1 - B1 -func (suite KeeperTestSuite) TestGetAllConnections() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllConnections() { path1 := ibctesting.NewPath(suite.chainA, suite.chainB) path1.SetupConnections() @@ -92,7 +92,7 @@ func (suite KeeperTestSuite) TestGetAllConnections() { //nolint:govet // this is // the test creates 2 clients path.EndpointA.ClientID0 and path.EndpointA.ClientID1. path.EndpointA.ClientID0 has a single // connection and path.EndpointA.ClientID1 has 2 connections. -func (suite KeeperTestSuite) TestGetAllClientConnectionPaths() { //nolint:govet // this is a test, we are okay with copying locks +func (suite *KeeperTestSuite) TestGetAllClientConnectionPaths() { path1 := ibctesting.NewPath(suite.chainA, suite.chainB) path2 := ibctesting.NewPath(suite.chainA, suite.chainB) path1.SetupConnections() diff --git a/modules/core/03-connection/keeper/verify.go b/modules/core/03-connection/keeper/verify.go index 61c99dc21f2..8470dcf97d3 100644 --- a/modules/core/03-connection/keeper/verify.go +++ b/modules/core/03-connection/keeper/verify.go @@ -29,7 +29,7 @@ func (k Keeper) VerifyClientState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -45,7 +45,7 @@ func (k Keeper) VerifyClientState( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, @@ -71,7 +71,7 @@ func (k Keeper) VerifyClientConsensusState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -87,7 +87,7 @@ func (k Keeper) VerifyClientConsensusState( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, @@ -113,7 +113,7 @@ func (k Keeper) VerifyConnectionState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -129,7 +129,7 @@ func (k Keeper) VerifyConnectionState( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, @@ -156,7 +156,7 @@ func (k Keeper) VerifyChannelState( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -172,7 +172,7 @@ func (k Keeper) VerifyChannelState( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, @@ -200,7 +200,7 @@ func (k Keeper) VerifyPacketCommitment( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -215,7 +215,7 @@ func (k Keeper) VerifyPacketCommitment( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, commitmentBytes, ); err != nil { return errorsmod.Wrapf(err, "failed packet commitment verification for client (%s)", clientID) @@ -241,7 +241,7 @@ func (k Keeper) VerifyPacketAcknowledgement( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -256,7 +256,7 @@ func (k Keeper) VerifyPacketAcknowledgement( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, channeltypes.CommitAcknowledgement(acknowledgement), ); err != nil { @@ -288,7 +288,7 @@ func (k Keeper) VerifyPacketReceiptAbsence( return err } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientType) } @@ -303,7 +303,7 @@ func (k Keeper) VerifyPacketReceiptAbsence( return err } - if err := lightClientModule.VerifyNonMembership( + if err := clientModule.VerifyNonMembership( ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, ); err != nil { return errorsmod.Wrapf(err, "failed packet receipt absence verification for client (%s)", clientID) @@ -328,7 +328,7 @@ func (k Keeper) VerifyNextSequenceRecv( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -343,7 +343,7 @@ func (k Keeper) VerifyNextSequenceRecv( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, timeDelay, blockDelay, proof, merklePath, sdk.Uint64ToBigEndian(nextSequenceRecv), @@ -369,7 +369,7 @@ func (k Keeper) VerifyChannelUpgradeError( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -385,7 +385,7 @@ func (k Keeper) VerifyChannelUpgradeError( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, height, 0, 0, // skip delay period checks for non-packet processing verification proof, merklePath, bz, @@ -411,7 +411,7 @@ func (k Keeper) VerifyChannelUpgrade( return errorsmod.Wrapf(clienttypes.ErrClientNotActive, "client (%s) status is %s", clientID, status) } - lightClientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) + clientModule, found := k.clientKeeper.GetRouter().GetRoute(clientID) if !found { return errorsmod.Wrap(clienttypes.ErrRouteNotFound, clientID) } @@ -427,7 +427,7 @@ func (k Keeper) VerifyChannelUpgrade( return err } - if err := lightClientModule.VerifyMembership( + if err := clientModule.VerifyMembership( ctx, clientID, proofHeight, 0, 0, // skip delay period checks for non-packet processing verification upgradeProof, merklePath, bz, diff --git a/modules/core/03-connection/keeper/verify_test.go b/modules/core/03-connection/keeper/verify_test.go index 5b91bc21e9e..7867d2271d3 100644 --- a/modules/core/03-connection/keeper/verify_test.go +++ b/modules/core/03-connection/keeper/verify_test.go @@ -99,8 +99,6 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { heightDiff = 5 }, false}, {"verification failed", func() { - clientState := suite.chainB.GetClientState(path.EndpointB.ClientID) - // give chainB wrong consensus state for chainA consState, found := suite.chainB.App.GetIBCKeeper().ClientKeeper.GetLatestClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID) suite.Require().True(found) @@ -109,7 +107,7 @@ func (suite *KeeperTestSuite) TestVerifyClientConsensusState() { suite.Require().True(ok) tmConsState.Timestamp = time.Now() - suite.chainB.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID, clientState.GetLatestHeight(), tmConsState) + suite.chainB.App.GetIBCKeeper().ClientKeeper.SetClientConsensusState(suite.chainB.GetContext(), path.EndpointB.ClientID, path.EndpointB.GetClientLatestHeight(), tmConsState) suite.coordinator.CommitBlock(suite.chainB) }, false}, diff --git a/modules/core/04-channel/client/utils/utils.go b/modules/core/04-channel/client/utils/utils.go index c5118aa0011..a6ef2505ed5 100644 --- a/modules/core/04-channel/client/utils/utils.go +++ b/modules/core/04-channel/client/utils/utils.go @@ -16,6 +16,7 @@ import ( ibcclient "github.com/cosmos/ibc-go/v8/modules/core/client" ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ) // QueryChannel returns a channel end. @@ -127,6 +128,8 @@ func QueryChannelConsensusState( // QueryLatestConsensusState uses the channel Querier to return the // latest ConsensusState given the source port ID and source channel ID. +// Deprecated: This function will be removed in a later release of ibc-go. +// NOTE: This function only supports querying latest consensus state of 07-tendermint client state implementations. func QueryLatestConsensusState( clientCtx client.Context, portID, channelID string, ) (exported.ConsensusState, clienttypes.Height, clienttypes.Height, error) { @@ -140,12 +143,13 @@ func QueryLatestConsensusState( return nil, clienttypes.Height{}, clienttypes.Height{}, err } - clientHeight, ok := clientState.GetLatestHeight().(clienttypes.Height) + tmClientState, ok := clientState.(*ibctm.ClientState) if !ok { - return nil, clienttypes.Height{}, clienttypes.Height{}, errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "invalid height type. expected type: %T, got: %T", - clienttypes.Height{}, clientHeight) + return nil, clienttypes.Height{}, clienttypes.Height{}, errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected type: %T, got: %T", + ibctm.ClientState{}, clientState) } - res, err := QueryChannelConsensusState(clientCtx, portID, channelID, clientHeight, false) + + res, err := QueryChannelConsensusState(clientCtx, portID, channelID, tmClientState.LatestHeight, false) if err != nil { return nil, clienttypes.Height{}, clienttypes.Height{}, err } @@ -155,7 +159,7 @@ func QueryLatestConsensusState( return nil, clienttypes.Height{}, clienttypes.Height{}, err } - return consensusState, clientHeight, res.ProofHeight, nil + return consensusState, tmClientState.LatestHeight, res.ProofHeight, nil } // QueryNextSequenceReceive returns the next sequence receive. diff --git a/modules/core/04-channel/keeper/grpc_query_test.go b/modules/core/04-channel/keeper/grpc_query_test.go index ba2f3126b30..8dd89e1384e 100644 --- a/modules/core/04-channel/keeper/grpc_query_test.go +++ b/modules/core/04-channel/keeper/grpc_query_test.go @@ -557,16 +557,15 @@ func (suite *KeeperTestSuite) TestQueryChannelConsensusState() { err := path.EndpointA.ChanOpenInit() suite.Require().NoError(err) - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) - expConsensusState, _ = suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientState.GetLatestHeight()) + expConsensusState, _ = suite.chainA.GetConsensusState(path.EndpointA.ClientID, path.EndpointA.GetClientLatestHeight()) suite.Require().NotNil(expConsensusState) expClientID = path.EndpointA.ClientID req = &types.QueryChannelConsensusStateRequest{ PortId: path.EndpointA.ChannelConfig.PortID, ChannelId: path.EndpointA.ChannelID, - RevisionNumber: clientState.GetLatestHeight().GetRevisionNumber(), - RevisionHeight: clientState.GetLatestHeight().GetRevisionHeight(), + RevisionNumber: path.EndpointA.GetClientLatestHeight().GetRevisionNumber(), + RevisionHeight: path.EndpointA.GetClientLatestHeight().GetRevisionHeight(), } }, true, diff --git a/modules/core/04-channel/keeper/packet.go b/modules/core/04-channel/keeper/packet.go index c19360bc675..e0fea9b3921 100644 --- a/modules/core/04-channel/keeper/packet.go +++ b/modules/core/04-channel/keeper/packet.go @@ -63,17 +63,12 @@ func (k Keeper) SendPacket( return 0, errorsmod.Wrap(connectiontypes.ErrConnectionNotFound, channel.ConnectionHops[0]) } - clientState, found := k.clientKeeper.GetClientState(ctx, connectionEnd.ClientId) - if !found { - return 0, clienttypes.ErrClientNotFound - } - // prevent accidental sends with clients that cannot be updated if status := k.clientKeeper.GetClientStatus(ctx, connectionEnd.ClientId); status != exported.Active { return 0, errorsmod.Wrapf(clienttypes.ErrClientNotActive, "cannot send packet using client (%s) with status %s", connectionEnd.ClientId, status) } - latestHeight := clientState.GetLatestHeight() + latestHeight := k.clientKeeper.GetLatestHeight(ctx, connectionEnd.ClientId) latestTimestamp, err := k.clientKeeper.GetTimestampAtHeight(ctx, connectionEnd.ClientId, latestHeight) if err != nil { return 0, err @@ -81,8 +76,8 @@ func (k Keeper) SendPacket( // check if packet is timed out on the receiving chain timeout := types.NewTimeout(packet.GetTimeoutHeight().(clienttypes.Height), packet.GetTimeoutTimestamp()) - if timeout.Elapsed(latestHeight.(clienttypes.Height), latestTimestamp) { - return 0, errorsmod.Wrap(timeout.ErrTimeoutElapsed(latestHeight.(clienttypes.Height), latestTimestamp), "invalid packet timeout") + if timeout.Elapsed(latestHeight, latestTimestamp) { + return 0, errorsmod.Wrap(timeout.ErrTimeoutElapsed(latestHeight, latestTimestamp), "invalid packet timeout") } commitment := types.CommitPacket(k.cdc, packet) diff --git a/modules/core/04-channel/keeper/packet_test.go b/modules/core/04-channel/keeper/packet_test.go index b62d75e511f..4ab703036e7 100644 --- a/modules/core/04-channel/keeper/packet_test.go +++ b/modules/core/04-channel/keeper/packet_test.go @@ -150,19 +150,15 @@ func (suite *KeeperTestSuite) TestSendPacket() { path.Setup() sourceChannel = path.EndpointA.ChannelID - // use client state latest height for timeout - clientState := path.EndpointA.GetClientState() - timeoutHeight = clientState.GetLatestHeight().(clienttypes.Height) + timeoutHeight = path.EndpointA.GetClientLatestHeight().(clienttypes.Height) channelCap = suite.chainA.GetChannelCapability(path.EndpointA.ChannelConfig.PortID, path.EndpointA.ChannelID) }, false}, {"timeout timestamp passed", func() { path.Setup() sourceChannel = path.EndpointA.ChannelID - // use latest time on client state - clientState := path.EndpointA.GetClientState() connection := path.EndpointA.GetConnection() - timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.ClientId, clientState.GetLatestHeight()) + timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.ClientId, path.EndpointA.GetClientLatestHeight()) suite.Require().NoError(err) timeoutHeight = disabledTimeoutHeight @@ -178,9 +174,8 @@ func (suite *KeeperTestSuite) TestSendPacket() { path.EndpointA.UpdateConnection(func(c *connectiontypes.ConnectionEnd) { c.ClientId = path.EndpointA.ClientID }) - clientState := path.EndpointA.GetClientState() connection := path.EndpointA.GetConnection() - timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.ClientId, clientState.GetLatestHeight()) + timestamp, err := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetTimestampAtHeight(suite.chainA.GetContext(), connection.ClientId, path.EndpointA.GetClientLatestHeight()) suite.Require().NoError(err) sourceChannel = path.EndpointA.ChannelID diff --git a/modules/core/04-channel/types/expected_keepers.go b/modules/core/04-channel/types/expected_keepers.go index 8c3ea014297..b8dfea0d751 100644 --- a/modules/core/04-channel/types/expected_keepers.go +++ b/modules/core/04-channel/types/expected_keepers.go @@ -6,16 +6,18 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" + clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" connectiontypes "github.com/cosmos/ibc-go/v8/modules/core/03-connection/types" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) // ClientKeeper expected account IBC client keeper type ClientKeeper interface { + ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore GetClientStatus(ctx sdk.Context, clientID string) exported.Status GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) - ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore + GetLatestHeight(ctx sdk.Context, clientID string) clienttypes.Height GetTimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) } diff --git a/modules/core/ante/ante_test.go b/modules/core/ante/ante_test.go index 70dfafe2b32..8f5071e13fe 100644 --- a/modules/core/ante/ante_test.go +++ b/modules/core/ante/ante_test.go @@ -159,8 +159,8 @@ func (suite *AnteTestSuite) createUpdateClientMessage() sdk.Msg { switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: - trustedHeight := endpoint.GetClientState().GetLatestHeight().(clienttypes.Height) - header, _ = endpoint.Counterparty.Chain.IBCClientHeader(endpoint.Counterparty.Chain.LatestCommittedHeader, trustedHeight) + trustedHeight := endpoint.GetClientLatestHeight() + header, _ = endpoint.Counterparty.Chain.IBCClientHeader(endpoint.Counterparty.Chain.LatestCommittedHeader, trustedHeight.(clienttypes.Height)) default: } diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 93a7f039625..6c12d00a818 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -103,6 +103,9 @@ type LightClientModule interface { // Status must return the status of the client. Only Active clients are allowed to process packets. Status(ctx sdk.Context, clientID string) Status + // LatestHeight returns the latest height of the client. If no client is present for the provided client identifier a zero value height may be returned. + LatestHeight(ctx sdk.Context, clientID string) Height + // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. TimestampAtHeight( ctx sdk.Context, @@ -137,7 +140,6 @@ type ClientState interface { proto.Message ClientType() string - GetLatestHeight() Height Validate() error // Upgrade functions diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 1c865aaf274..2749af00fd9 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -819,11 +819,9 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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) - - upgradeClientProof, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + latestHeight := path.EndpointA.GetClientLatestHeight() + upgradeClientProof, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), latestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ := suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), latestHeight.GetRevisionHeight()) msg, err = clienttypes.NewMsgUpgradeClient(path.EndpointA.ClientID, upgradedClient, upgradedConsState, upgradeClientProof, upgradedConsensusStateProof, suite.chainA.SenderAccount.GetAddress().String()) @@ -878,7 +876,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { newChainID, err = clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) suite.Require().NoError(err) - newClientHeight = clienttypes.NewHeight(revisionNumber+1, clientState.GetLatestHeight().GetRevisionHeight()+1) + newClientHeight = clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1) tc.setup() @@ -897,7 +895,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { clienttypes.EventTypeUpgradeClient, sdk.NewAttribute(clienttypes.AttributeKeyClientID, ibctesting.FirstClientID), sdk.NewAttribute(clienttypes.AttributeKeyClientType, path.EndpointA.GetClientState().ClientType()), - sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, path.EndpointA.GetClientState().GetLatestHeight().String()), + sdk.NewAttribute(clienttypes.AttributeKeyConsensusHeight, path.EndpointA.GetClientLatestHeight().String()), ), }.ToABCIEvents() diff --git a/modules/light-clients/06-solomachine/client_state.go b/modules/light-clients/06-solomachine/client_state.go index 88f41ae07a0..6d57baa497e 100644 --- a/modules/light-clients/06-solomachine/client_state.go +++ b/modules/light-clients/06-solomachine/client_state.go @@ -34,13 +34,6 @@ func (ClientState) ClientType() string { return exported.Solomachine } -// GetLatestHeight returns the latest sequence number. -// Return exported.Height to satisfy ClientState interface -// Revision number is always 0 for a solo-machine. -func (cs ClientState) GetLatestHeight() exported.Height { - return clienttypes.NewHeight(0, cs.Sequence) -} - // GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. func (cs ClientState) GetTimestampAtHeight( _ sdk.Context, @@ -239,7 +232,7 @@ func produceVerificationArgs( return nil, nil, 0, 0, errorsmod.Wrapf(ErrInvalidProof, "the consensus state timestamp is greater than the signature timestamp (%d >= %d)", cs.ConsensusState.GetTimestamp(), timestamp) } - sequence := cs.GetLatestHeight().GetRevisionHeight() + sequence := cs.Sequence publicKey, err := cs.ConsensusState.GetPubKey() if err != nil { return nil, nil, 0, 0, err diff --git a/modules/light-clients/06-solomachine/client_state_test.go b/modules/light-clients/06-solomachine/client_state_test.go index 0f94dcffa54..5b982aaa407 100644 --- a/modules/light-clients/06-solomachine/client_state_test.go +++ b/modules/light-clients/06-solomachine/client_state_test.go @@ -850,7 +850,7 @@ func (suite *SoloMachineTestSuite) TestGetTimestampAtHeight() { { name: "get timestamp at height exists", clientState: suite.solomachine.ClientState(), - height: suite.solomachine.ClientState().GetLatestHeight(), + height: clienttypes.NewHeight(0, suite.solomachine.ClientState().Sequence), expValue: suite.solomachine.ClientState().ConsensusState.Timestamp, expPass: true, }, diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 7e294693067..b8cfb28b62d 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -174,6 +174,22 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S return clientState.Status(ctx, clientStore, lcm.cdc) } +// LatestHeight returns the latest height for the client state for the given client identifier. +// If no client is present for the provided client identifier a zero value height is returned. +// NOTE: RevisionNumber is always 0 for solomachine client heights. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. +func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + + clientState, found := getClientState(clientStore, lcm.cdc) + if !found { + return clienttypes.ZeroHeight() + } + + return clienttypes.NewHeight(0, clientState.Sequence) +} + // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. @@ -213,10 +229,6 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) } - if clientState.GetLatestHeight().GTE(substituteClient.GetLatestHeight()) { - return errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", clientState.GetLatestHeight(), substituteClient.GetLatestHeight()) - } - return clientState.CheckSubstituteAndUpdateState(ctx, lcm.cdc, clientStore, substituteClientStore, substituteClient) } diff --git a/modules/light-clients/06-solomachine/light_client_module_test.go b/modules/light-clients/06-solomachine/light_client_module_test.go index dbe423734ee..7127199f837 100644 --- a/modules/light-clients/06-solomachine/light_client_module_test.go +++ b/modules/light-clients/06-solomachine/light_client_module_test.go @@ -16,7 +16,7 @@ const ( func (suite *SoloMachineTestSuite) TestRecoverClient() { var ( subjectClientID, substituteClientID string - subjectClientState, substituteClientState exported.ClientState + subjectClientState, substituteClientState *solomachine.ClientState ) testCases := []struct { @@ -58,26 +58,6 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { }, clienttypes.ErrClientNotFound, }, - { - "subject and substitute have equal latest height", - func() { - smClientState, ok := subjectClientState.(*solomachine.ClientState) - suite.Require().True(ok) - smClientState.Sequence = substituteClientState.GetLatestHeight().GetRevisionHeight() - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, smClientState) - }, - clienttypes.ErrInvalidHeight, - }, - { - "subject height is greater than substitute height", - func() { - smClientState, ok := subjectClientState.(*solomachine.ClientState) - suite.Require().True(ok) - smClientState.Sequence = substituteClientState.GetLatestHeight().GetRevisionHeight() + 1 - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, smClientState) - }, - clienttypes.ErrInvalidHeight, - }, } for _, tc := range testCases { @@ -101,10 +81,8 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { bz := clienttypes.MustMarshalClientState(cdc, substituteClientState) clientStore.Set(host.ClientStateKey(), bz) - smClientState, ok := subjectClientState.(*solomachine.ClientState) - suite.Require().True(ok) - smClientState.IsFrozen = true - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(ctx, subjectClientID, smClientState) + subjectClientState.IsFrozen = true + suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(ctx, subjectClientID, subjectClientState) lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetRouter().GetRoute(subjectClientID) suite.Require().True(found) @@ -122,8 +100,8 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { bz = clientStore.Get(host.ClientStateKey()) smClientState := clienttypes.MustUnmarshalClientState(cdc, bz).(*solomachine.ClientState) - suite.Require().Equal(substituteClientState.(*solomachine.ClientState).ConsensusState, smClientState.ConsensusState) - suite.Require().Equal(substituteClientState.(*solomachine.ClientState).Sequence, smClientState.Sequence) + suite.Require().Equal(substituteClientState.ConsensusState, smClientState.ConsensusState) + suite.Require().Equal(substituteClientState.Sequence, smClientState.Sequence) suite.Require().Equal(exported.Active, smClientState.Status(ctx, clientStore, cdc)) } else { suite.Require().Error(err) diff --git a/modules/light-clients/06-solomachine/solomachine_test.go b/modules/light-clients/06-solomachine/solomachine_test.go index a14da421a1b..b5b21c894e2 100644 --- a/modules/light-clients/06-solomachine/solomachine_test.go +++ b/modules/light-clients/06-solomachine/solomachine_test.go @@ -144,7 +144,9 @@ func (suite *SoloMachineTestSuite) GetSequenceFromStore() uint64 { var clientState exported.ClientState err := suite.chainA.Codec.UnmarshalInterface(bz, &clientState) suite.Require().NoError(err) - return clientState.GetLatestHeight().GetRevisionHeight() + + smClientState := clientState.(*solomachine.ClientState) + return smClientState.Sequence } func (suite *SoloMachineTestSuite) GetInvalidProof() []byte { diff --git a/modules/light-clients/07-tendermint/client_state.go b/modules/light-clients/07-tendermint/client_state.go index 826b7554a0b..d0a1d10e30e 100644 --- a/modules/light-clients/07-tendermint/client_state.go +++ b/modules/light-clients/07-tendermint/client_state.go @@ -53,11 +53,6 @@ func (ClientState) ClientType() string { return exported.Tendermint } -// GetLatestHeight returns latest block height. -func (cs ClientState) GetLatestHeight() exported.Height { - return cs.LatestHeight -} - // GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. func (ClientState) GetTimestampAtHeight( ctx sdk.Context, @@ -91,7 +86,7 @@ func (cs ClientState) Status( } // get latest consensus state from clientStore to check for expiry - consState, found := GetConsensusState(clientStore, cdc, cs.GetLatestHeight()) + consState, found := GetConsensusState(clientStore, cdc, cs.LatestHeight) if !found { // if the client state does not have an associated consensus state for its latest height // then it must be expired @@ -199,8 +194,8 @@ func (cs ClientState) Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientS } setClientState(clientStore, cdc, &cs) - setConsensusState(clientStore, cdc, consensusState, cs.GetLatestHeight()) - setConsensusMetadata(ctx, clientStore, cs.GetLatestHeight()) + setConsensusState(clientStore, cdc, consensusState, cs.LatestHeight) + setConsensusMetadata(ctx, clientStore, cs.LatestHeight) return nil } @@ -219,10 +214,10 @@ func (cs ClientState) VerifyMembership( path exported.Path, value []byte, ) error { - if cs.GetLatestHeight().LT(height) { + if cs.LatestHeight.LT(height) { return errorsmod.Wrapf( ibcerrors.ErrInvalidHeight, - "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.LatestHeight, height, ) } @@ -261,10 +256,10 @@ func (cs ClientState) VerifyNonMembership( proof []byte, path exported.Path, ) error { - if cs.GetLatestHeight().LT(height) { + if cs.LatestHeight.LT(height) { return errorsmod.Wrapf( ibcerrors.ErrInvalidHeight, - "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.LatestHeight, height, ) } diff --git a/modules/light-clients/07-tendermint/client_state_test.go b/modules/light-clients/07-tendermint/client_state_test.go index b0a81c69c8f..0fa2222de6e 100644 --- a/modules/light-clients/07-tendermint/client_state_test.go +++ b/modules/light-clients/07-tendermint/client_state_test.go @@ -91,8 +91,8 @@ func (suite *TendermintTestSuite) TestGetTimestampAtHeight() { { "failure: consensus state not found for height", func() { - clientState := path.EndpointA.GetClientState() - height = clientState.GetLatestHeight().Increment() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + height = clientState.LatestHeight.Increment() }, clienttypes.ErrConsensusStateNotFound, }, @@ -107,7 +107,7 @@ func (suite *TendermintTestSuite) TestGetTimestampAtHeight() { path.SetupClients() clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) - height = clientState.GetLatestHeight() + height = clientState.LatestHeight store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) @@ -323,14 +323,16 @@ func (suite *TendermintTestSuite) TestVerifyMembership() { }, { "successful ConsensusState verification", func() { - key := host.FullConsensusStateKey(testingpath.EndpointB.ClientID, testingpath.EndpointB.GetClientState().GetLatestHeight()) + latestHeight := testingpath.EndpointB.GetClientLatestHeight() + + key := host.FullConsensusStateKey(testingpath.EndpointB.ClientID, latestHeight) merklePath := commitmenttypes.NewMerklePath(string(key)) path, err = commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) suite.Require().NoError(err) proof, proofHeight = suite.chainB.QueryProof(key) - consensusState := testingpath.EndpointB.GetConsensusState(testingpath.EndpointB.GetClientState().GetLatestHeight()).(*ibctm.ConsensusState) + consensusState := testingpath.EndpointB.GetConsensusState(latestHeight).(*ibctm.ConsensusState) value, err = suite.chainB.Codec.MarshalInterface(consensusState) suite.Require().NoError(err) }, @@ -437,8 +439,7 @@ func (suite *TendermintTestSuite) TestVerifyMembership() { path, err = commitmenttypes.ApplyPrefix(commitmenttypes.NewMerklePrefix([]byte(transfertypes.StoreKey)), merklePath) suite.Require().NoError(err) - clientState := testingpath.EndpointA.GetClientState() - proof, proofHeight = suite.chainB.QueryProofForStore(transfertypes.StoreKey, key, int64(clientState.GetLatestHeight().GetRevisionHeight())) + proof, proofHeight = suite.chainB.QueryProofForStore(transfertypes.StoreKey, key, int64(testingpath.EndpointA.GetClientLatestHeight().GetRevisionHeight())) value = []byte(suite.chainB.GetSimApp().TransferKeeper.GetPort(suite.chainB.GetContext())) suite.Require().NoError(err) @@ -471,7 +472,7 @@ func (suite *TendermintTestSuite) TestVerifyMembership() { }, { "latest client height < height", func() { - proofHeight = testingpath.EndpointA.GetClientState().GetLatestHeight().Increment() + proofHeight = testingpath.EndpointA.GetClientLatestHeight().Increment() }, false, }, { @@ -581,7 +582,7 @@ func (suite *TendermintTestSuite) TestVerifyNonMembership() { }, { "successful ConsensusState verification of non membership", func() { - key := host.FullConsensusStateKey(invalidClientID, testingpath.EndpointB.GetClientState().GetLatestHeight()) + key := host.FullConsensusStateKey(invalidClientID, testingpath.EndpointB.GetClientLatestHeight()) merklePath := commitmenttypes.NewMerklePath(string(key)) path, err = commitmenttypes.ApplyPrefix(suite.chainB.GetPrefix(), merklePath) suite.Require().NoError(err) @@ -652,8 +653,7 @@ func (suite *TendermintTestSuite) TestVerifyNonMembership() { path, err = commitmenttypes.ApplyPrefix(commitmenttypes.NewMerklePrefix([]byte(transfertypes.StoreKey)), merklePath) suite.Require().NoError(err) - clientState := testingpath.EndpointA.GetClientState() - proof, proofHeight = suite.chainB.QueryProofForStore(transfertypes.StoreKey, key, int64(clientState.GetLatestHeight().GetRevisionHeight())) + proof, proofHeight = suite.chainB.QueryProofForStore(transfertypes.StoreKey, key, int64(testingpath.EndpointA.GetClientLatestHeight().GetRevisionHeight())) }, true, }, @@ -683,7 +683,7 @@ func (suite *TendermintTestSuite) TestVerifyNonMembership() { }, { "latest client height < height", func() { - proofHeight = testingpath.EndpointA.GetClientState().GetLatestHeight().Increment() + proofHeight = testingpath.EndpointA.GetClientLatestHeight().Increment() }, false, }, { diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 123d2b7d414..15baba26982 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -190,6 +190,21 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S return clientState.Status(ctx, clientStore, cdc) } +// LatestHeight returns the latest height for the client state for the given client identifier. +// If no client is present for the provided client identifier a zero value height is returned. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. +func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + + clientState, found := getClientState(clientStore, lcm.keeper.Codec()) + if !found { + return clienttypes.ZeroHeight() + } + + return clientState.LatestHeight +} + // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. @@ -237,10 +252,6 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) } - if clientState.GetLatestHeight().GTE(substituteClient.GetLatestHeight()) { - return errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", clientState.GetLatestHeight(), substituteClient.GetLatestHeight()) - } - return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } 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 708875f4456..08a638c6d87 100644 --- a/modules/light-clients/07-tendermint/light_client_module_test.go +++ b/modules/light-clients/07-tendermint/light_client_module_test.go @@ -15,8 +15,8 @@ var ( func (suite *TendermintTestSuite) TestRecoverClient() { var ( - subjectClientID, substituteClientID string - subjectClientState, substituteClientState exported.ClientState + subjectClientID, substituteClientID string + subjectClientState exported.ClientState ) testCases := []struct { @@ -58,26 +58,6 @@ func (suite *TendermintTestSuite) TestRecoverClient() { }, clienttypes.ErrClientNotFound, }, - { - "subject and substitute have equal latest height", - func() { - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.LatestHeight = substituteClientState.GetLatestHeight().(clienttypes.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, tmClientState) - }, - clienttypes.ErrInvalidHeight, - }, - { - "subject height is greater than substitute height", - func() { - tmClientState, ok := subjectClientState.(*ibctm.ClientState) - suite.Require().True(ok) - tmClientState.LatestHeight = substituteClientState.GetLatestHeight().Increment().(clienttypes.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, tmClientState) - }, - clienttypes.ErrInvalidHeight, - }, } for _, tc := range testCases { @@ -94,7 +74,6 @@ func (suite *TendermintTestSuite) TestRecoverClient() { substitutePath := ibctesting.NewPath(suite.chainA, suite.chainB) substitutePath.SetupClients() substituteClientID = substitutePath.EndpointA.ClientID - substituteClientState = suite.chainA.GetClientState(substituteClientID) tmClientState, ok := subjectClientState.(*ibctm.ClientState) suite.Require().True(ok) diff --git a/modules/light-clients/07-tendermint/migrations/migrations_test.go b/modules/light-clients/07-tendermint/migrations/migrations_test.go index a0b6234460e..3c44c306ba5 100644 --- a/modules/light-clients/07-tendermint/migrations/migrations_test.go +++ b/modules/light-clients/07-tendermint/migrations/migrations_test.go @@ -69,14 +69,14 @@ func (suite *MigrationsTestSuite) TestPruneExpiredConsensusStates() { for _, path := range paths { // collect all heights expected to be pruned var pruneHeights []exported.Height - pruneHeights = append(pruneHeights, path.EndpointA.GetClientState().GetLatestHeight()) + pruneHeights = append(pruneHeights, path.EndpointA.GetClientLatestHeight()) // these heights will be expired and also pruned for i := 0; i < 3; i++ { err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - pruneHeights = append(pruneHeights, path.EndpointA.GetClientState().GetLatestHeight()) + pruneHeights = append(pruneHeights, path.EndpointA.GetClientLatestHeight()) } // double chedck all information is currently stored @@ -110,11 +110,11 @@ func (suite *MigrationsTestSuite) TestPruneExpiredConsensusStates() { var unexpiredHeights []exported.Height err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - unexpiredHeights = append(unexpiredHeights, path.EndpointA.GetClientState().GetLatestHeight()) + unexpiredHeights = append(unexpiredHeights, path.EndpointA.GetClientLatestHeight()) err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - unexpiredHeights = append(unexpiredHeights, path.EndpointA.GetClientState().GetLatestHeight()) + unexpiredHeights = append(unexpiredHeights, path.EndpointA.GetClientLatestHeight()) unexpiredHeightMap[path] = unexpiredHeights } diff --git a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go index b835423258c..835f586f7d5 100644 --- a/modules/light-clients/07-tendermint/misbehaviour_handle_test.go +++ b/modules/light-clients/07-tendermint/misbehaviour_handle_test.go @@ -39,7 +39,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }{ { "valid fork misbehaviour", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -47,7 +47,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -58,7 +58,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid time misbehaviour", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -72,7 +72,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid time misbehaviour, header 1 time strictly less than header 2 time", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -86,7 +86,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid misbehavior at height greater than last consensusState", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -99,7 +99,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid misbehaviour with different trusted heights", func() { - trustedHeight1 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight1 := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals1, err := suite.chainB.GetTrustedValidators(int64(trustedHeight1.RevisionHeight)) suite.Require().NoError(err) @@ -107,7 +107,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - trustedHeight2 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight2 := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals2, err := suite.chainB.GetTrustedValidators(int64(trustedHeight2.RevisionHeight)) suite.Require().NoError(err) @@ -121,7 +121,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid misbehaviour at a previous revision", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -129,7 +129,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -144,12 +144,12 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid misbehaviour at a future revision", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) futureRevision := fmt.Sprintf("%s-%d", strings.TrimSuffix(suite.chainB.ChainID, fmt.Sprintf("-%d", clienttypes.ParseChainID(suite.chainB.ChainID))), height.GetRevisionNumber()+1) @@ -162,7 +162,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "valid misbehaviour with trusted heights at a previous revision", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -171,7 +171,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointB.UpgradeChain() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -182,7 +182,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "consensus state's valset hash different from misbehaviour should still pass", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -190,7 +190,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) // Create bothValSet with both suite validator and altVal bothValSet := cmttypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altValSet.Proposer)) @@ -205,7 +205,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "invalid misbehaviour: misbehaviour from different chain", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -213,7 +213,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -223,12 +223,12 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "misbehaviour trusted validators does not match validator hash in trusted consensus state", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers), @@ -238,7 +238,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "trusted consensus state does not exist", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -256,7 +256,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "trusting period expired", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -264,7 +264,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) suite.chainA.ExpireClient(path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod) @@ -276,7 +276,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "header 1 valset has too much change", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -284,7 +284,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), @@ -294,7 +294,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "header 2 valset has too much change", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -302,7 +302,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -312,7 +312,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { }, { "both header 1 and header 2 valsets have too much change", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -320,7 +320,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), @@ -387,7 +387,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }{ { "valid fork misbehaviour", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -395,7 +395,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -406,7 +406,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "valid time misbehaviour", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -420,7 +420,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "valid time misbehaviour, header 1 time strictly less than header 2 time", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -434,7 +434,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "valid misbehavior at height greater than last consensusState", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -447,7 +447,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "valid misbehaviour with different trusted heights", func() { - trustedHeight1 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight1 := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals1, err := suite.chainB.GetTrustedValidators(int64(trustedHeight1.RevisionHeight)) suite.Require().NoError(err) @@ -455,7 +455,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - trustedHeight2 := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight2 := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals2, err := suite.chainB.GetTrustedValidators(int64(trustedHeight2.RevisionHeight)) suite.Require().NoError(err) @@ -469,7 +469,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "consensus state's valset hash different from misbehaviour should still pass", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -477,7 +477,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) // Create bothValSet with both suite validator and altVal bothValSet := cmttypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altValSet.Proposer)) @@ -492,7 +492,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "invalid misbehaviour: misbehaviour from different chain", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -500,7 +500,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader("evmos", int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -510,12 +510,12 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "misbehaviour trusted validators does not match validator hash in trusted consensus state", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, altValSet, suite.chainB.Signers), @@ -525,7 +525,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "trusted consensus state does not exist", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -543,7 +543,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "trusting period expired", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -551,7 +551,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) suite.chainA.ExpireClient(path.EndpointA.ClientConfig.(*ibctesting.TendermintConfig).TrustingPeriod) @@ -563,7 +563,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "header 1 valset has too much change", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -571,7 +571,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), @@ -581,7 +581,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "header 2 valset has too much change", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -589,7 +589,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers), @@ -599,7 +599,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { }, { "both header 1 and header 2 valsets have too much change", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -607,7 +607,7 @@ func (suite *TendermintTestSuite) TestVerifyMisbehaviourNonRevisionChainID() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviour = &ibctm.Misbehaviour{ Header1: suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), altValSet, suite.chainB.NextVals, trustedVals, altSigners), diff --git a/modules/light-clients/07-tendermint/proposal_handle.go b/modules/light-clients/07-tendermint/proposal_handle.go index b2fabeac68e..8f36ad1dffe 100644 --- a/modules/light-clients/07-tendermint/proposal_handle.go +++ b/modules/light-clients/07-tendermint/proposal_handle.go @@ -46,7 +46,7 @@ func (cs ClientState) CheckSubstituteAndUpdateState( // copy consensus states and processed time from substitute to subject // starting from initial height and ending on the latest height (inclusive) - height := substituteClientState.GetLatestHeight() + height := substituteClientState.LatestHeight consensusState, found := GetConsensusState(substituteClientStore, cdc, height) if !found { diff --git a/modules/light-clients/07-tendermint/proposal_handle_test.go b/modules/light-clients/07-tendermint/proposal_handle_test.go index 4bae7099708..7f9b14a27fa 100644 --- a/modules/light-clients/07-tendermint/proposal_handle_test.go +++ b/modules/light-clients/07-tendermint/proposal_handle_test.go @@ -125,39 +125,39 @@ func (suite *TendermintTestSuite) TestCheckSubstituteAndUpdateState() { subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) substituteClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), substitutePath.EndpointA.ClientID) - expectedConsState := substitutePath.EndpointA.GetConsensusState(substituteClientState.GetLatestHeight()) - expectedProcessedTime, found := ibctm.GetProcessedTime(substituteClientStore, substituteClientState.GetLatestHeight()) + expectedConsState := substitutePath.EndpointA.GetConsensusState(substituteClientState.LatestHeight) + expectedProcessedTime, found := ibctm.GetProcessedTime(substituteClientStore, substituteClientState.LatestHeight) suite.Require().True(found) - expectedProcessedHeight, found := ibctm.GetProcessedTime(substituteClientStore, substituteClientState.GetLatestHeight()) + expectedProcessedHeight, found := ibctm.GetProcessedTime(substituteClientStore, substituteClientState.LatestHeight) suite.Require().True(found) - expectedIterationKey := ibctm.GetIterationKey(substituteClientStore, substituteClientState.GetLatestHeight()) + expectedIterationKey := ibctm.GetIterationKey(substituteClientStore, substituteClientState.LatestHeight) err := subjectClientState.CheckSubstituteAndUpdateState(suite.chainA.GetContext(), suite.chainA.App.AppCodec(), subjectClientStore, substituteClientStore, substituteClientState) if tc.expPass { suite.Require().NoError(err) - updatedClient := subjectPath.EndpointA.GetClientState() - suite.Require().Equal(clienttypes.ZeroHeight(), updatedClient.(*ibctm.ClientState).FrozenHeight) + updatedClient := subjectPath.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().Equal(clienttypes.ZeroHeight(), updatedClient.FrozenHeight) subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectPath.EndpointA.ClientID) // check that the correct consensus state was copied over - suite.Require().Equal(substituteClientState.GetLatestHeight(), updatedClient.GetLatestHeight()) - subjectConsState := subjectPath.EndpointA.GetConsensusState(updatedClient.GetLatestHeight()) - subjectProcessedTime, found := ibctm.GetProcessedTime(subjectClientStore, updatedClient.GetLatestHeight()) + suite.Require().Equal(substituteClientState.LatestHeight, updatedClient.LatestHeight) + subjectConsState := subjectPath.EndpointA.GetConsensusState(updatedClient.LatestHeight) + subjectProcessedTime, found := ibctm.GetProcessedTime(subjectClientStore, updatedClient.LatestHeight) suite.Require().True(found) - subjectProcessedHeight, found := ibctm.GetProcessedTime(substituteClientStore, updatedClient.GetLatestHeight()) + subjectProcessedHeight, found := ibctm.GetProcessedTime(substituteClientStore, updatedClient.LatestHeight) suite.Require().True(found) - subjectIterationKey := ibctm.GetIterationKey(substituteClientStore, updatedClient.GetLatestHeight()) + subjectIterationKey := ibctm.GetIterationKey(substituteClientStore, updatedClient.LatestHeight) suite.Require().Equal(expectedConsState, subjectConsState) suite.Require().Equal(expectedProcessedTime, subjectProcessedTime) suite.Require().Equal(expectedProcessedHeight, subjectProcessedHeight) suite.Require().Equal(expectedIterationKey, subjectIterationKey) - suite.Require().Equal(newChainID, updatedClient.(*ibctm.ClientState).ChainId) - suite.Require().Equal(time.Hour*24*7, updatedClient.(*ibctm.ClientState).TrustingPeriod) + suite.Require().Equal(newChainID, updatedClient.ChainId) + suite.Require().Equal(time.Hour*24*7, updatedClient.TrustingPeriod) } else { suite.Require().Error(err) } diff --git a/modules/light-clients/07-tendermint/store_test.go b/modules/light-clients/07-tendermint/store_test.go index 405c1bd03f7..fac0199ca5f 100644 --- a/modules/light-clients/07-tendermint/store_test.go +++ b/modules/light-clients/07-tendermint/store_test.go @@ -31,7 +31,7 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { { "consensus state not found", func() { // use height with no consensus state set - height = height.(clienttypes.Height).Increment() + height = height.Increment() }, false, false, }, { @@ -60,8 +60,8 @@ func (suite *TendermintTestSuite) TestGetConsensusState() { path = ibctesting.NewPath(suite.chainA, suite.chainB) path.Setup() - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) - height = clientState.GetLatestHeight() + + height = path.EndpointA.GetClientLatestHeight() tc.malleate() // change vars as necessary @@ -101,8 +101,7 @@ func (suite *TendermintTestSuite) TestGetProcessedTime() { err := path.EndpointA.CreateClient() suite.Require().NoError(err) - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) - height := clientState.GetLatestHeight() + height := path.EndpointA.GetClientLatestHeight() store := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) actualTime, ok := tendermint.GetProcessedTime(store, height) @@ -117,8 +116,7 @@ func (suite *TendermintTestSuite) TestGetProcessedTime() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - clientState = suite.chainA.GetClientState(path.EndpointA.ClientID) - height = clientState.GetLatestHeight() + height = path.EndpointA.GetClientLatestHeight() store = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), path.EndpointA.ClientID) actualTime, ok = tendermint.GetProcessedTime(store, height) diff --git a/modules/light-clients/07-tendermint/update_test.go b/modules/light-clients/07-tendermint/update_test.go index c6187dc84bf..7b6a6032248 100644 --- a/modules/light-clients/07-tendermint/update_test.go +++ b/modules/light-clients/07-tendermint/update_test.go @@ -47,7 +47,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "successful verify header for header with a previous height", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -66,7 +66,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "successful verify header: header with future height and different validator set", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -83,7 +83,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "successful verify header: header with next height and different validator set", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -100,7 +100,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful updates, passed in incorrect trusted validators for given consensus state", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) // Create bothValSet with both suite validator and altVal bothValSet := cmttypes.NewValidatorSet(append(suite.chainB.Vals.Validators, altVal)) @@ -114,7 +114,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful verify header with next height: update header mismatches nextValSetHash", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -127,7 +127,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful update with future height: too much change in validator set", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -139,7 +139,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful verify header: header height revision and trusted height revision mismatch", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -150,7 +150,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful verify header: header height < consensus height", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -173,7 +173,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful verify header: header timestamp is not past last client timestamp", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -185,7 +185,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful verify header: header with incorrect header chain-id", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -197,7 +197,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful update: trusting period has passed since last client timestamp", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight)) suite.Require().NoError(err) @@ -211,7 +211,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful update for a previous revision", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -228,7 +228,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "successful update with identical header to a previous update", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -246,7 +246,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful update to a future revision", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -259,7 +259,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { { name: "unsuccessful update: header height revision and trusted height revision mismatch", malleate: func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -285,7 +285,7 @@ func (suite *TendermintTestSuite) TestVerifyHeader() { // ensure counterparty state is committed suite.coordinator.CommitBlock(suite.chainB) - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) header, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) @@ -327,15 +327,15 @@ func (suite *TendermintTestSuite) TestUpdateState() { "success with height later than latest height", func() { tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) - suite.Require().True(path.EndpointA.GetClientState().GetLatestHeight().LT(tmHeader.GetHeight())) + suite.Require().True(path.EndpointA.GetClientLatestHeight().(clienttypes.Height).LT(tmHeader.GetHeight())) }, func() { tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) - clientState := path.EndpointA.GetClientState() - suite.Require().True(clientState.GetLatestHeight().EQ(tmHeader.GetHeight())) // new update, updated client state should have changed - suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(clientState.LatestHeight.EQ(tmHeader.GetHeight())) // new update, updated client state should have changed + suite.Require().True(clientState.LatestHeight.EQ(consensusHeights[0])) }, true, }, { @@ -348,14 +348,14 @@ func (suite *TendermintTestSuite) TestUpdateState() { tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) - suite.Require().True(path.EndpointA.GetClientState().GetLatestHeight().GT(tmHeader.GetHeight())) + suite.Require().True(path.EndpointA.GetClientLatestHeight().(clienttypes.Height).GT(tmHeader.GetHeight())) prevClientState = path.EndpointA.GetClientState() }, func() { - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) suite.Require().Equal(clientState, prevClientState) // fill in height, no change to client state - suite.Require().True(clientState.GetLatestHeight().GT(consensusHeights[0])) + suite.Require().True(clientState.LatestHeight.GT(consensusHeights[0])) }, true, }, { @@ -365,21 +365,21 @@ func (suite *TendermintTestSuite) TestUpdateState() { suite.Require().NoError(err) // use the same header which just updated the client - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) - suite.Require().Equal(path.EndpointA.GetClientState().GetLatestHeight(), tmHeader.GetHeight()) + suite.Require().Equal(path.EndpointA.GetClientLatestHeight().(clienttypes.Height), tmHeader.GetHeight()) prevClientState = path.EndpointA.GetClientState() prevConsensusState = path.EndpointA.GetConsensusState(tmHeader.GetHeight()) }, func() { - clientState := path.EndpointA.GetClientState() + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) suite.Require().Equal(clientState, prevClientState) - suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + suite.Require().True(clientState.LatestHeight.EQ(consensusHeights[0])) tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) @@ -391,7 +391,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { // this height will be expired and pruned err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - pruneHeight = path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + pruneHeight = path.EndpointA.GetClientLatestHeight().(clienttypes.Height) // Increment the time by a week suite.coordinator.IncrementTimeBy(7 * 24 * time.Hour) @@ -408,7 +408,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { // ensure counterparty state is committed suite.coordinator.CommitBlock(suite.chainB) - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) }, @@ -416,9 +416,9 @@ func (suite *TendermintTestSuite) TestUpdateState() { tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) - clientState := path.EndpointA.GetClientState() - suite.Require().True(clientState.GetLatestHeight().EQ(tmHeader.GetHeight())) // new update, updated client state should have changed - suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(clientState.LatestHeight.EQ(tmHeader.GetHeight())) // new update, updated client state should have changed + suite.Require().True(clientState.LatestHeight.EQ(consensusHeights[0])) // ensure consensus state was pruned _, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) @@ -430,7 +430,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { // this height will be expired and pruned err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - pruneHeight = path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + pruneHeight = path.EndpointA.GetClientLatestHeight().(clienttypes.Height) // assert that a consensus state exists at the prune height consensusState, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) @@ -451,7 +451,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { suite.Require().NoError(err) // use the same header which just updated the client - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) }, @@ -459,9 +459,9 @@ func (suite *TendermintTestSuite) TestUpdateState() { tmHeader, ok := clientMessage.(*ibctm.Header) suite.Require().True(ok) - clientState := path.EndpointA.GetClientState() - suite.Require().True(clientState.GetLatestHeight().EQ(tmHeader.GetHeight())) // new update, updated client state should have changed - suite.Require().True(clientState.GetLatestHeight().EQ(consensusHeights[0])) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + suite.Require().True(clientState.LatestHeight.EQ(tmHeader.GetHeight())) // new update, updated client state should have changed + suite.Require().True(clientState.LatestHeight.EQ(consensusHeights[0])) // ensure consensus state was pruned _, found := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, pruneHeight) @@ -488,7 +488,7 @@ func (suite *TendermintTestSuite) TestUpdateState() { // ensure counterparty state is committed suite.coordinator.CommitBlock(suite.chainB) - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) @@ -542,7 +542,7 @@ func (suite *TendermintTestSuite) TestPruneConsensusState() { // this height will be expired but not pruned err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - expiredHeight := path.EndpointA.GetClientState().GetLatestHeight() + expiredHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) // expected values that must still remain in store after pruning expectedConsState, ok := path.EndpointA.Chain.GetConsensusState(path.EndpointA.ClientID, expiredHeight) @@ -644,7 +644,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { }, { "invalid fork misbehaviour: identical headers", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -652,7 +652,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - height := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + height := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) misbehaviourHeader := suite.chainB.CreateTMClientHeader(suite.chainB.ChainID, int64(height.RevisionHeight), trustedHeight, suite.chainB.ProposedHeader.Time.Add(time.Minute), suite.chainB.Vals, suite.chainB.NextVals, trustedVals, suite.chainB.Signers) clientMessage = &ibctm.Misbehaviour{ @@ -663,7 +663,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { }, { "invalid time misbehaviour: monotonically increasing time", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -722,7 +722,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { { "valid fork misbehaviour returns true", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) header1, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) @@ -731,7 +731,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { err = path.EndpointA.UpdateClient() suite.Require().NoError(err) - trustedHeight = path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight = path.EndpointA.GetClientLatestHeight().(clienttypes.Height) header2, err := path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) @@ -748,7 +748,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { }, { "valid time misbehaviour: not monotonically increasing time", func() { - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) trustedVals, err := suite.chainB.GetTrustedValidators(int64(trustedHeight.RevisionHeight) + 1) suite.Require().NoError(err) @@ -773,7 +773,7 @@ func (suite *TendermintTestSuite) TestCheckForMisbehaviour() { // ensure counterparty state is committed suite.coordinator.CommitBlock(suite.chainB) - trustedHeight := path.EndpointA.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := path.EndpointA.GetClientLatestHeight().(clienttypes.Height) clientMessage, err = path.EndpointA.Counterparty.Chain.IBCClientHeader(path.EndpointA.Counterparty.Chain.LatestCommittedHeader, trustedHeight) suite.Require().NoError(err) diff --git a/modules/light-clients/07-tendermint/upgrade.go b/modules/light-clients/07-tendermint/upgrade.go index 300023040da..be19cffda9a 100644 --- a/modules/light-clients/07-tendermint/upgrade.go +++ b/modules/light-clients/07-tendermint/upgrade.go @@ -59,7 +59,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( } // last height of current counterparty chain must be client's latest height - lastHeight := cs.GetLatestHeight() + lastHeight := cs.LatestHeight // Must prove against latest consensus state to ensure we are verifying against latest upgrade plan // This verifies that upgrade is intended for the provided revision, since committed client must exist diff --git a/modules/light-clients/07-tendermint/upgrade_test.go b/modules/light-clients/07-tendermint/upgrade_test.go index 290fcae730a..4b2a848a09c 100644 --- a/modules/light-clients/07-tendermint/upgrade_test.go +++ b/modules/light-clients/07-tendermint/upgrade_test.go @@ -45,16 +45,18 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, { 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.GetLatestHeight().GetRevisionHeight()+10), commitmenttypes.GetSDKSpecs(), upgradePath) + 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() upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -74,9 +76,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -99,9 +103,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -128,9 +134,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -153,9 +161,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -175,9 +185,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -204,9 +216,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -217,8 +231,10 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedClientProof = []byte("proof") }, @@ -231,8 +247,10 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(lastHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) upgradedConsensusStateProof = []byte("proof") }, @@ -250,9 +268,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -268,9 +288,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -291,9 +313,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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 tmClient, _ := cs.(*ibctm.ClientState) @@ -319,9 +343,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -342,9 +368,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -365,9 +393,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -388,9 +418,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -417,9 +449,11 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { 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())), cs.GetLatestHeight().GetRevisionHeight()) - upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(lastHeight.GetRevisionHeight())), cs.GetLatestHeight().GetRevisionHeight()) + 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, }, @@ -442,7 +476,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { newChainID, err = clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) suite.Require().NoError(err) - upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.GetLatestHeight().GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), upgradePath) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), upgradePath) upgradedClient = upgradedClient.ZeroCustomFields() upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) suite.Require().NoError(err) @@ -474,10 +508,10 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { if tc.expPass { suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) - clientState := suite.chainA.GetClientState(path.EndpointA.ClientID) + clientState := suite.chainA.GetClientState(path.EndpointA.ClientID).(*ibctm.ClientState) suite.Require().NotNil(clientState, "verify upgrade failed on valid case: %s", tc.name) - consensusState, found := suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientState.GetLatestHeight()) + consensusState, found := suite.chainA.GetConsensusState(path.EndpointA.ClientID, clientState.LatestHeight) suite.Require().NotNil(consensusState, "verify upgrade failed on valid case: %s", tc.name) suite.Require().True(found) } else { diff --git a/modules/light-clients/08-wasm/keeper/keeper_test.go b/modules/light-clients/08-wasm/keeper/keeper_test.go index 73810c74b42..3afaaccff11 100644 --- a/modules/light-clients/08-wasm/keeper/keeper_test.go +++ b/modules/light-clients/08-wasm/keeper/keeper_test.go @@ -27,6 +27,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -89,15 +90,15 @@ func (suite *KeeperTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[ err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) - wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) - clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.GetLatestHeight().(clienttypes.Height)) + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.LatestHeight) clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), clientStateBz) consensusState := types.NewConsensusState(payload.ConsensusState) consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) - store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) + store.Set(host.ConsensusStateKey(clientState.LatestHeight), consensusStateBz) resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 7f0b5284636..4f31048421f 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -191,6 +191,22 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S return clientState.Status(ctx, clientStore, cdc) } +// LatestHeight returns the latest height for the client state for the given client identifier. +// If no client is present for the provided client identifier a zero value height is returned. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. +func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + cdc := lcm.keeper.Codec() + + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return clienttypes.ZeroHeight() + } + + return clientState.LatestHeight +} + // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. @@ -234,10 +250,6 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) } - if clientState.GetLatestHeight().GTE(substituteClient.GetLatestHeight()) { - return errorsmod.Wrapf(clienttypes.ErrInvalidHeight, "subject client state latest height is greater or equal to substitute client state latest height (%s >= %s)", clientState.GetLatestHeight(), substituteClient.GetLatestHeight()) - } - return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } diff --git a/modules/light-clients/08-wasm/light_client_module_test.go b/modules/light-clients/08-wasm/light_client_module_test.go index 120b40ce2e3..ca9d665797f 100644 --- a/modules/light-clients/08-wasm/light_client_module_test.go +++ b/modules/light-clients/08-wasm/light_client_module_test.go @@ -2,10 +2,8 @@ package wasm_test import ( wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" - wasmtypes "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" - "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -16,9 +14,8 @@ const ( func (suite *WasmTestSuite) TestRecoverClient() { var ( - expectedClientStateBz []byte - subjectClientID, substituteClientID string - subjectClientState, substituteClientState exported.ClientState + expectedClientStateBz []byte + subjectClientID, substituteClientID string ) testCases := []struct { @@ -61,26 +58,6 @@ func (suite *WasmTestSuite) TestRecoverClient() { }, clienttypes.ErrClientNotFound, }, - { - "subject and substitute have equal latest height", - func() { - wasmClientState, ok := subjectClientState.(*wasmtypes.ClientState) - suite.Require().True(ok) - wasmClientState.LatestHeight = substituteClientState.GetLatestHeight().(clienttypes.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, wasmClientState) - }, - clienttypes.ErrInvalidHeight, - }, - { - "subject height is greater than substitute height", - func() { - wasmClientState, ok := subjectClientState.(*wasmtypes.ClientState) - suite.Require().True(ok) - wasmClientState.LatestHeight = substituteClientState.GetLatestHeight().Increment().(clienttypes.Height) - suite.chainA.App.GetIBCKeeper().ClientKeeper.SetClientState(suite.chainA.GetContext(), subjectClientID, wasmClientState) - }, - clienttypes.ErrInvalidHeight, - }, } for _, tc := range testCases { @@ -94,7 +71,6 @@ func (suite *WasmTestSuite) TestRecoverClient() { suite.Require().NoError(err) subjectClientID = subjectEndpoint.ClientID - subjectClientState = subjectEndpoint.GetClientState() subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), subjectClientID) substituteEndpoint := wasmtesting.NewWasmEndpoint(suite.chainA) @@ -102,8 +78,6 @@ func (suite *WasmTestSuite) TestRecoverClient() { suite.Require().NoError(err) substituteClientID = substituteEndpoint.ClientID - substituteClientState = substituteEndpoint.GetClientState() - lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetRouter().GetRoute(subjectClientID) suite.Require().True(found) diff --git a/modules/light-clients/08-wasm/testing/values.go b/modules/light-clients/08-wasm/testing/values.go index e91fa5296a1..f7e27c5d7c1 100644 --- a/modules/light-clients/08-wasm/testing/values.go +++ b/modules/light-clients/08-wasm/testing/values.go @@ -49,7 +49,7 @@ func CreateMockTendermintClientState(height clienttypes.Height) *ibctm.ClientSta // CreateMockClientStateBz returns valid client state bytes for use in tests. func CreateMockClientStateBz(cdc codec.BinaryCodec, checksum types.Checksum) []byte { wrappedClientStateBz := clienttypes.MustMarshalClientState(cdc, MockTendermitClientState) - mockClientSate := types.NewClientState(wrappedClientStateBz, checksum, MockTendermitClientState.GetLatestHeight().(clienttypes.Height)) + mockClientSate := types.NewClientState(wrappedClientStateBz, checksum, MockTendermitClientState.LatestHeight) return clienttypes.MustMarshalClientState(cdc, mockClientSate) } diff --git a/modules/light-clients/08-wasm/types/client_state.go b/modules/light-clients/08-wasm/types/client_state.go index cced48113d1..4ce6fe3e044 100644 --- a/modules/light-clients/08-wasm/types/client_state.go +++ b/modules/light-clients/08-wasm/types/client_state.go @@ -31,11 +31,6 @@ func (ClientState) ClientType() string { return Wasm } -// GetLatestHeight returns latest block height. -func (cs ClientState) GetLatestHeight() exported.Height { - return cs.LatestHeight -} - // Validate performs a basic validation of the client state fields. func (cs ClientState) Validate() error { if len(cs.Data) == 0 { @@ -142,10 +137,10 @@ func (cs ClientState) VerifyMembership( return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", clienttypes.Height{}, height) } - if cs.GetLatestHeight().LT(height) { + if cs.LatestHeight.LT(height) { return errorsmod.Wrapf( ibcerrors.ErrInvalidHeight, - "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.LatestHeight, height, ) } @@ -186,10 +181,10 @@ func (cs ClientState) VerifyNonMembership( return errorsmod.Wrapf(ibcerrors.ErrInvalidType, "expected %T, got %T", clienttypes.Height{}, height) } - if cs.GetLatestHeight().LT(height) { + if cs.LatestHeight.LT(height) { return errorsmod.Wrapf( ibcerrors.ErrInvalidHeight, - "client state height < proof height (%d < %d), please ensure the client has been updated", cs.GetLatestHeight(), height, + "client state height < proof height (%d < %d), please ensure the client has been updated", cs.LatestHeight, height, ) } diff --git a/modules/light-clients/08-wasm/types/client_state_test.go b/modules/light-clients/08-wasm/types/client_state_test.go index 3514b90fda9..b69b6459251 100644 --- a/modules/light-clients/08-wasm/types/client_state_test.go +++ b/modules/light-clients/08-wasm/types/client_state_test.go @@ -18,6 +18,7 @@ import ( ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "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" ibcmock "github.com/cosmos/ibc-go/v8/testing/mock" ) @@ -153,7 +154,7 @@ func (suite *TypesTestSuite) TestGetTimestampAtHeight() { clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) clientState := endpoint.GetClientState().(*types.ClientState) - height = clientState.GetLatestHeight() + height = clientState.LatestHeight tc.malleate() @@ -256,15 +257,15 @@ func (suite *TypesTestSuite) TestInitialize() { suite.Require().Equal(env.Contract.Address, defaultWasmClientID) - wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) - clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.GetLatestHeight().(clienttypes.Height)) + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.LatestHeight) clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), clientStateBz) consensusState := types.NewConsensusState(payload.ConsensusState) consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) - store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) + store.Set(host.ConsensusStateKey(clientState.LatestHeight), consensusStateBz) resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) @@ -313,7 +314,7 @@ func (suite *TypesTestSuite) TestInitialize() { wrappedClientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), wasmtesting.MockTendermitClientState) wrappedClientConsensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientConsensusState) - clientState = types.NewClientState(wrappedClientStateBz, suite.checksum, wasmtesting.MockTendermitClientState.GetLatestHeight().(clienttypes.Height)) + clientState = types.NewClientState(wrappedClientStateBz, suite.checksum, wasmtesting.MockTendermitClientState.LatestHeight) consensusState = types.NewConsensusState(wrappedClientConsensusStateBz) clientID := suite.chainA.App.GetIBCKeeper().ClientKeeper.GenerateClientIdentifier(suite.chainA.GetContext(), clientState.ClientType()) @@ -331,7 +332,7 @@ func (suite *TypesTestSuite) TestInitialize() { suite.Require().Equal(expClientState, clientStore.Get(host.ClientStateKey())) expConsensusState := clienttypes.MustMarshalConsensusState(suite.chainA.Codec, consensusState) - suite.Require().Equal(expConsensusState, clientStore.Get(host.ConsensusStateKey(clientState.GetLatestHeight()))) + suite.Require().Equal(expConsensusState, clientStore.Get(host.ConsensusStateKey(clientState.LatestHeight))) } else { suite.Require().ErrorIs(err, tc.expError) } diff --git a/modules/light-clients/08-wasm/types/types_test.go b/modules/light-clients/08-wasm/types/types_test.go index e1729f66997..6442b36ed7e 100644 --- a/modules/light-clients/08-wasm/types/types_test.go +++ b/modules/light-clients/08-wasm/types/types_test.go @@ -23,6 +23,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -89,15 +90,15 @@ func (suite *TypesTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[s err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) - wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) - clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.GetLatestHeight().(clienttypes.Height)) + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.LatestHeight) clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), clientStateBz) consensusState := types.NewConsensusState(payload.ConsensusState) consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) - store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) + store.Set(host.ConsensusStateKey(clientState.LatestHeight), consensusStateBz) resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) diff --git a/modules/light-clients/08-wasm/types/upgrade_test.go b/modules/light-clients/08-wasm/types/upgrade_test.go index f1dcfa0744d..bcf27763bdf 100644 --- a/modules/light-clients/08-wasm/types/upgrade_test.go +++ b/modules/light-clients/08-wasm/types/upgrade_test.go @@ -162,9 +162,9 @@ func (suite *TypesTestSuite) TestVerifyUpgradeAndUpdateState() { suite.Require().NoError(err) // set new client state and consensus state - wrappedUpgradedClient := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), expectedUpgradedClient.Data) + wrappedUpgradedClient := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), expectedUpgradedClient.Data).(*ibctm.ClientState) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), upgradedClient)) - store.Set(host.ConsensusStateKey(wrappedUpgradedClient.GetLatestHeight()), clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState)) + store.Set(host.ConsensusStateKey(wrappedUpgradedClient.LatestHeight), clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState)) return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil }) @@ -244,7 +244,7 @@ func (suite *TypesTestSuite) TestVerifyUpgradeAndUpdateState() { suite.Require().NotEmpty(clientStateBz) suite.Require().Equal(upgradedClient, clienttypes.MustUnmarshalClientState(suite.chainA.Codec, clientStateBz)) - consStateBz := clientStore.Get(host.ConsensusStateKey(upgradedClient.GetLatestHeight())) + consStateBz := clientStore.Get(host.ConsensusStateKey(upgradedClient.(*types.ClientState).LatestHeight)) suite.Require().NotEmpty(consStateBz) suite.Require().Equal(upgradedConsState, clienttypes.MustUnmarshalConsensusState(suite.chainA.Codec, consStateBz)) } else { diff --git a/modules/light-clients/08-wasm/types/vm_test.go b/modules/light-clients/08-wasm/types/vm_test.go index 7b56857a55e..1c5810565ea 100644 --- a/modules/light-clients/08-wasm/types/vm_test.go +++ b/modules/light-clients/08-wasm/types/vm_test.go @@ -11,6 +11,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" localhost "github.com/cosmos/ibc-go/v8/modules/light-clients/09-localhost" ) @@ -32,15 +33,15 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) - wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) - clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.GetLatestHeight().(clienttypes.Height)) + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.LatestHeight) clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), clientStateBz) consensusState := types.NewConsensusState(payload.ConsensusState) consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) - store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) + store.Set(host.ConsensusStateKey(clientState.LatestHeight), consensusStateBz) return &wasmvmtypes.Response{}, 0, nil } @@ -136,8 +137,8 @@ func (suite *TypesTestSuite) TestWasmInstantiate() { suite.Require().NoError(err) // Change the checksum to something else. - wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) - clientState := types.NewClientState(payload.ClientState, []byte("new checksum"), wrappedClientState.GetLatestHeight().(clienttypes.Height)) + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) + clientState := types.NewClientState(payload.ClientState, []byte("new checksum"), wrappedClientState.LatestHeight) store.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState)) resp, err := json.Marshal(types.UpdateStateResult{}) diff --git a/modules/light-clients/08-wasm/wasm_test.go b/modules/light-clients/08-wasm/wasm_test.go index 79702fa860c..f6e9d6e54c7 100644 --- a/modules/light-clients/08-wasm/wasm_test.go +++ b/modules/light-clients/08-wasm/wasm_test.go @@ -23,6 +23,7 @@ import ( clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -84,15 +85,15 @@ func (suite *WasmTestSuite) setupWasmWithMockVM() (ibctesting.TestingApp, map[st err := json.Unmarshal(initMsg, &payload) suite.Require().NoError(err) - wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState) + wrappedClientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), payload.ClientState).(*ibctm.ClientState) - clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.GetLatestHeight().(clienttypes.Height)) + clientState := types.NewClientState(payload.ClientState, payload.Checksum, wrappedClientState.LatestHeight) clientStateBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), clientStateBz) consensusState := types.NewConsensusState(payload.ConsensusState) consensusStateBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), consensusState) - store.Set(host.ConsensusStateKey(clientState.GetLatestHeight()), consensusStateBz) + store.Set(host.ConsensusStateKey(clientState.LatestHeight), consensusStateBz) resp, err := json.Marshal(types.EmptyResult{}) suite.Require().NoError(err) diff --git a/modules/light-clients/09-localhost/client_state.go b/modules/light-clients/09-localhost/client_state.go index 93d15fe9803..f687deeef1e 100644 --- a/modules/light-clients/09-localhost/client_state.go +++ b/modules/light-clients/09-localhost/client_state.go @@ -30,11 +30,6 @@ func (ClientState) ClientType() string { return exported.Localhost } -// GetLatestHeight returns the 09-localhost client state latest height. -func (cs ClientState) GetLatestHeight() exported.Height { - return cs.LatestHeight -} - // Validate performs a basic validation of the client state fields. func (cs ClientState) Validate() error { if cs.LatestHeight.RevisionHeight == 0 { diff --git a/modules/light-clients/09-localhost/client_state_test.go b/modules/light-clients/09-localhost/client_state_test.go index 23a36c39334..2265a970033 100644 --- a/modules/light-clients/09-localhost/client_state_test.go +++ b/modules/light-clients/09-localhost/client_state_test.go @@ -15,7 +15,7 @@ func (suite *LocalhostTestSuite) TestClientType() { func (suite *LocalhostTestSuite) TestGetLatestHeight() { expectedHeight := clienttypes.NewHeight(3, 10) clientState := localhost.NewClientState(expectedHeight) - suite.Require().Equal(expectedHeight, clientState.GetLatestHeight()) + suite.Require().Equal(expectedHeight, clientState.LatestHeight) } func (suite *LocalhostTestSuite) TestGetTimestampAtHeight() { @@ -117,7 +117,7 @@ func (suite *LocalhostTestSuite) TestUpdateState() { suite.Require().True(heights[0].EQ(expHeight)) clientState = suite.chain.GetClientState(exported.LocalhostClientID).(*localhost.ClientState) - suite.Require().True(heights[0].EQ(clientState.GetLatestHeight())) + suite.Require().True(heights[0].EQ(clientState.LatestHeight)) } func (suite *LocalhostTestSuite) TestCheckSubstituteAndUpdateState() { diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index 9fb0f7a349f..f3b69ffe643 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -144,6 +144,21 @@ func (LightClientModule) Status(ctx sdk.Context, clientID string) exported.Statu return exported.Active } +// LatestHeight returns the latest height for the client state for the given client identifier. +// If no client is present for the provided client identifier a zero value height is returned. +// +// CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. +func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + + clientState, found := getClientState(clientStore, lcm.cdc) + if !found { + return clienttypes.ZeroHeight() + } + + return clientState.LatestHeight +} + // TimestampAtHeight returns the current block time retrieved from the application context. The localhost client does not store consensus states and thus // cannot provide a timestamp for the provided height. func (LightClientModule) TimestampAtHeight( diff --git a/testing/chain.go b/testing/chain.go index cb695b5744b..f48dd0156d4 100644 --- a/testing/chain.go +++ b/testing/chain.go @@ -276,9 +276,7 @@ func (chain *TestChain) QueryUpgradeProof(key []byte, height uint64) ([]byte, cl // QueryConsensusStateProof performs an abci query for a consensus state // stored on the given clientID. The proof and consensusHeight are returned. func (chain *TestChain) QueryConsensusStateProof(clientID string) ([]byte, clienttypes.Height) { - clientState := chain.GetClientState(clientID) - - consensusHeight := clientState.GetLatestHeight().(clienttypes.Height) + consensusHeight := chain.GetClientLatestHeight(clientID).(clienttypes.Height) consensusKey := host.FullConsensusStateKey(clientID, consensusHeight) consensusProof, _ := chain.QueryProof(consensusKey) @@ -613,6 +611,14 @@ func (chain *TestChain) GetChannelCapability(portID, channelID string) *capabili return capability } +// GetClientLatestHeight returns the latest height for the client state with the given client identifier. +// If an invalid client identifier is provided then a zero value height will be returned and testing wil fail. +func (chain *TestChain) GetClientLatestHeight(clientID string) exported.Height { + latestHeight := chain.App.GetIBCKeeper().ClientKeeper.GetLatestHeight(chain.GetContext(), clientID) + require.False(chain.TB, latestHeight.IsZero()) + return latestHeight +} + // GetTimeoutHeight is a convenience function which returns a IBC packet timeout height // to be used for testing. It returns the current IBC height + 100 blocks func (chain *TestChain) GetTimeoutHeight() clienttypes.Height { diff --git a/testing/endpoint.go b/testing/endpoint.go index e1d8282c45f..bde2146432f 100644 --- a/testing/endpoint.go +++ b/testing/endpoint.go @@ -65,11 +65,10 @@ func NewDefaultEndpoint(chain *TestChain) *Endpoint { // QueryProof queries proof associated with this endpoint using the latest client state // height on the counterparty chain. func (endpoint *Endpoint) QueryProof(key []byte) ([]byte, clienttypes.Height) { - // obtain the counterparty client representing the chain associated with the endpoint - clientState := endpoint.Counterparty.Chain.GetClientState(endpoint.Counterparty.ClientID) - + // obtain the counterparty client height. + latestCounterpartyHeight := endpoint.Counterparty.GetClientLatestHeight() // query proof on the counterparty using the latest height of the IBC client - return endpoint.QueryProofAtHeight(key, clientState.GetLatestHeight().GetRevisionHeight()) + return endpoint.QueryProofAtHeight(key, latestCounterpartyHeight.GetRevisionHeight()) } // QueryProofAtHeight queries proof associated with this endpoint using the proof height @@ -139,7 +138,7 @@ func (endpoint *Endpoint) UpdateClient() (err error) { switch endpoint.ClientConfig.GetClientType() { case exported.Tendermint: - trustedHeight := endpoint.GetClientState().GetLatestHeight().(clienttypes.Height) + trustedHeight := endpoint.GetClientLatestHeight().(clienttypes.Height) header, err = endpoint.Counterparty.Chain.IBCClientHeader(endpoint.Counterparty.Chain.LatestCommittedHeader, trustedHeight) default: err = fmt.Errorf("client type %s is not supported", endpoint.ClientConfig.GetClientType()) @@ -200,7 +199,10 @@ func (endpoint *Endpoint) UpgradeChain() error { Root: commitmenttypes.NewMerkleRoot(endpoint.Chain.LatestCommittedHeader.Header.GetAppHash()), NextValidatorsHash: endpoint.Chain.LatestCommittedHeader.Header.NextValidatorsHash, } - endpoint.Counterparty.SetConsensusState(tmConsensusState, clientState.GetLatestHeight()) + + latestHeight := endpoint.Counterparty.GetClientLatestHeight() + + endpoint.Counterparty.SetConsensusState(tmConsensusState, latestHeight) // ensure the next update isn't identical to the one set in state endpoint.Chain.Coordinator.IncrementTime() @@ -304,8 +306,7 @@ func (endpoint *Endpoint) QueryConnectionHandshakeProof() ( clientKey := host.FullClientStateKey(endpoint.Counterparty.ClientID) clientProof, proofHeight = endpoint.Counterparty.QueryProof(clientKey) - consensusHeight = clientState.GetLatestHeight().(clienttypes.Height) - + consensusHeight = endpoint.Counterparty.GetClientLatestHeight().(clienttypes.Height) // query proof for the consensus state on the counterparty consensusKey := host.FullConsensusStateKey(endpoint.Counterparty.ClientID, consensusHeight) consensusProof, _ = endpoint.Counterparty.QueryProofAtHeight(consensusKey, proofHeight.GetRevisionHeight()) @@ -787,7 +788,13 @@ func (endpoint *Endpoint) UpdateChannel(updater func(channel *channeltypes.Chann require.NoError(endpoint.Chain.TB, err) } -// GetClientState retrieves the Client State for this endpoint. The +// GetClientLatestHeight returns the latest height for the client state for this endpoint. +// The client state is expected to exist otherwise testing will fail. +func (endpoint *Endpoint) GetClientLatestHeight() exported.Height { + return endpoint.Chain.GetClientLatestHeight(endpoint.ClientID) +} + +// GetClientState retrieves the client state for this endpoint. The // client state is expected to exist otherwise testing will fail. func (endpoint *Endpoint) GetClientState() exported.ClientState { return endpoint.Chain.GetClientState(endpoint.ClientID) diff --git a/testing/solomachine.go b/testing/solomachine.go index 470f3b74943..34877aa8535 100644 --- a/testing/solomachine.go +++ b/testing/solomachine.go @@ -298,7 +298,7 @@ func (solo *Solomachine) ConnOpenAck(chain *TestChain, clientID, connectionID st msgConnOpenAck := connectiontypes.NewMsgConnectionOpenAck( connectionID, connectionIDSolomachine, clientState, tryProof, clientProof, consensusProof, - clienttypes.ZeroHeight(), clientState.GetLatestHeight().(clienttypes.Height), + clienttypes.ZeroHeight(), clientState.LatestHeight, ConnectionVersion, chain.SenderAccount.GetAddress().String(), ) From ccf2adfb49945d45fe0c6a6a537e436b67afb3f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 11 Mar 2024 17:15:46 +0100 Subject: [PATCH 45/74] docs: refactor light client developer guide --- .../01-ibc/05-upgrades/02-developer-guide.md | 2 +- .../01-developer-guide/01-overview.md | 21 +++++++++++++--- ...ent-state.md => 02-light-client-module.md} | 24 +++++-------------- .../01-developer-guide/03-client-state.md | 23 ++++++++++++++++++ ...nsensus-state.md => 04-consensus-state.md} | 4 ++-- ...iour.md => 05-updates-and-misbehaviour.md} | 6 ++--- .../{05-upgrades.md => 06-upgrades.md} | 2 +- .../{06-proofs.md => 07-proofs.md} | 2 +- .../{07-proposals.md => 08-proposals.md} | 2 +- .../{08-setup.md => 09-setup.md} | 2 +- .../04-wasm/03-integration.md | 2 +- .../03-light-clients/04-wasm/07-contracts.md | 20 ++++++++-------- docs/docs/05-migrations/02-sdk-to-v1.md | 2 +- 13 files changed, 69 insertions(+), 43 deletions(-) rename docs/docs/03-light-clients/01-developer-guide/{02-client-state.md => 02-light-client-module.md} (66%) create mode 100644 docs/docs/03-light-clients/01-developer-guide/03-client-state.md rename docs/docs/03-light-clients/01-developer-guide/{03-consensus-state.md => 04-consensus-state.md} (96%) rename docs/docs/03-light-clients/01-developer-guide/{04-updates-and-misbehaviour.md => 05-updates-and-misbehaviour.md} (97%) rename docs/docs/03-light-clients/01-developer-guide/{05-upgrades.md => 06-upgrades.md} (99%) rename docs/docs/03-light-clients/01-developer-guide/{06-proofs.md => 07-proofs.md} (99%) rename docs/docs/03-light-clients/01-developer-guide/{07-proposals.md => 08-proposals.md} (99%) rename docs/docs/03-light-clients/01-developer-guide/{08-setup.md => 09-setup.md} (99%) diff --git a/docs/docs/01-ibc/05-upgrades/02-developer-guide.md b/docs/docs/01-ibc/05-upgrades/02-developer-guide.md index 1f33e9d0ad2..c21b23e03e3 100644 --- a/docs/docs/01-ibc/05-upgrades/02-developer-guide.md +++ b/docs/docs/01-ibc/05-upgrades/02-developer-guide.md @@ -11,4 +11,4 @@ slug: /ibc/upgrades/developer-guide Learn how to implement upgrade functionality for your custom IBC client. ::: -Please see the section [Handling upgrades](../../03-light-clients/01-developer-guide/05-upgrades.md) from the light client developer guide for more information. +Please see the section [Handling upgrades](../../03-light-clients/01-developer-guide/06-upgrades.md) from the light client developer guide for more information. diff --git a/docs/docs/03-light-clients/01-developer-guide/01-overview.md b/docs/docs/03-light-clients/01-developer-guide/01-overview.md index eeef65a7be7..b8dc7e7c434 100644 --- a/docs/docs/03-light-clients/01-developer-guide/01-overview.md +++ b/docs/docs/03-light-clients/01-developer-guide/01-overview.md @@ -27,6 +27,7 @@ The following aims to provide a high level IBC light client module developer gui A light client module developer should be concerned with three main interfaces: +- [`LightClientModule`](#lightclientmodule) a module which manages many light client instances of a certain type. - [`ClientState`](#clientstate) encapsulates the light client implementation and its semantics. - [`ConsensusState`](#consensusstate) tracks consensus data used for verification of client updates, misbehaviour detection and proof verification of counterparty state. - [`ClientMessage`](#clientmessage) used for submitting block headers for client updates and submission of misbehaviour evidence using conflicting headers. @@ -35,6 +36,20 @@ Throughout this guide the `07-tendermint` light client module may be referred to ## Concepts and vocabulary +### `LightClientModule` + +`LightClientModule` is an interface defined by core IBC which allows for modular light client implementations. All light client implementations *must* implement the [`LightClientModule` interface](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/core/exported/client.go#L51) so that core IBC may redirect calls to the light client module. + +For example a light client module may need to: +- create clients +- update clients +- recover and upgrade clients +- verify membership and non-membership + +The methods which make up this interface are detailed at a more granular level in the [LightClientModule section of this guide](02-light-client-module.md). + +Please refer to the `07-tendermint`'s[`LightClientModule` definition](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/light-clients/07-tendermint/light_client_module.go#L17) for more information. + ### `ClientState` `ClientState` is a term used to define the data structure which encapsulates opaque light client state. The `ClientState` contains all the information needed to verify a `ClientMessage` and perform membership and non-membership proof verification of counterparty state. This includes properties that refer to the remote state machine, the light client type and the specific light client instance. @@ -47,7 +62,7 @@ For example: - Constraints used for client upgrades. The `ClientState` type maintained within the light client module *must* implement the [`ClientState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L36) interface defined in `core/modules/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [ClientState section of this guide](02-client-state.md). +The methods which make up this interface are detailed at a more granular level in the [ClientState section of this guide](03-client-state.md). Please refer to the `07-tendermint` light client module's [`ClientState` definition](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L18) containing information such as chain ID, status, latest height, unbonding period and proof specifications. @@ -58,7 +73,7 @@ Please refer to the `07-tendermint` light client module's [`ClientState` definit For example, the `ConsensusState` of the `07-tendermint` light client module defines a trusted root which is used by the `ClientState` to perform verification of membership and non-membership commitment proofs, as well as the next validator set hash used for verifying headers can be trusted in client updates. The `ConsensusState` type maintained within the light client module *must* implement the [`ConsensusState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L134) interface defined in `modules/core/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [`ConsensusState` section of this guide](03-consensus-state.md). +The methods which make up this interface are detailed at a more granular level in the [`ConsensusState` section of this guide](04-consensus-state.md). ### `Height` @@ -76,4 +91,4 @@ The following are considered as valid update scenarios: - A batch of block headers which when verified inserts `N` `ConsensusState` instances for `N` unique heights. - Evidence of misbehaviour provided by two conflicting block headers. -Learn more in the [Handling update and misbehaviour](04-updates-and-misbehaviour.md) section. +Learn more in the [Handling update and misbehaviour](05-updates-and-misbehaviour.md) section. diff --git a/docs/docs/03-light-clients/01-developer-guide/02-client-state.md b/docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md similarity index 66% rename from docs/docs/03-light-clients/01-developer-guide/02-client-state.md rename to docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md index 58649b6f825..e88051b17ad 100644 --- a/docs/docs/03-light-clients/01-developer-guide/02-client-state.md +++ b/docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md @@ -1,24 +1,12 @@ --- -title: Client State interface -sidebar_label: Client State interface +title: Light Client Module interface +sidebar_label: Light Client Module interface sidebar_position: 2 -slug: /ibc/light-clients/client-state +slug: /ibc/light-clients/light-client-module --- -# Implementing the `ClientState` interface - -Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface. This list of methods described here does not include all methods of the interface. Some methods are explained in detail in the relevant sections of the guide. - -## `ClientType` method - -`ClientType` should return a unique string identifier of the light client. This will be used when generating a client identifier. -The format is created as follows: `ClientType-{N}` where `{N}` is the unique global nonce associated with a specific client. - -## `Validate` method - -`Validate` should validate every client state field and should return an error if any value is invalid. The light client -implementer is in charge of determining which checks are required. See the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/client_state.go#L111) as a reference. +# Implementing the `LightClientModule` interface ## `Status` method @@ -33,9 +21,9 @@ All possible `Status` types can be found [here](https://github.com/cosmos/ibc-go This field is returned in the response of the gRPC [`ibc.core.client.v1.Query/ClientStatus`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/types/query.pb.go#L665) endpoint. -## `GetTimestampAtHeight` method +## `TimestampAtHeight` method -`GetTimestampAtHeight` must return the timestamp for the consensus state associated with the provided height. +`TimestampAtHeight` must return the timestamp for the consensus state associated with the provided height. This value is used to facilitate timeouts by checking the packet timeout timestamp against the returned value. ## `Initialize` method diff --git a/docs/docs/03-light-clients/01-developer-guide/03-client-state.md b/docs/docs/03-light-clients/01-developer-guide/03-client-state.md new file mode 100644 index 00000000000..d5ba30ac8d5 --- /dev/null +++ b/docs/docs/03-light-clients/01-developer-guide/03-client-state.md @@ -0,0 +1,23 @@ +--- +title: Client State interface +sidebar_label: Client State interface +sidebar_position: 3 +slug: /ibc/light-clients/client-state +--- + + +# Implementing the `ClientState` interface + +Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface. This list of methods described here does not include all methods of the interface. Some methods are explained in detail in the relevant sections of the guide. + +## `ClientType` method + +`ClientType` should return a unique string identifier of the light client. This will be used when generating a client identifier. +The format is created as follows: `ClientType-{N}` where `{N}` is the unique global nonce associated with a specific client. + +## `Validate` method + +`Validate` should validate every client state field and should return an error if any value is invalid. The light client +implementer is in charge of determining which checks are required. See the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/client_state.go#L111) as a reference. + + diff --git a/docs/docs/03-light-clients/01-developer-guide/03-consensus-state.md b/docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md similarity index 96% rename from docs/docs/03-light-clients/01-developer-guide/03-consensus-state.md rename to docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md index a716a6477d7..cc54204d1dd 100644 --- a/docs/docs/03-light-clients/01-developer-guide/03-consensus-state.md +++ b/docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md @@ -1,7 +1,7 @@ --- title: Consensus State interface sidebar_label: Consensus State interface -sidebar_position: 3 +sidebar_position: 4 slug: /ibc/light-clients/consensus-state --- @@ -16,7 +16,7 @@ The below [`ConsensusState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/module ## `ClientType` method -This is the type of client consensus. It should be the same as the `ClientType` return value for the [corresponding `ClientState` implementation](02-client-state.md). +This is the type of client consensus. It should be the same as the `ClientType` return value for the [corresponding `ClientState` implementation](03-client-state.md). ## `GetTimestamp` method diff --git a/docs/docs/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md b/docs/docs/03-light-clients/01-developer-guide/05-updates-and-misbehaviour.md similarity index 97% rename from docs/docs/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md rename to docs/docs/03-light-clients/01-developer-guide/05-updates-and-misbehaviour.md index 776c442baed..b32d8b90087 100644 --- a/docs/docs/03-light-clients/01-developer-guide/04-updates-and-misbehaviour.md +++ b/docs/docs/03-light-clients/01-developer-guide/05-updates-and-misbehaviour.md @@ -1,14 +1,14 @@ --- title: Handling Updates and Misbehaviour sidebar_label: Handling Updates and Misbehaviour -sidebar_position: 4 +sidebar_position: 5 slug: /ibc/light-clients/updates-and-misbehaviour --- # Handling `ClientMessage`s: updates and misbehaviour -As mentioned before in the documentation about [implementing the `ConsensusState` interface](03-consensus-state.md), [`ClientMessage`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L147) is an interface used to update an IBC client. This update may be performed by: +As mentioned before in the documentation about [implementing the `ConsensusState` interface](04-consensus-state.md), [`ClientMessage`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L147) is an interface used to update an IBC client. This update may be performed by: - a single header - a batch of headers @@ -30,7 +30,7 @@ type ClientMessage interface { } ``` -The `ClientMessage` will be passed to the client to be used in [`UpdateClient`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L48), which retrieves the `ClientState` by client ID (available in `MsgUpdateClient`). This `ClientState` implements the [`ClientState` interface](02-client-state.md) for its specific consenus type (e.g. Tendermint). +The `ClientMessage` will be passed to the client to be used in [`UpdateClient`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L48), which retrieves the `ClientState` by client ID (available in `MsgUpdateClient`). This `ClientState` implements the [`ClientState` interface](03-client-state.md) for its specific consenus type (e.g. Tendermint). `UpdateClient` will then handle a number of cases including misbehaviour and/or updating the consensus state, utilizing the specific methods defined in the relevant `ClientState`. diff --git a/docs/docs/03-light-clients/01-developer-guide/05-upgrades.md b/docs/docs/03-light-clients/01-developer-guide/06-upgrades.md similarity index 99% rename from docs/docs/03-light-clients/01-developer-guide/05-upgrades.md rename to docs/docs/03-light-clients/01-developer-guide/06-upgrades.md index 10eb3ed5ce4..461e63703d1 100644 --- a/docs/docs/03-light-clients/01-developer-guide/05-upgrades.md +++ b/docs/docs/03-light-clients/01-developer-guide/06-upgrades.md @@ -1,7 +1,7 @@ --- title: Handling Upgrades sidebar_label: Handling Upgrades -sidebar_position: 5 +sidebar_position: 6 slug: /ibc/light-clients/upgrades --- diff --git a/docs/docs/03-light-clients/01-developer-guide/06-proofs.md b/docs/docs/03-light-clients/01-developer-guide/07-proofs.md similarity index 99% rename from docs/docs/03-light-clients/01-developer-guide/06-proofs.md rename to docs/docs/03-light-clients/01-developer-guide/07-proofs.md index 636e2b70e80..b6951842be0 100644 --- a/docs/docs/03-light-clients/01-developer-guide/06-proofs.md +++ b/docs/docs/03-light-clients/01-developer-guide/07-proofs.md @@ -1,7 +1,7 @@ --- title: Existence/Non-Existence Proofs sidebar_label: Existence/Non-Existence Proofs -sidebar_position: 6 +sidebar_position: 7 slug: /ibc/light-clients/proofs --- diff --git a/docs/docs/03-light-clients/01-developer-guide/07-proposals.md b/docs/docs/03-light-clients/01-developer-guide/08-proposals.md similarity index 99% rename from docs/docs/03-light-clients/01-developer-guide/07-proposals.md rename to docs/docs/03-light-clients/01-developer-guide/08-proposals.md index a5af1b4c705..579a9e372e4 100644 --- a/docs/docs/03-light-clients/01-developer-guide/07-proposals.md +++ b/docs/docs/03-light-clients/01-developer-guide/08-proposals.md @@ -1,7 +1,7 @@ --- title: Handling Proposals sidebar_label: Handling Proposals -sidebar_position: 7 +sidebar_position: 8 slug: /ibc/light-clients/proposals --- diff --git a/docs/docs/03-light-clients/01-developer-guide/08-setup.md b/docs/docs/03-light-clients/01-developer-guide/09-setup.md similarity index 99% rename from docs/docs/03-light-clients/01-developer-guide/08-setup.md rename to docs/docs/03-light-clients/01-developer-guide/09-setup.md index 3c55dc902a9..31481ea7642 100644 --- a/docs/docs/03-light-clients/01-developer-guide/08-setup.md +++ b/docs/docs/03-light-clients/01-developer-guide/09-setup.md @@ -1,7 +1,7 @@ --- title: Setup sidebar_label: Setup -sidebar_position: 8 +sidebar_position: 9 slug: /ibc/light-clients/setup --- diff --git a/docs/docs/03-light-clients/04-wasm/03-integration.md b/docs/docs/03-light-clients/04-wasm/03-integration.md index 7b7f3d7ef2f..882832c65ea 100644 --- a/docs/docs/03-light-clients/04-wasm/03-integration.md +++ b/docs/docs/03-light-clients/04-wasm/03-integration.md @@ -353,7 +353,7 @@ func CreateWasmUpgradeHandler( } ``` -Or alternatively the parameter can be updated via a governance proposal (see at the bottom of section [`Creating clients`](../01-developer-guide/08-setup.md#creating-clients) for an example of how to do this). +Or alternatively the parameter can be updated via a governance proposal (see at the bottom of section [`Creating clients`](../01-developer-guide/09-setup.md#creating-clients) for an example of how to do this). ## Adding the module to the store diff --git a/docs/docs/03-light-clients/04-wasm/07-contracts.md b/docs/docs/03-light-clients/04-wasm/07-contracts.md index b73978a184d..7e88309124b 100644 --- a/docs/docs/03-light-clients/04-wasm/07-contracts.md +++ b/docs/docs/03-light-clients/04-wasm/07-contracts.md @@ -52,10 +52,10 @@ pub enum QueryMsg { To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponding section of the [Light client developer guide](../01-developer-guide/01-overview.md): -- For `StatusMsg`, see the section [`Status` method](../01-developer-guide/02-client-state.md#status-method). -- For `TimestampAtHeightMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/02-client-state.md#gettimestampatheight-method). -- For `VerifyClientMessageMsg`, see the section [`VerifyClientMessage`](../01-developer-guide/04-updates-and-misbehaviour.md#verifyclientmessage). -- For `CheckForMisbehaviourMsg`, see the section [`CheckForMisbehaviour` method](../01-developer-guide/02-client-state.md#checkformisbehaviour-method). +- For `StatusMsg`, see the section [`Status` method](../01-developer-guide/03-client-state.md#status-method). +- For `TimestampAtHeightMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/03-client-state.md#gettimestampatheight-method). +- For `VerifyClientMessageMsg`, see the section [`VerifyClientMessage`](../01-developer-guide/05-updates-and-misbehaviour.md#verifyclientmessage). +- For `CheckForMisbehaviourMsg`, see the section [`CheckForMisbehaviour` method](../01-developer-guide/03-client-state.md#checkformisbehaviour-method). ## `SudoMsg` @@ -88,12 +88,12 @@ pub enum SudoMsg { To learn what it is expected from the Wasm light client contract when processing each message, please read the corresponding section of the [Light client developer guide](../01-developer-guide/01-overview.md): -- For `UpdateStateMsg`, see the section [`UpdateState`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestate). -- For `UpdateStateOnMisbehaviourMsg`, see the section [`UpdateStateOnMisbehaviour`](../01-developer-guide/04-updates-and-misbehaviour.md#updatestateonmisbehaviour). -- For `VerifyUpgradeAndUpdateStateMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/05-upgrades.md#implementing-verifyupgradeandupdatestate). -- For `VerifyMembershipMsg`, see the section [`VerifyMembership` method](../01-developer-guide/02-client-state.md#verifymembership-method). -- For `VerifyNonMembershipMsg`, see the section [`VerifyNonMembership` method](../01-developer-guide/02-client-state.md#verifynonmembership-method). -- For `MigrateClientStoreMsg`, see the section [Implementing `CheckSubstituteAndUpdateState`](../01-developer-guide/07-proposals.md#implementing-checksubstituteandupdatestate). +- For `UpdateStateMsg`, see the section [`UpdateState`](../01-developer-guide/05-updates-and-misbehaviour.md#updatestate). +- For `UpdateStateOnMisbehaviourMsg`, see the section [`UpdateStateOnMisbehaviour`](../01-developer-guide/05-updates-and-misbehaviour.md#updatestateonmisbehaviour). +- For `VerifyUpgradeAndUpdateStateMsg`, see the section [`GetTimestampAtHeight` method](../01-developer-guide/06-upgrades.md#implementing-verifyupgradeandupdatestate). +- For `VerifyMembershipMsg`, see the section [`VerifyMembership` method](../01-developer-guide/03-client-state.md#verifymembership-method). +- For `VerifyNonMembershipMsg`, see the section [`VerifyNonMembership` method](../01-developer-guide/03-client-state.md#verifynonmembership-method). +- For `MigrateClientStoreMsg`, see the section [Implementing `CheckSubstituteAndUpdateState`](../01-developer-guide/08-proposals.md#implementing-checksubstituteandupdatestate). ### Migration diff --git a/docs/docs/05-migrations/02-sdk-to-v1.md b/docs/docs/05-migrations/02-sdk-to-v1.md index 88022435f64..3cd667b86aa 100644 --- a/docs/docs/05-migrations/02-sdk-to-v1.md +++ b/docs/docs/05-migrations/02-sdk-to-v1.md @@ -112,7 +112,7 @@ app.IBCKeeper = ibckeeper.NewKeeper( ### UpdateClientProposal -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/07-proposals.md) for more information. +The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/08-proposals.md) for more information. ### UpgradeProposal From 63ec69ce9ba0efa47860af57d3af4f4711798508 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Mon, 11 Mar 2024 18:02:06 +0100 Subject: [PATCH 46/74] imp: cleanup godoc on router type --- modules/core/02-client/types/router.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index cfb37584ca1..ffe1b599468 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -8,13 +8,16 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// The router is a map from module name to the LightClientModule -// which contains all the module-defined callbacks required by ICS-26 +// Router is a map from a light client module name to a LightClientModule. +// The light client module name must be the same name as the client type. +// The router also has a reference to the client store provided (02-client keeper) +// and will set the store provider on a client module upon route registration. type Router struct { routes map[string]exported.LightClientModule storeProvider exported.ClientStoreProvider } +// NewRouter returns a instance of the Router. func NewRouter(key storetypes.StoreKey) *Router { return &Router{ routes: make(map[string]exported.LightClientModule), @@ -24,6 +27,7 @@ func NewRouter(key storetypes.StoreKey) *Router { // AddRoute adds LightClientModule for a given module name. It returns the Router // so AddRoute calls can be linked. It will panic if the Router is sealed. +// The store provider will be registered on the light client module. func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule) *Router { if rtr.HasRoute(clientType) { panic(fmt.Errorf("route %s has already been registered", module)) @@ -36,8 +40,8 @@ func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule } // HasRoute returns true if the Router has a module registered or false otherwise. -func (rtr *Router) HasRoute(module string) bool { - _, ok := rtr.routes[module] +func (rtr *Router) HasRoute(clientType string) bool { + _, ok := rtr.routes[clientType] return ok } From b6d07a555185f0fd4ae505ee5e1015eab7b48dcd Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Tue, 12 Mar 2024 15:47:06 +0100 Subject: [PATCH 47/74] 02-client routing: implement `VerifyUpgradeAndUpdateState` in light client modules (#5827) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * wip: implementation and tests for verify upgrade and update state function in light client modules * add test case * fix un-marshaling in tendermint light client module * add tests for verify upgrade and update state of 08-wasm light client module * fix linter warnings * check client state post upgrade * fix: encoding issue: unmarshal to concrete types and not interfaces in 07-tendermint * fix import * cast type before calling zero custom fields * test: marshal concrete types using chain codec for upgrade tests which bypass msg server entrypoint * chore: remove basic validation of lc types in tm VerifyUpgradeAndUpdateState * marshal to concrete type in tests * keep client/consensus state as interface marshalled * Apply suggestions from code review Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> * chore: make lint-fix * chore: rm redundant test, tested in lightclient module * fix: remove marshalling of anys to bytes for verify upgrade (#5967) * fix: remove marshalling of anys to bytes for verify upgrade * test: refactor 02-client tests for verify upgrade * test: fix tests in 07-tenderint client module * chore: rm backwards compatability notice and marshalling of anys in core msg server * test: cleanup happy path assertions in 07-tendermint verify upgrade test * nit: update inline code commentin test * doc: update godoc of UpgradeClient handler in core ibc * lint: make lint-fix * nit: inline comments in tests last Height -> upgrade height * fix: address 08-wasm upgrade client and tests --------- Co-authored-by: Damian Nolan Co-authored-by: colin axnér <25233464+colin-axner@users.noreply.github.com> --- modules/core/02-client/keeper/client.go | 38 ++-- modules/core/02-client/keeper/client_test.go | 131 +++++------- modules/core/exported/client.go | 18 -- modules/core/keeper/msg_server.go | 23 +-- modules/core/keeper/msg_server_test.go | 3 +- .../06-solomachine/client_state.go | 8 - .../06-solomachine/light_client_module.go | 11 +- .../light_client_module_test.go | 12 ++ .../07-tendermint/light_client_module.go | 39 ++-- .../07-tendermint/light_client_module_test.go | 174 ++++++++++++++++ .../light-clients/07-tendermint/upgrade.go | 1 + .../07-tendermint/upgrade_test.go | 2 +- .../08-wasm/light_client_module.go | 36 +++- .../08-wasm/light_client_module_test.go | 186 ++++++++++++++++++ .../09-localhost/client_state.go | 13 -- .../09-localhost/client_state_test.go | 6 - .../09-localhost/light_client_module_test.go | 10 + 17 files changed, 533 insertions(+), 178 deletions(-) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index b47d75b260d..58c7c7cc500 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -122,48 +122,42 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte // UpgradeClient upgrades the client to a new client state if this new client was committed to // by the old client at the specified upgrade height -func (k Keeper) UpgradeClient(ctx sdk.Context, clientID string, upgradedClient exported.ClientState, upgradedConsState exported.ConsensusState, - upgradeClientProof, upgradeConsensusStateProof []byte, +func (k Keeper) UpgradeClient( + ctx sdk.Context, + clientID string, + upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof []byte, ) error { - clientState, found := k.GetClientState(ctx, clientID) - if !found { - return errorsmod.Wrapf(types.ErrClientNotFound, "cannot update client with ID %s", clientID) - } - - clientStore := k.ClientStore(ctx, clientID) - if status := k.GetClientStatus(ctx, clientID); status != exported.Active { return errorsmod.Wrapf(types.ErrClientNotActive, "cannot upgrade client (%s) with status %s", clientID, status) } - // TODO: This code is removed in https://github.com/cosmos/ibc-go/pull/5827 - // last height of current counterparty chain must be client's latest height - // lastHeight := k.GetLatestHeight(ctx, clientID) + clientType, _, err := types.ParseClientIdentifier(clientID) + if err != nil { + return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) + } - // if !upgradedClient.GetLatestHeight().GT(lastHeight) { - // return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", - // upgradedClient.GetLatestHeight(), lastHeight) - // } + clientModule, found := k.router.GetRoute(clientID) + if !found { + return errorsmod.Wrap(types.ErrRouteNotFound, clientID) + } - if err := clientState.VerifyUpgradeAndUpdateState(ctx, k.cdc, clientStore, - upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof, - ); err != nil { + if err := clientModule.VerifyUpgradeAndUpdateState(ctx, clientID, upgradedClient, upgradedConsState, upgradeClientProof, upgradeConsensusStateProof); err != nil { return errorsmod.Wrapf(err, "cannot upgrade client with ID %s", clientID) } - latestHeight := k.GetLatestHeight(ctx, clientID) // TODO: use clientModule when addressing this func in https://github.com/cosmos/ibc-go/pull/5827 + latestHeight := clientModule.LatestHeight(ctx, clientID) k.Logger(ctx).Info("client state upgraded", "client-id", clientID, "height", latestHeight.String()) defer telemetry.IncrCounterWithLabels( []string{"ibc", "client", "upgrade"}, 1, []metrics.Label{ - telemetry.NewLabel(types.LabelClientType, upgradedClient.ClientType()), + telemetry.NewLabel(types.LabelClientType, clientType), telemetry.NewLabel(types.LabelClientID, clientID), }, ) - emitUpgradeClientEvent(ctx, clientID, upgradedClient.ClientType(), latestHeight) + emitUpgradeClientEvent(ctx, clientID, clientType, latestHeight) return nil } diff --git a/modules/core/02-client/keeper/client_test.go b/modules/core/02-client/keeper/client_test.go index 31e0589acdb..446fe195f03 100644 --- a/modules/core/02-client/keeper/client_test.go +++ b/modules/core/02-client/keeper/client_test.go @@ -6,6 +6,7 @@ import ( upgradetypes "cosmossdk.io/x/upgrade/types" + codectypes "github.com/cosmos/cosmos-sdk/codec/types" sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" @@ -321,9 +322,9 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { path *ibctesting.Path upgradedClient *ibctm.ClientState upgradedConsState exported.ConsensusState - lastHeight exported.Height + upgradeHeight exported.Height + upgradedClientAny, upgradedConsStateAny *codectypes.Any upgradedClientProof, upgradedConsensusStateProof []byte - upgradedClientBz, upgradedConsStateBz []byte ) testCases := []struct { @@ -334,13 +335,13 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { { name: "successful upgrade", setup: func() { - // last Height is at next block - lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) + // upgrade Height is at next block + upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny)) suite.Require().NoError(err) - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny)) suite.Require().NoError(err) // commit upgrade store changes and update clients @@ -353,21 +354,21 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, expPass: true, }, { name: "client state not found", setup: func() { - // last Height is at next block - lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) + // upgrade height is at next block + upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny)) suite.Require().NoError(err) - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny)) suite.Require().NoError(err) // commit upgrade store changes and update clients @@ -381,8 +382,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) path.EndpointA.ClientID = "wrongclientid" }, @@ -393,17 +394,16 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { setup: func() { // client is frozen - // last Height is at next block - lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) + // upgrade height is at next block + upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny)) suite.Require().NoError(err) - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny)) suite.Require().NoError(err) // commit upgrade store changes and update clients - suite.coordinator.CommitBlock(suite.chainB) err = path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -413,8 +413,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) // set frozen client in store tmClient, ok := cs.(*ibctm.ClientState) @@ -425,49 +425,22 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { expPass: false, }, { - name: "tendermint client VerifyUpgrade fails", + name: "light client module VerifyUpgradeAndUpdateState fails", setup: func() { - // last Height is at next block - lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) + // upgrade height is at next block + upgradeHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) // zero custom fields and store in upgrade store - err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedClientBz) + err := suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedClient(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedClientAny)) suite.Require().NoError(err) - err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(lastHeight.GetRevisionHeight()), upgradedConsStateBz) + err = suite.chainB.GetSimApp().UpgradeKeeper.SetUpgradedConsensusState(suite.chainB.GetContext(), int64(upgradeHeight.GetRevisionHeight()), suite.chainB.Codec.MustMarshal(upgradedConsStateAny)) suite.Require().NoError(err) // change upgradedClient client-specified parameters upgradedClient.ChainId = "wrongchainID" - - suite.coordinator.CommitBlock(suite.chainB) - err = path.EndpointA.UpdateClient() + upgradedClientAny, err = codectypes.NewAnyWithValue(upgradedClient) 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()) - }, - expPass: false, - }, - { - name: "unsuccessful upgrade: upgraded height is not greater than current height", - setup: func() { - // last Height is at next block - lastHeight = clienttypes.NewHeight(1, uint64(suite.chainB.GetContext().BlockHeight()+1)) - - // zero custom fields and store in upgrade store - 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 height to be lower than current client state height - upgradedClient.LatestHeight = clienttypes.NewHeight(0, 1) - suite.coordinator.CommitBlock(suite.chainB) err = path.EndpointA.UpdateClient() suite.Require().NoError(err) @@ -477,8 +450,8 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { 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()) + upgradedClientProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedClientKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) + upgradedConsensusStateProof, _ = suite.chainB.QueryUpgradeProof(upgradetypes.UpgradedConsStateKey(int64(upgradeHeight.GetRevisionHeight())), tmCs.LatestHeight.GetRevisionHeight()) }, expPass: false, }, @@ -486,35 +459,37 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { for _, tc := range testCases { tc := tc - path = ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupClients() + suite.Run(tc.name, func() { + path = ibctesting.NewPath(suite.chainA, suite.chainB) + path.SetupClients() - clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) - revisionNumber := clienttypes.ParseChainID(clientState.ChainId) + clientState := path.EndpointA.GetClientState().(*ibctm.ClientState) + revisionNumber := clienttypes.ParseChainID(clientState.ChainId) - newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) - suite.Require().NoError(err) + newChainID, err := clienttypes.SetRevisionNumber(clientState.ChainId, revisionNumber+1) + suite.Require().NoError(err) - upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) - upgradedClient = upgradedClient.ZeroCustomFields() - upgradedClientBz, err = clienttypes.MarshalClientState(suite.chainA.App.AppCodec(), upgradedClient) - suite.Require().NoError(err) + upgradedClient = ibctm.NewClientState(newChainID, ibctm.DefaultTrustLevel, trustingPeriod, ubdPeriod+trustingPeriod, maxClockDrift, clienttypes.NewHeight(revisionNumber+1, clientState.LatestHeight.GetRevisionHeight()+1), commitmenttypes.GetSDKSpecs(), ibctesting.UpgradePath) + upgradedClient = upgradedClient.ZeroCustomFields() - upgradedConsState = &ibctm.ConsensusState{ - NextValidatorsHash: []byte("nextValsHash"), - } - upgradedConsStateBz, err = clienttypes.MarshalConsensusState(suite.chainA.App.AppCodec(), upgradedConsState) - suite.Require().NoError(err) + upgradedClientAny, err = codectypes.NewAnyWithValue(upgradedClient) + suite.Require().NoError(err) + + upgradedConsState = &ibctm.ConsensusState{NextValidatorsHash: []byte("nextValsHash")} + + upgradedConsStateAny, err = codectypes.NewAnyWithValue(upgradedConsState) + suite.Require().NoError(err) - tc.setup() + tc.setup() - err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClient, upgradedConsState, upgradedClientProof, upgradedConsensusStateProof) + err = suite.chainA.App.GetIBCKeeper().ClientKeeper.UpgradeClient(suite.chainA.GetContext(), path.EndpointA.ClientID, upgradedClientAny.Value, upgradedConsStateAny.Value, upgradedClientProof, upgradedConsensusStateProof) - if tc.expPass { - suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) - } else { - suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) - } + if tc.expPass { + suite.Require().NoError(err, "verify upgrade failed on valid case: %s", tc.name) + } else { + suite.Require().Error(err, "verify upgrade passed on invalid case: %s", tc.name) + } + }) } } diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 6c12d00a818..482ee6ff75d 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -5,7 +5,6 @@ import ( storetypes "cosmossdk.io/store/types" - "github.com/cosmos/cosmos-sdk/codec" sdk "github.com/cosmos/cosmos-sdk/types" ) @@ -141,23 +140,6 @@ type ClientState interface { ClientType() string Validate() error - - // Upgrade functions - // NOTE: proof heights are not included as upgrade to a new revision is expected to pass only on the last - // height committed by the current revision. Clients are responsible for ensuring that the planned last - // height of the current revision is somehow encoded in the proof verification process. - // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty - // may be cancelled or modified before the last planned height. - // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. - VerifyUpgradeAndUpdateState( - ctx sdk.Context, - cdc codec.BinaryCodec, - store storetypes.KVStore, - newClient ClientState, - newConsState ConsensusState, - upgradeClientProof, - upgradeConsensusStateProof []byte, - ) error } // ConsensusState is the state of the consensus process diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 14c23704752..75119959f54 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -67,20 +67,21 @@ func (k Keeper) UpdateClient(goCtx context.Context, msg *clienttypes.MsgUpdateCl } // UpgradeClient defines a rpc handler method for MsgUpgradeClient. +// NOTE: The raw bytes of the conretes types encoded into protobuf.Any is passed to the client keeper. +// The 02-client handler will route to the appropriate light client module based on client identifier and it is the responsibility +// of the light client module to unmarshal and interpret the proto encoded bytes. +// Backwards compatibility with older versions of ibc-go is maintained through the light client module reconstructing and encoding +// the expected concrete type to the protobuf.Any for proof verification. func (k Keeper) UpgradeClient(goCtx context.Context, msg *clienttypes.MsgUpgradeClient) (*clienttypes.MsgUpgradeClientResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) - upgradedClient, err := clienttypes.UnpackClientState(msg.ClientState) - if err != nil { - return nil, err - } - upgradedConsState, err := clienttypes.UnpackConsensusState(msg.ConsensusState) - if err != nil { - return nil, err - } - - if err = k.ClientKeeper.UpgradeClient(ctx, msg.ClientId, upgradedClient, upgradedConsState, - msg.ProofUpgradeClient, msg.ProofUpgradeConsensusState); err != nil { + if err := k.ClientKeeper.UpgradeClient( + ctx, msg.ClientId, + msg.ClientState.Value, + msg.ConsensusState.Value, + msg.ProofUpgradeClient, + msg.ProofUpgradeConsensusState, + ); err != nil { return nil, err } diff --git a/modules/core/keeper/msg_server_test.go b/modules/core/keeper/msg_server_test.go index 2749af00fd9..dd9c21cb30b 100644 --- a/modules/core/keeper/msg_server_test.go +++ b/modules/core/keeper/msg_server_test.go @@ -881,7 +881,7 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { tc.setup() ctx := suite.chainA.GetContext() - _, err = keeper.Keeper.UpgradeClient(*suite.chainA.App.GetIBCKeeper(), ctx, msg) + _, err = suite.chainA.GetSimApp().GetIBCKeeper().UpgradeClient(ctx, msg) if tc.expPass { suite.Require().NoError(err, "upgrade handler failed on valid case: %s", tc.name) @@ -901,7 +901,6 @@ func (suite *KeeperTestSuite) TestUpgradeClient() { expectedEvents = sdk.MarkEventsToIndex(expectedEvents, map[string]struct{}{}) ibctesting.AssertEvents(&suite.Suite, expectedEvents, ctx.EventManager().Events().ToABCIEvents()) - } else { suite.Require().Error(err, "upgrade handler passed on invalid case: %s", tc.name) } diff --git a/modules/light-clients/06-solomachine/client_state.go b/modules/light-clients/06-solomachine/client_state.go index 6d57baa497e..24335d0287f 100644 --- a/modules/light-clients/06-solomachine/client_state.go +++ b/modules/light-clients/06-solomachine/client_state.go @@ -80,14 +80,6 @@ func (cs ClientState) Initialize(_ sdk.Context, cdc codec.BinaryCodec, clientSto return nil } -// VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades -func (ClientState) VerifyUpgradeAndUpdateState( - _ sdk.Context, _ codec.BinaryCodec, _ storetypes.KVStore, - _ exported.ClientState, _ exported.ConsensusState, _, _ []byte, -) error { - return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") -} - // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the latest sequence. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). func (cs *ClientState) VerifyMembership( diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index b8cfb28b62d..651302c0f47 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -235,6 +235,13 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute // VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { - return nil +func (LightClientModule) VerifyUpgradeAndUpdateState( + ctx sdk.Context, + clientID string, + newClient []byte, + newConsState []byte, + upgradeClientProof, + upgradeConsensusStateProof []byte, +) error { + return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") } diff --git a/modules/light-clients/06-solomachine/light_client_module_test.go b/modules/light-clients/06-solomachine/light_client_module_test.go index 7127199f837..a7d10aa3137 100644 --- a/modules/light-clients/06-solomachine/light_client_module_test.go +++ b/modules/light-clients/06-solomachine/light_client_module_test.go @@ -110,3 +110,15 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { }) } } + +func (suite *SoloMachineTestSuite) TestVerifyUpgradeAndUpdateState() { + suite.SetupTest() + + clientID := suite.chainA.App.GetIBCKeeper().ClientKeeper.GenerateClientIdentifier(suite.chainA.GetContext(), exported.Solomachine) + + lightClientModule, found := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(clientID) + suite.Require().True(found) + + err := lightClientModule.VerifyUpgradeAndUpdateState(suite.chainA.GetContext(), clientID, nil, nil, nil, nil) + suite.Require().Error(err) +} diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 15baba26982..669876cbafd 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -7,6 +7,7 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint/internal/keeper" ) @@ -255,8 +256,17 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } -// VerifyUpgradeAndUpdateState, on a successful verification expects the contract to update -// the new client state, consensus state, and any other client metadata. +// VerifyUpgradeAndUpdateState checks if the upgraded client has been committed by the current client +// It will zero out all client-specific fields (e.g. TrustingPeriod) and verify all data +// in client state that must be the same across all valid Tendermint clients for the new chain. +// VerifyUpgrade will return an error if: +// - the upgradedClient is not a Tendermint ClientState +// - the latest height of the client state does not have the same revision number or has a greater +// height than the committed client. +// - the height of upgraded client is not greater than that of current client +// - the latest height of the new client does not match or is greater than the height in committed client +// - any Tendermint chain specified parameter in upgraded client such as ChainID, UnbondingPeriod, +// and ProofSpecs do not match parameters set by committed client // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (lcm LightClientModule) VerifyUpgradeAndUpdateState( @@ -267,30 +277,29 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( upgradeClientProof, upgradeConsensusStateProof []byte, ) error { - var newClientState ClientState - if err := lcm.keeper.Codec().Unmarshal(newClient, &newClientState); err != nil { - return err - } + cdc := lcm.keeper.Codec() - if err := newClientState.Validate(); err != nil { - return err + var newClientState ClientState + if err := cdc.Unmarshal(newClient, &newClientState); err != nil { + return errorsmod.Wrap(clienttypes.ErrInvalidClient, err.Error()) } var newConsensusState ConsensusState - if err := lcm.keeper.Codec().Unmarshal(newConsState, &newConsensusState); err != nil { - return err - } - if err := newConsensusState.ValidateBasic(); err != nil { - return err + if err := cdc.Unmarshal(newConsState, &newConsensusState); err != nil { + return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, err.Error()) } clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() - clientState, found := getClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } + // last height of current counterparty chain must be client's latest height + lastHeight := clientState.LatestHeight + if !newClientState.LatestHeight.GT(lastHeight) { + return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", newClientState.LatestHeight, lastHeight) + } + return clientState.VerifyUpgradeAndUpdateState(ctx, cdc, clientStore, &newClientState, &newConsensusState, upgradeClientProof, upgradeConsensusStateProof) } 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 08a638c6d87..4dd646eae3e 100644 --- a/modules/light-clients/07-tendermint/light_client_module_test.go +++ b/modules/light-clients/07-tendermint/light_client_module_test.go @@ -1,8 +1,17 @@ package tendermint_test import ( + "crypto/sha256" + "time" + + upgradetypes "cosmossdk.io/x/upgrade/types" + + codectypes "github.com/cosmos/cosmos-sdk/codec/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" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" @@ -102,3 +111,168 @@ func (suite *TendermintTestSuite) TestRecoverClient() { }) } } + +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 := upgradedClientState.(*ibctm.ClientState) + + newLatestheight, ok := path.EndpointA.GetClientLatestHeight().Decrement() + suite.Require().True(ok) + + tmClient.LatestHeight = newLatestheight.(clienttypes.Height) + 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 := path.EndpointA.GetClientState().(*ibctm.ClientState) + 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.GetRouter().GetRoute(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/upgrade.go b/modules/light-clients/07-tendermint/upgrade.go index be19cffda9a..ef62e707795 100644 --- a/modules/light-clients/07-tendermint/upgrade.go +++ b/modules/light-clients/07-tendermint/upgrade.go @@ -43,6 +43,7 @@ func (cs ClientState) VerifyUpgradeAndUpdateState( return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "upgraded client must be Tendermint client. expected: %T got: %T", &ClientState{}, upgradedClient) } + tmUpgradeConsState, ok := upgradedConsState.(*ConsensusState) if !ok { return errorsmod.Wrapf(clienttypes.ErrInvalidConsensus, "upgraded consensus state must be Tendermint consensus state. expected %T, got: %T", diff --git a/modules/light-clients/07-tendermint/upgrade_test.go b/modules/light-clients/07-tendermint/upgrade_test.go index 4b2a848a09c..4715aad3961 100644 --- a/modules/light-clients/07-tendermint/upgrade_test.go +++ b/modules/light-clients/07-tendermint/upgrade_test.go @@ -489,7 +489,7 @@ func (suite *TendermintTestSuite) TestVerifyUpgrade() { tc.setup() - cs := suite.chainA.GetClientState(path.EndpointA.ClientID) + cs := suite.chainA.GetClientState(path.EndpointA.ClientID).(*ibctm.ClientState) 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 diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 4f31048421f..589215ae472 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -8,6 +8,7 @@ import ( wasmkeeper "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/keeper" "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/types" clienttypes "github.com/cosmos/ibc-go/v8/modules/core/02-client/types" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" "github.com/cosmos/ibc-go/v8/modules/core/exported" ) @@ -257,6 +258,37 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute // the new client state, consensus state, and any other client metadata. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient []byte, newConsState []byte, upgradeClientProof, upgradeConsensusStateProof []byte) error { - return nil +func (lcm LightClientModule) VerifyUpgradeAndUpdateState( + ctx sdk.Context, + clientID string, + newClient []byte, + newConsState []byte, + upgradeClientProof, + upgradeConsensusStateProof []byte, +) error { + cdc := lcm.keeper.Codec() + + var newClientState types.ClientState + if err := cdc.Unmarshal(newClient, &newClientState); err != nil { + return errorsmod.Wrap(clienttypes.ErrInvalidClient, err.Error()) + } + + var newConsensusState types.ConsensusState + if err := cdc.Unmarshal(newConsState, &newConsensusState); err != nil { + return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, err.Error()) + } + + clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientState, found := types.GetClientState(clientStore, cdc) + if !found { + return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) + } + + // last height of current counterparty chain must be client's latest height + lastHeight := clientState.LatestHeight + if !newClientState.LatestHeight.GT(lastHeight) { + return errorsmod.Wrapf(ibcerrors.ErrInvalidHeight, "upgraded client height %s must be at greater than current client height %s", newClientState.LatestHeight, lastHeight) + } + + return clientState.VerifyUpgradeAndUpdateState(ctx, cdc, clientStore, &newClientState, &newConsensusState, upgradeClientProof, upgradeConsensusStateProof) } diff --git a/modules/light-clients/08-wasm/light_client_module_test.go b/modules/light-clients/08-wasm/light_client_module_test.go index ca9d665797f..e1c969fc5aa 100644 --- a/modules/light-clients/08-wasm/light_client_module_test.go +++ b/modules/light-clients/08-wasm/light_client_module_test.go @@ -1,9 +1,22 @@ package wasm_test import ( + "encoding/json" + "time" + + wasmvm "github.com/CosmWasm/wasmvm" + wasmvmtypes "github.com/CosmWasm/wasmvm/types" + + codectypes "github.com/cosmos/cosmos-sdk/codec/types" + wasmtesting "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/testing" + "github.com/cosmos/ibc-go/modules/light-clients/08-wasm/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" host "github.com/cosmos/ibc-go/v8/modules/core/24-host" + ibcerrors "github.com/cosmos/ibc-go/v8/modules/core/errors" + "github.com/cosmos/ibc-go/v8/modules/core/exported" + ibctm "github.com/cosmos/ibc-go/v8/modules/light-clients/07-tendermint" ibctesting "github.com/cosmos/ibc-go/v8/testing" ) @@ -97,3 +110,176 @@ func (suite *WasmTestSuite) TestRecoverClient() { }) } } + +func (suite *WasmTestSuite) TestVerifyUpgradeAndUpdateState() { + var ( + clientID string + clientState *types.ClientState + upgradedClientState exported.ClientState + upgradedConsensusState exported.ConsensusState + upgradedClientStateAny, upgradedConsensusStateAny *codectypes.Any + upgradedClientStateProof, upgradedConsensusStateProof []byte + ) + + testCases := []struct { + name string + malleate func() + expErr error + }{ + { + "success", + func() { + suite.mockVM.RegisterSudoCallback(types.VerifyUpgradeAndUpdateStateMsg{}, func(_ wasmvm.Checksum, _ wasmvmtypes.Env, sudoMsg []byte, store wasmvm.KVStore, _ wasmvm.GoAPI, _ wasmvm.Querier, _ wasmvm.GasMeter, _ uint64, _ wasmvmtypes.UFraction) (*wasmvmtypes.Response, uint64, error) { + var payload types.SudoMsg + + err := json.Unmarshal(sudoMsg, &payload) + suite.Require().NoError(err) + + expectedUpgradedClient, ok := upgradedClientState.(*types.ClientState) + suite.Require().True(ok) + expectedUpgradedConsensus, ok := upgradedConsensusState.(*types.ConsensusState) + suite.Require().True(ok) + + // verify payload values + suite.Require().Equal(expectedUpgradedClient.Data, payload.VerifyUpgradeAndUpdateState.UpgradeClientState) + suite.Require().Equal(expectedUpgradedConsensus.Data, payload.VerifyUpgradeAndUpdateState.UpgradeConsensusState) + suite.Require().Equal(upgradedClientStateProof, payload.VerifyUpgradeAndUpdateState.ProofUpgradeClient) + suite.Require().Equal(upgradedConsensusStateProof, payload.VerifyUpgradeAndUpdateState.ProofUpgradeConsensusState) + + // verify other Sudo fields are nil + suite.Require().Nil(payload.UpdateState) + suite.Require().Nil(payload.UpdateStateOnMisbehaviour) + suite.Require().Nil(payload.VerifyMembership) + suite.Require().Nil(payload.VerifyNonMembership) + + data, err := json.Marshal(types.EmptyResult{}) + suite.Require().NoError(err) + + // set new client state and consensus state + bz, err := suite.chainA.Codec.MarshalInterface(upgradedClientState) + suite.Require().NoError(err) + + store.Set(host.ClientStateKey(), bz) + + bz, err = suite.chainA.Codec.MarshalInterface(upgradedConsensusState) + suite.Require().NoError(err) + + store.Set(host.ConsensusStateKey(expectedUpgradedClient.LatestHeight), bz) + + return &wasmvmtypes.Response{Data: data}, wasmtesting.DefaultGasUsed, nil + }) + }, + nil, + }, + { + "cannot find client state", + func() { + clientID = wasmClientID + }, + clienttypes.ErrClientNotFound, + }, + { + "upgraded client state is not wasm client state", + func() { + upgradedClientStateAny = &codectypes.Any{ + Value: []byte("invalid client state bytes"), + } + }, + clienttypes.ErrInvalidClient, + }, + { + "upgraded consensus state is not wasm consensus sate", + func() { + upgradedConsensusStateAny = &codectypes.Any{ + Value: []byte("invalid consensus state bytes"), + } + }, + clienttypes.ErrInvalidConsensus, + }, + { + "upgraded client state height is not greater than current height", + func() { + var err error + latestHeight := clientState.LatestHeight + newLatestHeight := clienttypes.NewHeight(latestHeight.GetRevisionNumber(), latestHeight.GetRevisionHeight()-1) + + wrappedUpgradedClient := wasmtesting.CreateMockTendermintClientState(newLatestHeight) + wrappedUpgradedClientBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), wrappedUpgradedClient) + upgradedClientState = types.NewClientState(wrappedUpgradedClientBz, clientState.Checksum, newLatestHeight) + upgradedClientStateAny, err = codectypes.NewAnyWithValue(upgradedClientState) + suite.Require().NoError(err) + }, + ibcerrors.ErrInvalidHeight, + }, + } + + for _, tc := range testCases { + tc := tc + suite.Run(tc.name, func() { + suite.SetupWasmWithMockVM() // reset suite + + endpoint := wasmtesting.NewWasmEndpoint(suite.chainA) + err := endpoint.CreateClient() + suite.Require().NoError(err) + clientID = endpoint.ClientID + + clientState = endpoint.GetClientState().(*types.ClientState) + latestHeight := clientState.LatestHeight + + newLatestHeight := clienttypes.NewHeight(latestHeight.GetRevisionNumber(), latestHeight.GetRevisionHeight()+1) + wrappedUpgradedClient := wasmtesting.CreateMockTendermintClientState(newLatestHeight) + wrappedUpgradedClientBz := clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), wrappedUpgradedClient) + upgradedClientState = types.NewClientState(wrappedUpgradedClientBz, clientState.Checksum, newLatestHeight) + upgradedClientStateAny, err = codectypes.NewAnyWithValue(upgradedClientState) + suite.Require().NoError(err) + + wrappedUpgradedConsensus := ibctm.NewConsensusState(time.Now(), commitmenttypes.NewMerkleRoot([]byte("new-hash")), []byte("new-nextValsHash")) + wrappedUpgradedConsensusBz := clienttypes.MustMarshalConsensusState(suite.chainA.App.AppCodec(), wrappedUpgradedConsensus) + upgradedConsensusState = types.NewConsensusState(wrappedUpgradedConsensusBz) + upgradedConsensusStateAny, err = codectypes.NewAnyWithValue(upgradedConsensusState) + suite.Require().NoError(err) + + lightClientModule, found := suite.chainA.App.GetIBCKeeper().ClientKeeper.GetRouter().GetRoute(clientID) + suite.Require().True(found) + + tc.malleate() + + clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), clientID) + + upgradedClientStateProof = wasmtesting.MockUpgradedClientStateProofBz + upgradedConsensusStateProof = wasmtesting.MockUpgradedConsensusStateProofBz + + err = lightClientModule.VerifyUpgradeAndUpdateState( + suite.chainA.GetContext(), + clientID, + upgradedClientStateAny.Value, + upgradedConsensusStateAny.Value, + upgradedClientStateProof, + upgradedConsensusStateProof, + ) + + expPass := tc.expErr == nil + if expPass { + suite.Require().NoError(err) + + // verify new client state and consensus state + clientStateBz := clientStore.Get(host.ClientStateKey()) + suite.Require().NotEmpty(clientStateBz) + + expClientStateBz, err := suite.chainA.Codec.MarshalInterface(upgradedClientState) + suite.Require().NoError(err) + suite.Require().Equal(expClientStateBz, clientStateBz) + + consensusStateBz := clientStore.Get(host.ConsensusStateKey(endpoint.GetClientLatestHeight())) + suite.Require().NotEmpty(consensusStateBz) + + expConsensusStateBz, err := suite.chainA.Codec.MarshalInterface(upgradedConsensusState) + suite.Require().NoError(err) + suite.Require().Equal(expConsensusStateBz, consensusStateBz) + } else { + suite.Require().Error(err) + suite.Require().ErrorIs(err, tc.expErr) + } + }) + } +} diff --git a/modules/light-clients/09-localhost/client_state.go b/modules/light-clients/09-localhost/client_state.go index f687deeef1e..3bcf3f11bd9 100644 --- a/modules/light-clients/09-localhost/client_state.go +++ b/modules/light-clients/09-localhost/client_state.go @@ -166,16 +166,3 @@ func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, client func (ClientState) CheckSubstituteAndUpdateState(_ sdk.Context, _ codec.BinaryCodec, _, _ storetypes.KVStore, _ exported.ClientState) error { return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") } - -// VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded -func (ClientState) VerifyUpgradeAndUpdateState( - _ sdk.Context, - _ codec.BinaryCodec, - _ storetypes.KVStore, - _ exported.ClientState, - _ exported.ConsensusState, - _, - _ []byte, -) error { - return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client") -} diff --git a/modules/light-clients/09-localhost/client_state_test.go b/modules/light-clients/09-localhost/client_state_test.go index 2265a970033..8131aa7480e 100644 --- a/modules/light-clients/09-localhost/client_state_test.go +++ b/modules/light-clients/09-localhost/client_state_test.go @@ -125,9 +125,3 @@ func (suite *LocalhostTestSuite) TestCheckSubstituteAndUpdateState() { err := clientState.CheckSubstituteAndUpdateState(suite.chain.GetContext(), suite.chain.Codec, nil, nil, nil) suite.Require().Error(err) } - -func (suite *LocalhostTestSuite) TestVerifyUpgradeAndUpdateState() { - clientState := localhost.NewClientState(clienttypes.NewHeight(1, 10)) - err := clientState.VerifyUpgradeAndUpdateState(suite.chain.GetContext(), suite.chain.Codec, nil, nil, nil, nil, nil) - suite.Require().Error(err) -} diff --git a/modules/light-clients/09-localhost/light_client_module_test.go b/modules/light-clients/09-localhost/light_client_module_test.go index 97a5df1306e..ada90831a9d 100644 --- a/modules/light-clients/09-localhost/light_client_module_test.go +++ b/modules/light-clients/09-localhost/light_client_module_test.go @@ -302,3 +302,13 @@ func (suite *LocalhostTestSuite) TestVerifyNonMembership() { }) } } + +func (suite *LocalhostTestSuite) TestVerifyUpgradeAndUpdateState() { + suite.SetupTest() + + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.LocalhostClientID) + suite.Require().True(found) + + err := lightClientModule.VerifyUpgradeAndUpdateState(suite.chain.GetContext(), exported.LocalhostClientID, nil, nil, nil, nil) + suite.Require().Error(err) +} From 93f84b0960af9e85c49367cdc1726981bbcc30c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:10:01 +0100 Subject: [PATCH 48/74] nit: lcm -> l for all light client modules --- .../06-solomachine/light_client_module.go | 96 +++++++++---------- .../07-tendermint/light_client_module.go | 82 ++++++++-------- .../08-wasm/light_client_module.go | 84 ++++++++-------- .../09-localhost/light_client_module.go | 38 ++++---- 4 files changed, 150 insertions(+), 150 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 651302c0f47..0baca8cf6f9 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -28,17 +28,17 @@ func NewLightClientModule(cdc codec.BinaryCodec) LightClientModule { // RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. // It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores // to IBC light client instances. -func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { - lcm.storeProvider = storeProvider +func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + l.storeProvider = storeProvider } // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { +func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { var clientState ClientState - if err := lcm.cdc.Unmarshal(clientStateBz, &clientState); err != nil { + if err := l.cdc.Unmarshal(clientStateBz, &clientState); err != nil { return err } @@ -47,7 +47,7 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client } var consensusState ConsensusState - if err := lcm.cdc.Unmarshal(consensusStateBz, &consensusState); err != nil { + if err := l.cdc.Unmarshal(consensusStateBz, &consensusState); err != nil { return err } @@ -55,8 +55,8 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return err } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - return clientState.Initialize(ctx, lcm.cdc, clientStore, &consensusState) + clientStore := l.storeProvider.ClientStore(ctx, clientID) + return clientState.Initialize(ctx, l.cdc, clientStore, &consensusState) } // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. @@ -65,62 +65,62 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client // if the ClientMessage fails to verify. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) +func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, lcm.cdc, clientStore, clientMsg) + return clientState.VerifyClientMessage(ctx, l.cdc, clientStore, clientMsg) } // Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage // has already been verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) +func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.CheckForMisbehaviour(ctx, lcm.cdc, clientStore, clientMsg) + return clientState.CheckForMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) +func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - clientState.UpdateStateOnMisbehaviour(ctx, lcm.cdc, clientStore, clientMsg) + clientState.UpdateStateOnMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } // 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. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) +func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { panic(errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID)) } - return clientState.UpdateState(ctx, lcm.cdc, clientStore, clientMsg) + return clientState.UpdateState(ctx, l.cdc, clientStore, clientMsg) } // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) VerifyMembership( +func (l LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -130,20 +130,20 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, // TODO: change to conrete type value []byte, ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyMembership(ctx, clientStore, lcm.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) + return clientState.VerifyMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } // VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) VerifyNonMembership( +func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -152,26 +152,26 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyNonMembership(ctx, clientStore, lcm.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) + return clientState.VerifyNonMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } // Status must return the status of the client. Only Active clients are allowed to process packets. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) +func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { return exported.Unknown } - return clientState.Status(ctx, clientStore, lcm.cdc) + return clientState.Status(ctx, clientStore, l.cdc) } // LatestHeight returns the latest height for the client state for the given client identifier. @@ -179,10 +179,10 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S // NOTE: RevisionNumber is always 0 for solomachine client heights. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) +func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return clienttypes.ZeroHeight() } @@ -193,21 +193,21 @@ func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) expo // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) +func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { return 0, errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.GetTimestampAtHeight(ctx, clientStore, lcm.cdc, height) + return clientState.GetTimestampAtHeight(ctx, clientStore, l.cdc, height) } // RecoverClient must verify that the provided substitute may be used to update the subject client. // The light client must set the updated client and consensus states within the clientStore for the subject client. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) if err != nil { return err @@ -217,19 +217,19 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Solomachine, substituteClientType) } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) + clientStore := l.storeProvider.ClientStore(ctx, clientID) + clientState, found := getClientState(clientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - substituteClientStore := lcm.storeProvider.ClientStore(ctx, substituteClientID) - substituteClient, found := getClientState(substituteClientStore, lcm.cdc) + substituteClientStore := l.storeProvider.ClientStore(ctx, substituteClientID) + substituteClient, found := getClientState(substituteClientStore, l.cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) } - return clientState.CheckSubstituteAndUpdateState(ctx, lcm.cdc, clientStore, substituteClientStore, substituteClient) + return clientState.CheckSubstituteAndUpdateState(ctx, l.cdc, clientStore, substituteClientStore, substituteClient) } // VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 669876cbafd..24a0197b2c3 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -30,17 +30,17 @@ func NewLightClientModule(cdc codec.BinaryCodec, authority string) LightClientMo // RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. // It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores // to IBC light client instances. -func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { - lcm.storeProvider = storeProvider +func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + l.storeProvider = storeProvider } // Initialize checks that the initial consensus state is an 07-tendermint consensus state and // sets the client state, consensus state and associated metadata in the provided client store. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { +func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { var clientState ClientState - if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + if err := l.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { return err } @@ -49,7 +49,7 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client } var consensusState ConsensusState - if err := lcm.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + if err := l.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { return err } @@ -57,9 +57,9 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return err } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) - return clientState.Initialize(ctx, lcm.keeper.Codec(), clientStore, &consensusState) + return clientState.Initialize(ctx, l.keeper.Codec(), clientStore, &consensusState) } // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. @@ -68,9 +68,9 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client // if the ClientMessage fails to verify. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -84,9 +84,9 @@ func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID strin // has already been verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -99,9 +99,9 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -115,9 +115,9 @@ func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID // Upon successful update, a list of consensus heights is returned. It assumes the ClientMessage has already been verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -131,7 +131,7 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) VerifyMembership( +func (l LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, height exported.Height, @@ -141,8 +141,8 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, value []byte, ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -156,7 +156,7 @@ func (lcm LightClientModule) VerifyMembership( // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) VerifyNonMembership( +func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -165,8 +165,8 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -179,9 +179,9 @@ func (lcm LightClientModule) VerifyNonMembership( // Status must return the status of the client. Only Active clients are allowed to process packets. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -195,10 +195,10 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S // If no client is present for the provided client identifier a zero value height is returned. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) +func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.keeper.Codec()) + clientState, found := getClientState(clientStore, l.keeper.Codec()) if !found { return clienttypes.ZeroHeight() } @@ -209,13 +209,13 @@ func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) expo // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) TimestampAtHeight( +func (l LightClientModule) TimestampAtHeight( ctx sdk.Context, clientID string, height exported.Height, ) (uint64, error) { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := getClientState(clientStore, cdc) if !found { @@ -229,7 +229,7 @@ func (lcm LightClientModule) TimestampAtHeight( // The light client must set the updated client and consensus states within the clientStore for the subject client. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) if err != nil { return err @@ -239,15 +239,15 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", exported.Tendermint, substituteClientType) } - cdc := lcm.keeper.Codec() + cdc := l.keeper.Codec() - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - substituteClientStore := lcm.storeProvider.ClientStore(ctx, substituteClientID) + substituteClientStore := l.storeProvider.ClientStore(ctx, substituteClientID) substituteClient, found := getClientState(substituteClientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) @@ -269,7 +269,7 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute // and ProofSpecs do not match parameters set by committed client // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. -func (lcm LightClientModule) VerifyUpgradeAndUpdateState( +func (l LightClientModule) VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, newClient []byte, @@ -277,7 +277,7 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( upgradeClientProof, upgradeConsensusStateProof []byte, ) error { - cdc := lcm.keeper.Codec() + cdc := l.keeper.Codec() var newClientState ClientState if err := cdc.Unmarshal(newClient, &newClientState); err != nil { @@ -289,7 +289,7 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, err.Error()) } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 589215ae472..889cdde08d8 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -30,17 +30,17 @@ func NewLightClientModule(keeper wasmkeeper.Keeper) LightClientModule { // RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. // It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores // to IBC light client instances. -func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { - lcm.storeProvider = storeProvider +func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + l.storeProvider = storeProvider } // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { +func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { var clientState types.ClientState - if err := lcm.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { + if err := l.keeper.Codec().Unmarshal(clientStateBz, &clientState); err != nil { return err } @@ -49,7 +49,7 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client } var consensusState types.ConsensusState - if err := lcm.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { + if err := l.keeper.Codec().Unmarshal(consensusStateBz, &consensusState); err != nil { return err } @@ -57,8 +57,8 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client return err } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() return clientState.Initialize(ctx, cdc, clientStore, &consensusState) } @@ -69,25 +69,25 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, client // if the ClientMessage fails to verify. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - return clientState.VerifyClientMessage(ctx, lcm.keeper.Codec(), clientStore, clientMsg) + return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), clientStore, clientMsg) } // CheckForMisbehaviour checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage // has already been verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -100,9 +100,9 @@ func (lcm LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID stri // UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -116,9 +116,9 @@ func (lcm LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID // Upon successful update, a list of consensus heights is returned. It assumes the ClientMessage has already been verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -132,7 +132,7 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) VerifyMembership( +func (l LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -142,8 +142,8 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, // TODO: change to conrete type value []byte, ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -157,7 +157,7 @@ func (lcm LightClientModule) VerifyMembership( // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) VerifyNonMembership( +func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -166,8 +166,8 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -180,9 +180,9 @@ func (lcm LightClientModule) VerifyNonMembership( // Status must return the status of the client. Only Active clients are allowed to process packets. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -196,9 +196,9 @@ func (lcm LightClientModule) Status(ctx sdk.Context, clientID string) exported.S // If no client is present for the provided client identifier a zero value height is returned. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -211,9 +211,9 @@ func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) expo // TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.keeper.Codec() +func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.keeper.Codec() clientState, found := types.GetClientState(clientStore, cdc) if !found { @@ -227,7 +227,7 @@ func (lcm LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, // The light client must set the updated client and consensus states within the clientStore for the subject client. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { +func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { substituteClientType, _, err := clienttypes.ParseClientIdentifier(substituteClientID) if err != nil { return err @@ -237,15 +237,15 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute return errorsmod.Wrapf(clienttypes.ErrInvalidClientType, "expected: %s, got: %s", types.Wasm, substituteClientType) } - cdc := lcm.keeper.Codec() + cdc := l.keeper.Codec() - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) clientState, found := types.GetClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) } - substituteClientStore := lcm.storeProvider.ClientStore(ctx, substituteClientID) + substituteClientStore := l.storeProvider.ClientStore(ctx, substituteClientID) substituteClient, found := types.GetClientState(substituteClientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, substituteClientID) @@ -258,7 +258,7 @@ func (lcm LightClientModule) RecoverClient(ctx sdk.Context, clientID, substitute // the new client state, consensus state, and any other client metadata. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. -func (lcm LightClientModule) VerifyUpgradeAndUpdateState( +func (l LightClientModule) VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, newClient []byte, @@ -266,7 +266,7 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( upgradeClientProof, upgradeConsensusStateProof []byte, ) error { - cdc := lcm.keeper.Codec() + cdc := l.keeper.Codec() var newClientState types.ClientState if err := cdc.Unmarshal(newClient, &newClientState); err != nil { @@ -278,7 +278,7 @@ func (lcm LightClientModule) VerifyUpgradeAndUpdateState( return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, err.Error()) } - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) + clientStore := l.storeProvider.ClientStore(ctx, clientID) clientState, found := types.GetClientState(clientStore, cdc) if !found { return errorsmod.Wrap(clienttypes.ErrClientNotFound, clientID) diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index f3b69ffe643..ef8a60b3b75 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -32,14 +32,14 @@ func NewLightClientModule(cdc codec.BinaryCodec, key storetypes.StoreKey) *Light // RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. // It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores // to IBC light client instances. -func (lcm *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { - lcm.storeProvider = storeProvider +func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientStoreProvider) { + l.storeProvider = storeProvider } // Initialize ensures that initial consensus state for localhost is nil. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. -func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, _, consensusStateBz []byte) error { +func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, _, consensusStateBz []byte) error { if len(consensusStateBz) != 0 { return errorsmod.Wrap(clienttypes.ErrInvalidConsensus, "initial consensus state for localhost must be nil.") } @@ -48,8 +48,8 @@ func (lcm LightClientModule) Initialize(ctx sdk.Context, clientID string, _, con LatestHeight: clienttypes.GetSelfHeight(ctx), } - clientStore := lcm.storeProvider.ClientStore(ctx, exported.LocalhostClientID) - clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(lcm.cdc, &clientState)) + clientStore := l.storeProvider.ClientStore(ctx, exported.LocalhostClientID) + clientStore.Set(host.ClientStateKey(), clienttypes.MustMarshalClientState(l.cdc, &clientState)) return nil } @@ -74,9 +74,9 @@ func (LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID str // Upon successful update, a list of consensus heights is returned. It assumes the ClientMessage has already been verified. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. -func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - cdc := lcm.cdc +func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) + cdc := l.cdc clientState, found := getClientState(clientStore, cdc) if !found { @@ -91,7 +91,7 @@ func (lcm LightClientModule) UpdateState(ctx sdk.Context, clientID string, clien // The caller must provide the full IBC store. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. -func (lcm LightClientModule) VerifyMembership( +func (l LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, height exported.Height, @@ -101,9 +101,9 @@ func (lcm LightClientModule) VerifyMembership( path exported.Path, value []byte, ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - ibcStore := ctx.KVStore(lcm.key) - cdc := lcm.cdc + clientStore := l.storeProvider.ClientStore(ctx, clientID) + ibcStore := ctx.KVStore(l.key) + cdc := l.cdc clientState, found := getClientState(clientStore, cdc) if !found { @@ -118,7 +118,7 @@ func (lcm LightClientModule) VerifyMembership( // The caller must provide the full IBC store. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. -func (lcm LightClientModule) VerifyNonMembership( +func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, height exported.Height, // TODO: change to concrete type @@ -127,9 +127,9 @@ func (lcm LightClientModule) VerifyNonMembership( proof []byte, path exported.Path, // TODO: change to conrete type ) error { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) - ibcStore := ctx.KVStore(lcm.key) - cdc := lcm.cdc + clientStore := l.storeProvider.ClientStore(ctx, clientID) + ibcStore := ctx.KVStore(l.key) + cdc := l.cdc clientState, found := getClientState(clientStore, cdc) if !found { @@ -148,10 +148,10 @@ func (LightClientModule) Status(ctx sdk.Context, clientID string) exported.Statu // If no client is present for the provided client identifier a zero value height is returned. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. -func (lcm LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { - clientStore := lcm.storeProvider.ClientStore(ctx, clientID) +func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) exported.Height { + clientStore := l.storeProvider.ClientStore(ctx, clientID) - clientState, found := getClientState(clientStore, lcm.cdc) + clientState, found := getClientState(clientStore, l.cdc) if !found { return clienttypes.ZeroHeight() } From e3348f3535c0825d79b415464f615c8a9a297865 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:10:37 +0100 Subject: [PATCH 49/74] remove unnecessary comment --- modules/light-clients/08-wasm/testing/simapp/app.go | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/light-clients/08-wasm/testing/simapp/app.go b/modules/light-clients/08-wasm/testing/simapp/app.go index 2656490e3af..dd5a5a32e70 100644 --- a/modules/light-clients/08-wasm/testing/simapp/app.go +++ b/modules/light-clients/08-wasm/testing/simapp/app.go @@ -607,7 +607,6 @@ func NewSimApp( wasmLightClientModule := wasm.NewLightClientModule(app.WasmClientKeeper) clientRouter.AddRoute(wasmtypes.ModuleName, &wasmLightClientModule) - // wasmClientModule := wasm. // create evidence keeper with router evidenceKeeper := evidencekeeper.NewKeeper( appCodec, runtime.NewKVStoreService(keys[evidencetypes.StoreKey]), app.StakingKeeper, app.SlashingKeeper, app.AccountKeeper.AddressCodec(), runtime.ProvideCometInfoService(), From 39601e3b93e12ab20ae7e648bac7bdfb6f0c1c21 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:11:32 +0100 Subject: [PATCH 50/74] chore: remove unnecessary todo's --- modules/core/exported/client.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 482ee6ff75d..ac13f4ff737 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -72,18 +72,18 @@ type LightClientModule interface { // 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. - UpdateState(ctx sdk.Context, clientID string, clientMsg ClientMessage) []Height // TODO: change to concrete type + UpdateState(ctx sdk.Context, clientID string, clientMsg ClientMessage) []Height // VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. // The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). VerifyMembership( ctx sdk.Context, clientID string, - height Height, // TODO: change to concrete type + height Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path Path, // TODO: change to conrete type + path Path, value []byte, ) error @@ -92,11 +92,11 @@ type LightClientModule interface { VerifyNonMembership( ctx sdk.Context, clientID string, - height Height, // TODO: change to concrete type + height Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path Path, // TODO: change to conrete type + path Path, ) error // Status must return the status of the client. Only Active clients are allowed to process packets. @@ -109,7 +109,7 @@ type LightClientModule interface { TimestampAtHeight( ctx sdk.Context, clientID string, - height Height, // TODO: change to concrete type + height Height, ) (uint64, error) // RecoverClient must verify that the provided substitute may be used to update the subject client. From 0921bf61f5002036a39060b14499f6efaae70e30 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:17:40 +0100 Subject: [PATCH 51/74] chore: lint fix docs --- docs/docs/03-light-clients/01-developer-guide/01-overview.md | 1 + .../docs/03-light-clients/01-developer-guide/03-client-state.md | 2 -- docs/docs/05-migrations/13-v8-to-v9.md | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/docs/docs/03-light-clients/01-developer-guide/01-overview.md b/docs/docs/03-light-clients/01-developer-guide/01-overview.md index b8dc7e7c434..ef247b8d22d 100644 --- a/docs/docs/03-light-clients/01-developer-guide/01-overview.md +++ b/docs/docs/03-light-clients/01-developer-guide/01-overview.md @@ -41,6 +41,7 @@ Throughout this guide the `07-tendermint` light client module may be referred to `LightClientModule` is an interface defined by core IBC which allows for modular light client implementations. All light client implementations *must* implement the [`LightClientModule` interface](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/core/exported/client.go#L51) so that core IBC may redirect calls to the light client module. For example a light client module may need to: + - create clients - update clients - recover and upgrade clients diff --git a/docs/docs/03-light-clients/01-developer-guide/03-client-state.md b/docs/docs/03-light-clients/01-developer-guide/03-client-state.md index d5ba30ac8d5..cfacab611a2 100644 --- a/docs/docs/03-light-clients/01-developer-guide/03-client-state.md +++ b/docs/docs/03-light-clients/01-developer-guide/03-client-state.md @@ -19,5 +19,3 @@ The format is created as follows: `ClientType-{N}` where `{N}` is the unique glo `Validate` should validate every client state field and should return an error if any value is invalid. The light client implementer is in charge of determining which checks are required. See the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/client_state.go#L111) as a reference. - - diff --git a/docs/docs/05-migrations/13-v8-to-v9.md b/docs/docs/05-migrations/13-v8-to-v9.md index d031c9fcb44..f253592b234 100644 --- a/docs/docs/05-migrations/13-v8-to-v9.md +++ b/docs/docs/05-migrations/13-v8-to-v9.md @@ -57,7 +57,7 @@ The `ExportMetadata` interface function has been removed from the `ClientState` The `ZeroCustomFields` interface function has been removed from the `ClientState` interface. -The following functions have also been removed from the `ClientState` interface: `Initialize`, `Status`, `GetLatestHeight`, `GetTimestampAtHeight`, `VerifyClientMessage`, `VerifyMembership`, `VerifyNonMembership`, `CheckForMisbehaviour`, `UpdateState`, `UpdateStateOnMisbehaviour`, `CheckSubstituteAndUpdateState` and `VerifyUpgradeAndUpdateState`. ibc-go v9 decouples routing at the `02-client` layer from the light clients' encoding structure (i.e. every light client implementation of the `ClientState` interface is not used anymore to route the requests to the right light client at the `02-client` layer, instead a _light client module_ is registered for every light client type and `02-client` routes the requests to the right light client module based on the client ID). Light client developers must implement the newly introduced `LightClientModule` interface and are encouraged to move the logic implemented in the functions of their light client's implementation of the `ClientState` interface to the equivalent function in the `LightClientModule` interface. The table below shows the equivalence between the `ClientState` interface functions that have been removed and the functions in the `LightClientModule` interface: +The following functions have also been removed from the `ClientState` interface: `Initialize`, `Status`, `GetLatestHeight`, `GetTimestampAtHeight`, `VerifyClientMessage`, `VerifyMembership`, `VerifyNonMembership`, `CheckForMisbehaviour`, `UpdateState`, `UpdateStateOnMisbehaviour`, `CheckSubstituteAndUpdateState` and `VerifyUpgradeAndUpdateState`. ibc-go v9 decouples routing at the `02-client` layer from the light clients' encoding structure (i.e. every light client implementation of the `ClientState` interface is not used anymore to route the requests to the right light client at the `02-client` layer, instead a *light client module* is registered for every light client type and `02-client` routes the requests to the right light client module based on the client ID). Light client developers must implement the newly introduced `LightClientModule` interface and are encouraged to move the logic implemented in the functions of their light client's implementation of the `ClientState` interface to the equivalent function in the `LightClientModule` interface. The table below shows the equivalence between the `ClientState` interface functions that have been removed and the functions in the `LightClientModule` interface: |`ClientState` interface|`LightClientModule` interface| |-----------------------|-----------------------------| From 89112a1ef97dcb6aae9e2523b8aac2ffa9a5a750 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:19:08 +0100 Subject: [PATCH 52/74] Apply suggestions from code review --- modules/core/02-client/types/router.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index ffe1b599468..96401379336 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -8,16 +8,15 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// Router is a map from a light client module name to a LightClientModule. -// The light client module name must be the same name as the client type. -// The router also has a reference to the client store provided (02-client keeper) -// and will set the store provider on a client module upon route registration. +// Router is a map from a clientType to a LightClientModule instance. +// The router has a reference to the client store provider (02-client keeper) +// and will register the store provider on a client module upon route registration. type Router struct { routes map[string]exported.LightClientModule storeProvider exported.ClientStoreProvider } -// NewRouter returns a instance of the Router. +// NewRouter returns an instance of the Router. func NewRouter(key storetypes.StoreKey) *Router { return &Router{ routes: make(map[string]exported.LightClientModule), From 4f9b535163ecb3e6c2336fad970894a73b9e57ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:29:40 +0100 Subject: [PATCH 53/74] chore: 02-client handler godoc --- modules/core/02-client/keeper/client.go | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index 58c7c7cc500..a5019f77adf 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -12,12 +12,12 @@ import ( "github.com/cosmos/ibc-go/v8/modules/core/exported" ) -// CreateClient generates a new client identifier and isolated prefix store for the provided client state. -// The client state is responsible for setting any client-specific data in the store via the Initialize method. -// This includes the client state, initial consensus state and any associated metadata. -func (k Keeper) CreateClient( - ctx sdk.Context, clientType string, clientState []byte, consensusState []byte, -) (string, error) { +// CreateClient generates a new client identifier and invokes the associated light client module in order to +// initialize a new client. An isolated prefixed store will be reserved for this client using the generated +// client identifier. The light client module is responsible for setting any client-specific data in the store +// via the Initialize method. This includes the client state, initial consensus state and any associated +// metadata. The generated client identifier will be returned if a client was successfully initialized. +func (k Keeper) CreateClient(ctx sdk.Context, clientType string, clientState, consensusState []byte) (string, error) { if clientType == exported.Localhost { return "", errorsmod.Wrapf(types.ErrInvalidClientType, "cannot create client of type: %s", clientType) } @@ -162,13 +162,11 @@ func (k Keeper) UpgradeClient( return nil } -// RecoverClient will retrieve the subject and substitute client. -// A callback will occur to the subject client state with the client -// prefixed store being provided for both the subject and the substitute client. -// The IBC client implementations are responsible for validating the parameters of the -// substitute (ensuring they match the subject's parameters) as well as copying -// the necessary consensus states from the substitute to the subject client -// store. The substitute must be Active and the subject must not be Active. +// RecoverClient will invoke the light client module associated with the subject clientID requiesting it to +// recover the subject client given a substitute client identifier. The light client implementation +// is responsible for validating the parameters of the substitute (ensuring they match the subject's parameters) +// as well as copying the necessary consensus states from the substitute to the subject client store. +// The substitute must be Active and the subject must not be Active. func (k Keeper) RecoverClient(ctx sdk.Context, subjectClientID, substituteClientID string) error { if status := k.GetClientStatus(ctx, subjectClientID); status == exported.Active { return errorsmod.Wrapf(types.ErrInvalidRecoveryClient, "cannot recover %s subject client", exported.Active) From 8c5f67c584d554abe35ba1dcd1de9b4cba9ec5af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:36:42 +0100 Subject: [PATCH 54/74] Update modules/core/02-client/keeper/client.go --- modules/core/02-client/keeper/client.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index a5019f77adf..d1124201f65 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -162,7 +162,7 @@ func (k Keeper) UpgradeClient( return nil } -// RecoverClient will invoke the light client module associated with the subject clientID requiesting it to +// RecoverClient will invoke the light client module associated with the subject clientID requesting it to // recover the subject client given a substitute client identifier. The light client implementation // is responsible for validating the parameters of the substitute (ensuring they match the subject's parameters) // as well as copying the necessary consensus states from the substitute to the subject client store. From fa51d0dda8f4774c27c325eda335fd2a5c0a33b0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Tue, 12 Mar 2024 17:55:33 +0100 Subject: [PATCH 55/74] Update modules/light-clients/06-solomachine/light_client_module_test.go --- .../light-clients/06-solomachine/light_client_module_test.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module_test.go b/modules/light-clients/06-solomachine/light_client_module_test.go index a7d10aa3137..22e4c0d496a 100644 --- a/modules/light-clients/06-solomachine/light_client_module_test.go +++ b/modules/light-clients/06-solomachine/light_client_module_test.go @@ -112,8 +112,6 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { } func (suite *SoloMachineTestSuite) TestVerifyUpgradeAndUpdateState() { - suite.SetupTest() - clientID := suite.chainA.App.GetIBCKeeper().ClientKeeper.GenerateClientIdentifier(suite.chainA.GetContext(), exported.Solomachine) lightClientModule, found := suite.chainA.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(clientID) From bddbb07224c3a1699cbe9eccf35d937138f05879 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 16:33:24 +0100 Subject: [PATCH 56/74] remove commented out code in msg server --- modules/core/keeper/msg_server.go | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index 75119959f54..c721e2ce611 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -27,6 +27,11 @@ var ( ) // CreateClient defines a rpc handler method for MsgCreateClient. +// NOTE: The raw bytes of the conrete types encoded into protobuf.Any is passed to the client keeper. +// The 02-client handler will route to the appropriate light client module based on client type and it is the responsibility +// of the light client module to unmarshal and interpret the proto encoded bytes. +// Backwards compatibility with older versions of ibc-go is maintained through the light client module reconstructing and encoding +// the expected concrete type to the protobuf.Any for proof verification. func (k Keeper) CreateClient(goCtx context.Context, msg *clienttypes.MsgCreateClient) (*clienttypes.MsgCreateClientResponse, error) { ctx := sdk.UnwrapSDKContext(goCtx) @@ -35,14 +40,6 @@ func (k Keeper) CreateClient(goCtx context.Context, msg *clienttypes.MsgCreateCl return nil, err } - /* - consensusState, err := clienttypes.UnpackConsensusState(msg.ConsensusState) - if err != nil { - return nil, err - } - - */ - if _, err = k.ClientKeeper.CreateClient(ctx, clientState.ClientType(), msg.ClientState.Value, msg.ConsensusState.Value); err != nil { return nil, err } @@ -67,7 +64,7 @@ func (k Keeper) UpdateClient(goCtx context.Context, msg *clienttypes.MsgUpdateCl } // UpgradeClient defines a rpc handler method for MsgUpgradeClient. -// NOTE: The raw bytes of the conretes types encoded into protobuf.Any is passed to the client keeper. +// NOTE: The raw bytes of the conrete types encoded into protobuf.Any is passed to the client keeper. // The 02-client handler will route to the appropriate light client module based on client identifier and it is the responsibility // of the light client module to unmarshal and interpret the proto encoded bytes. // Backwards compatibility with older versions of ibc-go is maintained through the light client module reconstructing and encoding From 184a2714d53301d36d08710de25e8b80520f3f19 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:02:42 +0100 Subject: [PATCH 57/74] chore: update godoc, remove todo's --- .../light-clients/06-solomachine/light_client_module.go | 8 ++++---- .../light-clients/07-tendermint/light_client_module.go | 6 +++--- modules/light-clients/08-wasm/light_client_module.go | 8 ++++---- modules/light-clients/09-localhost/light_client_module.go | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index 0baca8cf6f9..bedb5d994c1 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -123,11 +123,11 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM func (l LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path exported.Path, // TODO: change to conrete type + path exported.Path, value []byte, ) error { clientStore := l.storeProvider.ClientStore(ctx, clientID) @@ -146,11 +146,11 @@ func (l LightClientModule) VerifyMembership( func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path exported.Path, // TODO: change to conrete type + path exported.Path, ) error { clientStore := l.storeProvider.ClientStore(ctx, clientID) clientState, found := getClientState(clientStore, l.cdc) diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index 24a0197b2c3..f3b4c53f783 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -20,7 +20,7 @@ type LightClientModule struct { storeProvider exported.ClientStoreProvider } -// NewLightClientModule creates and returns a new 08-wasm LightClientModule. +// NewLightClientModule creates and returns a new 07-tendermint LightClientModule. func NewLightClientModule(cdc codec.BinaryCodec, authority string) LightClientModule { return LightClientModule{ keeper: keeper.NewKeeper(cdc, authority), @@ -159,11 +159,11 @@ func (l LightClientModule) VerifyMembership( func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path exported.Path, // TODO: change to conrete type + path exported.Path, ) error { clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 889cdde08d8..1f54d14fab4 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -135,11 +135,11 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM func (l LightClientModule) VerifyMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path exported.Path, // TODO: change to conrete type + path exported.Path, value []byte, ) error { clientStore := l.storeProvider.ClientStore(ctx, clientID) @@ -160,11 +160,11 @@ func (l LightClientModule) VerifyMembership( func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path exported.Path, // TODO: change to conrete type + path exported.Path, ) error { clientStore := l.storeProvider.ClientStore(ctx, clientID) cdc := l.keeper.Codec() diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index ef8a60b3b75..edb3c3ef74e 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -121,11 +121,11 @@ func (l LightClientModule) VerifyMembership( func (l LightClientModule) VerifyNonMembership( ctx sdk.Context, clientID string, - height exported.Height, // TODO: change to concrete type + height exported.Height, delayTimePeriod uint64, delayBlockPeriod uint64, proof []byte, - path exported.Path, // TODO: change to conrete type + path exported.Path, ) error { clientStore := l.storeProvider.ClientStore(ctx, clientID) ibcStore := ctx.KVStore(l.key) From 708e452d4047d980f9bfe476002bc7413a627448 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:08:19 +0100 Subject: [PATCH 58/74] chore: remove unnecessary func from localhost + cleanup --- .../light-clients/09-localhost/client_state.go | 6 ------ .../09-localhost/client_state_test.go | 6 ------ .../09-localhost/light_client_module.go | 15 ++------------- .../09-localhost/light_client_module_test.go | 10 ++++++++-- 4 files changed, 10 insertions(+), 27 deletions(-) diff --git a/modules/light-clients/09-localhost/client_state.go b/modules/light-clients/09-localhost/client_state.go index 3bcf3f11bd9..114a6837cc4 100644 --- a/modules/light-clients/09-localhost/client_state.go +++ b/modules/light-clients/09-localhost/client_state.go @@ -160,9 +160,3 @@ func (cs ClientState) UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, client return []exported.Height{height} } - -// CheckSubstituteAndUpdateState returns an error. The localhost cannot be modified by -// proposals. -func (ClientState) CheckSubstituteAndUpdateState(_ sdk.Context, _ codec.BinaryCodec, _, _ storetypes.KVStore, _ exported.ClientState) error { - return errorsmod.Wrap(clienttypes.ErrUpdateClientFailed, "cannot update localhost client with a proposal") -} diff --git a/modules/light-clients/09-localhost/client_state_test.go b/modules/light-clients/09-localhost/client_state_test.go index 8131aa7480e..8cde7d01234 100644 --- a/modules/light-clients/09-localhost/client_state_test.go +++ b/modules/light-clients/09-localhost/client_state_test.go @@ -119,9 +119,3 @@ func (suite *LocalhostTestSuite) TestUpdateState() { clientState = suite.chain.GetClientState(exported.LocalhostClientID).(*localhost.ClientState) suite.Require().True(heights[0].EQ(clientState.LatestHeight)) } - -func (suite *LocalhostTestSuite) TestCheckSubstituteAndUpdateState() { - clientState := localhost.NewClientState(clienttypes.NewHeight(1, 10)) - err := clientState.CheckSubstituteAndUpdateState(suite.chain.GetContext(), suite.chain.Codec, nil, nil, nil) - suite.Require().Error(err) -} diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index edb3c3ef74e..40aa89c4c78 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -161,11 +161,7 @@ func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) export // TimestampAtHeight returns the current block time retrieved from the application context. The localhost client does not store consensus states and thus // cannot provide a timestamp for the provided height. -func (LightClientModule) TimestampAtHeight( - ctx sdk.Context, - clientID string, - height exported.Height, -) (uint64, error) { +func (LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { return uint64(ctx.BlockTime().UnixNano()), nil } @@ -175,13 +171,6 @@ func (LightClientModule) RecoverClient(_ sdk.Context, _, _ string) error { } // VerifyUpgradeAndUpdateState returns an error since localhost cannot be upgraded. -func (LightClientModule) VerifyUpgradeAndUpdateState( - ctx sdk.Context, - clientID string, - newClient []byte, - newConsState []byte, - upgradeClientProof, - upgradeConsensusStateProof []byte, -) error { +func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient, newConsState, upgradeClientProof, upgradeConsensusStateProof []byte) error { return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade localhost client") } diff --git a/modules/light-clients/09-localhost/light_client_module_test.go b/modules/light-clients/09-localhost/light_client_module_test.go index ada90831a9d..2c9311272ea 100644 --- a/modules/light-clients/09-localhost/light_client_module_test.go +++ b/modules/light-clients/09-localhost/light_client_module_test.go @@ -303,9 +303,15 @@ func (suite *LocalhostTestSuite) TestVerifyNonMembership() { } } -func (suite *LocalhostTestSuite) TestVerifyUpgradeAndUpdateState() { - suite.SetupTest() +func (suite *LocalhostTestSuite) TestRecoverClient() { + lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.LocalhostClientID) + suite.Require().True(found) + err := lightClientModule.RecoverClient(suite.chain.GetContext(), exported.LocalhostClientID, exported.LocalhostClientID) + suite.Require().Error(err) +} + +func (suite *LocalhostTestSuite) TestVerifyUpgradeAndUpdateState() { lightClientModule, found := suite.chain.GetSimApp().IBCKeeper.ClientKeeper.GetRouter().GetRoute(exported.LocalhostClientID) suite.Require().True(found) From 9bad0095d42f15aa20302f1ad6f638a37a6fad73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:14:35 +0100 Subject: [PATCH 59/74] Apply suggestions from code review --- modules/core/02-client/keeper/client.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/core/02-client/keeper/client.go b/modules/core/02-client/keeper/client.go index d1124201f65..4711491faae 100644 --- a/modules/core/02-client/keeper/client.go +++ b/modules/core/02-client/keeper/client.go @@ -67,7 +67,7 @@ func (k Keeper) UpdateClient(ctx sdk.Context, clientID string, clientMsg exporte clientType, _, err := types.ParseClientIdentifier(clientID) if err != nil { - return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) + return errorsmod.Wrapf(err, "unable to parse client identifier %s", clientID) } clientModule, found := k.router.GetRoute(clientID) @@ -133,7 +133,7 @@ func (k Keeper) UpgradeClient( clientType, _, err := types.ParseClientIdentifier(clientID) if err != nil { - return errorsmod.Wrapf(types.ErrClientNotFound, "clientID (%s)", clientID) + return errorsmod.Wrapf(err, "unable to parse client identifier %s", clientID) } clientModule, found := k.router.GetRoute(clientID) From cbfaea70c678ce9643f762e0c432533f0d81fb24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?colin=20axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:14:55 +0100 Subject: [PATCH 60/74] Update docs/docs/03-light-clients/01-developer-guide/01-overview.md Co-authored-by: DimitrisJim --- docs/docs/03-light-clients/01-developer-guide/01-overview.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/03-light-clients/01-developer-guide/01-overview.md b/docs/docs/03-light-clients/01-developer-guide/01-overview.md index ef247b8d22d..c482c28155e 100644 --- a/docs/docs/03-light-clients/01-developer-guide/01-overview.md +++ b/docs/docs/03-light-clients/01-developer-guide/01-overview.md @@ -49,7 +49,7 @@ For example a light client module may need to: The methods which make up this interface are detailed at a more granular level in the [LightClientModule section of this guide](02-light-client-module.md). -Please refer to the `07-tendermint`'s[`LightClientModule` definition](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/light-clients/07-tendermint/light_client_module.go#L17) for more information. +Please refer to the `07-tendermint`'s [`LightClientModule` definition](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/light-clients/07-tendermint/light_client_module.go#L17) for more information. ### `ClientState` From 5de2ebc91ff8da67c297aee07399d2bae5aa19de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:21:27 +0100 Subject: [PATCH 61/74] chore: remove todo + deprecation notice --- modules/core/02-client/keeper/keeper.go | 1 - modules/core/exported/client.go | 1 - 2 files changed, 2 deletions(-) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 4ae8d29af10..61d3f7976dc 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -497,7 +497,6 @@ func (k Keeper) GetLatestHeight(ctx sdk.Context, clientID string) types.Height { } // GetTimestampAtHeight returns the timestamp in nanoseconds of the consensus state at the given height. -// TODO: Replace exported.Height with concrete type. func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { clientType, _, err := types.ParseClientIdentifier(clientID) if err != nil { diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index ac13f4ff737..4d7369b3a30 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -123,7 +123,6 @@ type LightClientModule interface { // This is to ensure that no premature upgrades occur, since upgrade plans committed to by the counterparty // may be cancelled or modified before the last planned height. // If the upgrade is verified, the upgraded client and consensus states must be set in the client store. - // Deprecated: will be removed as performs internal functionality VerifyUpgradeAndUpdateState( ctx sdk.Context, clientID string, From 767495476e4a8621e44274bc8be32e509ed57b40 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:25:52 +0100 Subject: [PATCH 62/74] chore: fix broken link --- docs/docs/05-migrations/02-sdk-to-v1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/docs/05-migrations/02-sdk-to-v1.md b/docs/docs/05-migrations/02-sdk-to-v1.md index 3cd667b86aa..88022435f64 100644 --- a/docs/docs/05-migrations/02-sdk-to-v1.md +++ b/docs/docs/05-migrations/02-sdk-to-v1.md @@ -112,7 +112,7 @@ app.IBCKeeper = ibckeeper.NewKeeper( ### UpdateClientProposal -The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/08-proposals.md) for more information. +The `UpdateClient` has been modified to take in two client-identifiers and one initial height. Please see the [documentation](../01-ibc/07-proposals.md) for more information. ### UpgradeProposal From a830c11964c582f129ae531fe279ca0b014d6d66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:33:52 +0100 Subject: [PATCH 63/74] chore: godoc for exported client.go file --- modules/core/exported/client.go | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/modules/core/exported/client.go b/modules/core/exported/client.go index 4d7369b3a30..8a1bdd980dc 100644 --- a/modules/core/exported/client.go +++ b/modules/core/exported/client.go @@ -43,18 +43,25 @@ const ( Unauthorized Status = "Unauthorized" ) +// ClientStoreProvider is an interface which gives access to the client prefixed stores. +// It is implemented by the 02-client keeper and may be called by a light client module +// to obtain a client prefixed store for the given client identifier. type ClientStoreProvider interface { + // ClientStore will return a client prefixed store using the given client identifier ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore } +// LightClientModule is an interface which core IBC uses to interact with light client modules. +// Light client modules must implement this interface to integrate with core IBC. type LightClientModule interface { // RegisterStoreProvider is called by core IBC when a LightClientModule is added to the router. // It allows the LightClientModule to set a ClientStoreProvider which supplies isolated prefix client stores // to IBC light client instances. RegisterStoreProvider(storeProvider ClientStoreProvider) - // Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the - // client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. + // Initialize is called upon client creation, it allows the client to perform validation on the client state and initial consensus state. + // The light client module is responsible for setting any client-specific data in the store. This includes the client state, + // initial consensus state and any associated metadata. Initialize(ctx sdk.Context, clientID string, clientState, consensusState []byte) error // VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. @@ -113,7 +120,7 @@ type LightClientModule interface { ) (uint64, error) // RecoverClient must verify that the provided substitute may be used to update the subject client. - // The light client must set the updated client and consensus states within the clientStore for the subject client. + // The light client module must set the updated client and consensus states within the clientStore for the subject client. RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error // Upgrade functions From 3b3ff19d36fe8c6ef516bab7902d5bdd11d1e08c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:35:29 +0100 Subject: [PATCH 64/74] chore: test update --- .../light-clients/06-solomachine/light_client_module_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/light-clients/06-solomachine/light_client_module_test.go b/modules/light-clients/06-solomachine/light_client_module_test.go index 22e4c0d496a..6b400209f85 100644 --- a/modules/light-clients/06-solomachine/light_client_module_test.go +++ b/modules/light-clients/06-solomachine/light_client_module_test.go @@ -102,7 +102,7 @@ func (suite *SoloMachineTestSuite) TestRecoverClient() { suite.Require().Equal(substituteClientState.ConsensusState, smClientState.ConsensusState) suite.Require().Equal(substituteClientState.Sequence, smClientState.Sequence) - suite.Require().Equal(exported.Active, smClientState.Status(ctx, clientStore, cdc)) + suite.Require().Equal(exported.Active, lightClientModule.Status(ctx, subjectClientID)) } else { suite.Require().Error(err) suite.Require().ErrorIs(err, tc.expErr) From cfb8607f3a2f19d42c18c4de7a344c24d236c300 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:38:10 +0100 Subject: [PATCH 65/74] chore: godoc --- modules/core/02-client/keeper/keeper.go | 1 + modules/light-clients/07-tendermint/internal/keeper/keeper.go | 2 ++ 2 files changed, 3 insertions(+) diff --git a/modules/core/02-client/keeper/keeper.go b/modules/core/02-client/keeper/keeper.go index 61d3f7976dc..750224e9735 100644 --- a/modules/core/02-client/keeper/keeper.go +++ b/modules/core/02-client/keeper/keeper.go @@ -58,6 +58,7 @@ func (Keeper) Logger(ctx sdk.Context) log.Logger { return ctx.Logger().With("module", "x/"+exported.ModuleName+"/"+types.SubModuleName) } +// GetRouter returns the light client module router. func (k Keeper) GetRouter() *types.Router { return k.router } diff --git a/modules/light-clients/07-tendermint/internal/keeper/keeper.go b/modules/light-clients/07-tendermint/internal/keeper/keeper.go index f76e86570f0..2e1e4711e1f 100644 --- a/modules/light-clients/07-tendermint/internal/keeper/keeper.go +++ b/modules/light-clients/07-tendermint/internal/keeper/keeper.go @@ -16,6 +16,7 @@ type Keeper struct { authority string } +// NewKeeper returns a new instance of the Keeper func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper { if strings.TrimSpace(authority) == "" { panic(errors.New("authority must be non-empty")) @@ -27,6 +28,7 @@ func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper { } } +// Codec returns the codec func (k Keeper) Codec() codec.BinaryCodec { return k.cdc } From a43b1b32f65d0d4515976ac7a7709b1fa6e341ac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:48:37 +0100 Subject: [PATCH 66/74] chore: update godoc in 06-solomachine light client module --- .../06-solomachine/light_client_module.go | 40 ++++++------------- 1 file changed, 13 insertions(+), 27 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index bedb5d994c1..d8a2c48ab2f 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -32,8 +32,8 @@ func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientS l.storeProvider = storeProvider } -// Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the -// client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. +// Initialize unmarshals the provided client and consensus states and performs basic validation. It calls into the +// clientState.Initialize method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { @@ -59,10 +59,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return clientState.Initialize(ctx, l.cdc, clientStore, &consensusState) } -// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. -// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour -// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned -// if the ClientMessage fails to verify. +// VerifyClientMessage obtains the client state associated with the client identifier and calls into the clientState.VerifyClientMessage method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { @@ -75,8 +72,7 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return clientState.VerifyClientMessage(ctx, l.cdc, clientStore, clientMsg) } -// Checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage -// has already been verified. +// CheckForMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.CheckForMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { @@ -89,7 +85,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string return clientState.CheckForMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } -// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. +// UpdateStateOnMisbehaviour dobtains the client state associated with the client identifier and calls into the clientState.UpdateStateOnMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { @@ -102,8 +98,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s clientState.UpdateStateOnMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } -// 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. +// UpdateState obtains the client state associated with the client identifier and calls into the clientState.UpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { @@ -116,8 +111,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM return clientState.UpdateState(ctx, l.cdc, clientStore, clientMsg) } -// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// VerifyMembership obtains the client state associated with the client identifier and calls into the clientState.VerifyMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) VerifyMembership( @@ -139,8 +133,7 @@ func (l LightClientModule) VerifyMembership( return clientState.VerifyMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } -// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// VerifyNonMembership obtains the client state associated with the client identifier and calls into the clientState.VerifyNonMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) VerifyNonMembership( @@ -161,7 +154,7 @@ func (l LightClientModule) VerifyNonMembership( return clientState.VerifyNonMembership(ctx, clientStore, l.cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } -// Status must return the status of the client. Only Active clients are allowed to process packets. +// Status obtains the client state associated with the client identifier and calls into the clientState.Status method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { @@ -190,7 +183,7 @@ func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) export return clienttypes.NewHeight(0, clientState.Sequence) } -// TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +// TimestampAtHeight obtains the client state associated with the client identifier and calls into the clientState.GetTimestampAtHeight method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { @@ -203,8 +196,8 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return clientState.GetTimestampAtHeight(ctx, clientStore, l.cdc, height) } -// RecoverClient must verify that the provided substitute may be used to update the subject client. -// The light client must set the updated client and consensus states within the clientStore for the subject client. +// RecoverClient asserts that the substitute client is a solo machine client. It obtains the client state associated with the +// subject client and calls into the subjectClientState.CheckSubstituteAndUpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { @@ -235,13 +228,6 @@ func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteCl // VerifyUpgradeAndUpdateState returns an error since solomachine client does not support upgrades // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. -func (LightClientModule) VerifyUpgradeAndUpdateState( - ctx sdk.Context, - clientID string, - newClient []byte, - newConsState []byte, - upgradeClientProof, - upgradeConsensusStateProof []byte, -) error { +func (LightClientModule) VerifyUpgradeAndUpdateState(ctx sdk.Context, clientID string, newClient, newConsState, upgradeClientProof, upgradeConsensusStateProof []byte) error { return errorsmod.Wrap(clienttypes.ErrInvalidUpgradeClient, "cannot upgrade solomachine client") } From 3128ab898002ac9341ee669ed0e606d6e4a7729f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:55:33 +0100 Subject: [PATCH 67/74] chore: update 07-tendermint light client module godoc --- .../06-solomachine/light_client_module.go | 2 +- .../07-tendermint/light_client_module.go | 45 +++++++------------ 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/modules/light-clients/06-solomachine/light_client_module.go b/modules/light-clients/06-solomachine/light_client_module.go index d8a2c48ab2f..4cbf09b3991 100644 --- a/modules/light-clients/06-solomachine/light_client_module.go +++ b/modules/light-clients/06-solomachine/light_client_module.go @@ -85,7 +85,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string return clientState.CheckForMisbehaviour(ctx, l.cdc, clientStore, clientMsg) } -// UpdateStateOnMisbehaviour dobtains the client state associated with the client identifier and calls into the clientState.UpdateStateOnMisbehaviour method. +// UpdateStateOnMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.UpdateStateOnMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 06-solomachine-{n}. func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { diff --git a/modules/light-clients/07-tendermint/light_client_module.go b/modules/light-clients/07-tendermint/light_client_module.go index f3b4c53f783..46e52eec621 100644 --- a/modules/light-clients/07-tendermint/light_client_module.go +++ b/modules/light-clients/07-tendermint/light_client_module.go @@ -34,8 +34,8 @@ func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientS l.storeProvider = storeProvider } -// Initialize checks that the initial consensus state is an 07-tendermint consensus state and -// sets the client state, consensus state and associated metadata in the provided client store. +// Initialize unmarshals the provided client and consensus states and performs basic validation. It calls into the +// clientState.Initialize method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { @@ -62,10 +62,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return clientState.Initialize(ctx, l.keeper.Codec(), clientStore, &consensusState) } -// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. -// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour -// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned -// if the ClientMessage fails to verify. +// VerifyClientMessage obtains the client state associated with the client identifier and calls into the clientState.VerifyClientMessage method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { @@ -80,8 +77,7 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return clientState.VerifyClientMessage(ctx, cdc, clientStore, clientMsg) } -// CheckForMisbehaviour checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage -// has already been verified. +// CheckForMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.CheckForMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { @@ -96,7 +92,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string return clientState.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) } -// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. +// UpdateStateOnMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.UpdateStateOnMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { @@ -111,8 +107,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s clientState.UpdateStateOnMisbehaviour(ctx, cdc, clientStore, clientMsg) } -// 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. +// UpdateState obtains the client state associated with the client identifier and calls into the clientState.UpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { @@ -127,8 +122,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } -// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// VerifyMembership obtains the client state associated with the client identifier and calls into the clientState.VerifyMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) VerifyMembership( @@ -152,8 +146,7 @@ func (l LightClientModule) VerifyMembership( return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } -// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// VerifyNonMembership obtains the client state associated with the client identifier and calls into the clientState.VerifyNonMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) VerifyNonMembership( @@ -176,7 +169,7 @@ func (l LightClientModule) VerifyNonMembership( return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } -// Status must return the status of the client. Only Active clients are allowed to process packets. +// Status obtains the client state associated with the client identifier and calls into the clientState.Status method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { @@ -206,7 +199,7 @@ func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) export return clientState.LatestHeight } -// TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +// TimestampAtHeight obtains the client state associated with the client identifier and calls into the clientState.GetTimestampAtHeight method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) TimestampAtHeight( @@ -225,8 +218,8 @@ func (l LightClientModule) TimestampAtHeight( return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } -// RecoverClient must verify that the provided substitute may be used to update the subject client. -// The light client must set the updated client and consensus states within the clientStore for the subject client. +// RecoverClient asserts that the substitute client is a tendermint client. It obtains the client state associated with the +// subject client and calls into the subjectClientState.CheckSubstituteAndUpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { @@ -256,17 +249,9 @@ func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteCl return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } -// VerifyUpgradeAndUpdateState checks if the upgraded client has been committed by the current client -// It will zero out all client-specific fields (e.g. TrustingPeriod) and verify all data -// in client state that must be the same across all valid Tendermint clients for the new chain. -// VerifyUpgrade will return an error if: -// - the upgradedClient is not a Tendermint ClientState -// - the latest height of the client state does not have the same revision number or has a greater -// height than the committed client. -// - the height of upgraded client is not greater than that of current client -// - the latest height of the new client does not match or is greater than the height in committed client -// - any Tendermint chain specified parameter in upgraded client such as ChainID, UnbondingPeriod, -// and ProofSpecs do not match parameters set by committed client +// VerifyUpgradeAndUpdateState obtains the client state associated with the client identifier and calls into the clientState.VerifyUpgradeAndUpdateState method. +// The new client and consensus states will be unmarshaled and an error is returned if the new client state is not at a height greater +// than the existing client. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 07-tendermint-{n}. func (l LightClientModule) VerifyUpgradeAndUpdateState( From 5ed427adba8fa7554177f4996c96c2c736c5beaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 17:58:04 +0100 Subject: [PATCH 68/74] chore: update localhost client module godocs --- .../light-clients/09-localhost/light_client_module.go | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/modules/light-clients/09-localhost/light_client_module.go b/modules/light-clients/09-localhost/light_client_module.go index 40aa89c4c78..3c4570514b2 100644 --- a/modules/light-clients/09-localhost/light_client_module.go +++ b/modules/light-clients/09-localhost/light_client_module.go @@ -70,8 +70,7 @@ func (LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID str // no-op } -// 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. +// UpdateState obtains the localhost client state and calls into the clientState.UpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { @@ -86,9 +85,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } -// VerifyMembership is a generic proof verification method which verifies the existence of a given key and value within the IBC store. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -// The caller must provide the full IBC store. +// VerifyMembership obtains the localhost client state and calls into the clientState.VerifyMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. func (l LightClientModule) VerifyMembership( @@ -113,9 +110,7 @@ func (l LightClientModule) VerifyMembership( return clientState.VerifyMembership(ctx, ibcStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } -// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath within the IBC store. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). -// The caller must provide the full IBC store. +// VerifyNonMembership obtains the localhost client state and calls into the clientState.VerifyNonMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to be 09-localhost. func (l LightClientModule) VerifyNonMembership( From 0d821c5d90d01cf288a2a9e70ecfece0243b1a9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 18:00:54 +0100 Subject: [PATCH 69/74] chore: update 08-wasm light client module godoc --- .../08-wasm/light_client_module.go | 36 ++++++++----------- 1 file changed, 15 insertions(+), 21 deletions(-) diff --git a/modules/light-clients/08-wasm/light_client_module.go b/modules/light-clients/08-wasm/light_client_module.go index 1f54d14fab4..0b1376df4cd 100644 --- a/modules/light-clients/08-wasm/light_client_module.go +++ b/modules/light-clients/08-wasm/light_client_module.go @@ -34,8 +34,8 @@ func (l *LightClientModule) RegisterStoreProvider(storeProvider exported.ClientS l.storeProvider = storeProvider } -// Initialize is called upon client creation, it allows the client to perform validation on the initial consensus state and set the -// client state, consensus state and any client-specific metadata necessary for correct light client operation in the provided client store. +// Initialize unmarshals the provided client and consensus states and performs basic validation. It calls into the +// clientState.Initialize method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientStateBz, consensusStateBz []byte) error { @@ -63,10 +63,7 @@ func (l LightClientModule) Initialize(ctx sdk.Context, clientID string, clientSt return clientState.Initialize(ctx, cdc, clientStore, &consensusState) } -// VerifyClientMessage must verify a ClientMessage. A ClientMessage could be a Header, Misbehaviour, or batch update. -// It must handle each type of ClientMessage appropriately. Calls to CheckForMisbehaviour, UpdateState, and UpdateStateOnMisbehaviour -// will assume that the content of the ClientMessage has been verified and can be trusted. An error should be returned -// if the ClientMessage fails to verify. +// VerifyClientMessage obtains the client state associated with the client identifier and calls into the clientState.VerifyClientMessage method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) error { @@ -81,8 +78,7 @@ func (l LightClientModule) VerifyClientMessage(ctx sdk.Context, clientID string, return clientState.VerifyClientMessage(ctx, l.keeper.Codec(), clientStore, clientMsg) } -// CheckForMisbehaviour checks for evidence of a misbehaviour in Header or Misbehaviour type. It assumes the ClientMessage -// has already been verified. +// CheckForMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.CheckForMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) bool { @@ -97,7 +93,7 @@ func (l LightClientModule) CheckForMisbehaviour(ctx sdk.Context, clientID string return clientState.CheckForMisbehaviour(ctx, cdc, clientStore, clientMsg) } -// UpdateStateOnMisbehaviour should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. +// UpdateStateOnMisbehaviour obtains the client state associated with the client identifier and calls into the clientState.UpdateStateOnMisbehaviour method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) { @@ -112,8 +108,7 @@ func (l LightClientModule) UpdateStateOnMisbehaviour(ctx sdk.Context, clientID s clientState.UpdateStateOnMisbehaviour(ctx, cdc, clientStore, clientMsg) } -// 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. +// UpdateState obtains the client state associated with the client identifier and calls into the clientState.UpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientMsg exported.ClientMessage) []exported.Height { @@ -128,8 +123,7 @@ func (l LightClientModule) UpdateState(ctx sdk.Context, clientID string, clientM return clientState.UpdateState(ctx, cdc, clientStore, clientMsg) } -// VerifyMembership is a generic proof verification method which verifies a proof of the existence of a value at a given CommitmentPath at the specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// VerifyMembership obtains the client state associated with the client identifier and calls into the clientState.VerifyMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) VerifyMembership( @@ -153,8 +147,7 @@ func (l LightClientModule) VerifyMembership( return clientState.VerifyMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path, value) } -// VerifyNonMembership is a generic proof verification method which verifies the absence of a given CommitmentPath at a specified height. -// The caller is expected to construct the full CommitmentPath from a CommitmentPrefix and a standardized path (as defined in ICS 24). +// VerifyNonMembership obtains the client state associated with the client identifier and calls into the clientState.VerifyNonMembership method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) VerifyNonMembership( @@ -177,7 +170,7 @@ func (l LightClientModule) VerifyNonMembership( return clientState.VerifyNonMembership(ctx, clientStore, cdc, height, delayTimePeriod, delayBlockPeriod, proof, path) } -// Status must return the status of the client. Only Active clients are allowed to process packets. +// Status obtains the client state associated with the client identifier and calls into the clientState.Status method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) Status(ctx sdk.Context, clientID string) exported.Status { @@ -208,7 +201,7 @@ func (l LightClientModule) LatestHeight(ctx sdk.Context, clientID string) export return clientState.LatestHeight } -// TimestampAtHeight must return the timestamp for the consensus state associated with the provided height. +// TimestampAtHeight obtains the client state associated with the client identifier and calls into the clientState.GetTimestampAtHeight method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, height exported.Height) (uint64, error) { @@ -223,8 +216,8 @@ func (l LightClientModule) TimestampAtHeight(ctx sdk.Context, clientID string, h return clientState.GetTimestampAtHeight(ctx, clientStore, cdc, height) } -// RecoverClient must verify that the provided substitute may be used to update the subject client. -// The light client must set the updated client and consensus states within the clientStore for the subject client. +// RecoverClient asserts that the substitute client is a wasm client. It obtains the client state associated with the +// subject client and calls into the subjectClientState.CheckSubstituteAndUpdateState method. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteClientID string) error { @@ -254,8 +247,9 @@ func (l LightClientModule) RecoverClient(ctx sdk.Context, clientID, substituteCl return clientState.CheckSubstituteAndUpdateState(ctx, cdc, clientStore, substituteClientStore, substituteClient) } -// VerifyUpgradeAndUpdateState, on a successful verification expects the contract to update -// the new client state, consensus state, and any other client metadata. +// VerifyUpgradeAndUpdateState obtains the client state associated with the client identifier and calls into the clientState.VerifyUpgradeAndUpdateState method. +// The new client and consensus states will be unmarshaled and an error is returned if the new client state is not at a height greater +// than the existing client. // // CONTRACT: clientID is validated in 02-client router, thus clientID is assumed here to have the format 08-wasm-{n}. func (l LightClientModule) VerifyUpgradeAndUpdateState( From ba429b9c529077aee9287b1b5de0d58eb93ab70e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Colin=20Axn=C3=A9r?= <25233464+colin-axner@users.noreply.github.com> Date: Wed, 13 Mar 2024 18:04:06 +0100 Subject: [PATCH 70/74] fix: broken link --- .../01-developer-guide/02-light-client-module.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md b/docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md index e88051b17ad..783b1c74524 100644 --- a/docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md +++ b/docs/docs/03-light-clients/01-developer-guide/02-light-client-module.md @@ -36,12 +36,12 @@ Clients may also store any necessary client-specific metadata. ## `VerifyMembership` method `VerifyMembership` must verify the existence of a value at a given commitment path at the specified height. For more information about membership proofs -see the [Existence and non-existence proofs section](06-proofs.md). +see the [Existence and non-existence proofs section](07-proofs.md). ## `VerifyNonMembership` method `VerifyNonMembership` must verify the absence of a value at a given commitment path at a specified height. For more information about non-membership proofs -see the [Existence and non-existence proofs section](06-proofs.md). +see the [Existence and non-existence proofs section](07-proofs.md). ## `VerifyClientMessage` method From 03294519ec3114f7b3140e00f0da7590f5927330 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Wed, 13 Mar 2024 19:40:47 +0100 Subject: [PATCH 71/74] fix(e2e): correctly assign trusted height and latest height vars to be scoped correctly for later usage in misbehaviour test --- e2e/tests/core/02-client/client_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/e2e/tests/core/02-client/client_test.go b/e2e/tests/core/02-client/client_test.go index 83186f87098..06e1f3f3581 100644 --- a/e2e/tests/core/02-client/client_test.go +++ b/e2e/tests/core/02-client/client_test.go @@ -361,7 +361,7 @@ func (s *ClientTestSuite) TestClient_Update_Misbehaviour() { tmClientState, ok := clientState.(*ibctm.ClientState) s.Require().True(ok) - trustedHeight := tmClientState.LatestHeight + trustedHeight = tmClientState.LatestHeight s.Require().True(trustedHeight.GT(clienttypes.ZeroHeight())) }) @@ -377,7 +377,7 @@ func (s *ClientTestSuite) TestClient_Update_Misbehaviour() { tmClientState, ok := clientState.(*ibctm.ClientState) s.Require().True(ok) - latestHeight := tmClientState.LatestHeight + latestHeight = tmClientState.LatestHeight s.Require().True(latestHeight.GT(clienttypes.ZeroHeight())) }) From 16e141bacc1001003546f328c81b0bd1d113937b Mon Sep 17 00:00:00 2001 From: Carlos Rodriguez Date: Thu, 14 Mar 2024 15:24:06 +0100 Subject: [PATCH 72/74] address my self-review comments and some of rabbit's comments --- CHANGELOG.md | 2 ++ .../01-developer-guide/01-overview.md | 4 ++-- .../01-developer-guide/03-client-state.md | 4 ++-- .../01-developer-guide/04-consensus-state.md | 4 +--- docs/docs/05-migrations/13-v8-to-v9.md | 2 +- e2e/tests/transfer/localhost_test.go | 6 ++++-- modules/core/02-client/keeper/grpc_query_test.go | 8 ++++---- modules/core/02-client/keeper/keeper_test.go | 16 ++++++++-------- modules/core/02-client/types/router.go | 11 +++++++++-- modules/core/keeper/msg_server.go | 4 ++-- modules/light-clients/06-solomachine/doc.go | 2 +- modules/light-clients/06-solomachine/store.go | 2 ++ modules/light-clients/07-tendermint/doc.go | 2 +- .../07-tendermint/internal/keeper/keeper.go | 2 +- modules/light-clients/07-tendermint/store.go | 2 ++ modules/light-clients/08-wasm/doc.go | 2 +- .../08-wasm/keeper/msg_server_test.go | 4 +++- .../08-wasm/types/client_state_test.go | 15 +++++++++++---- .../08-wasm/types/misbehaviour_handle_test.go | 3 ++- .../08-wasm/types/proposal_handle_test.go | 3 ++- .../light-clients/08-wasm/types/querier_test.go | 4 +++- modules/light-clients/08-wasm/types/store.go | 2 ++ .../light-clients/08-wasm/types/update_test.go | 13 ++++++++----- .../light-clients/08-wasm/types/upgrade_test.go | 6 ++++-- modules/light-clients/09-localhost/doc.go | 7 +++++++ modules/light-clients/09-localhost/store.go | 2 ++ 26 files changed, 87 insertions(+), 45 deletions(-) create mode 100644 modules/light-clients/09-localhost/doc.go diff --git a/CHANGELOG.md b/CHANGELOG.md index a3d37512f5b..a7bee513a0c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,6 +40,8 @@ Ref: https://keepachangelog.com/en/1.0.0/ ### API Breaking +* (core/02-client, light-clients) [\#5806](https://github.com/cosmos/ibc-go/pull/5806) Decouple light client routing from their encoding structure. + ### State Machine Breaking ### Improvements diff --git a/docs/docs/03-light-clients/01-developer-guide/01-overview.md b/docs/docs/03-light-clients/01-developer-guide/01-overview.md index c482c28155e..89459264f7f 100644 --- a/docs/docs/03-light-clients/01-developer-guide/01-overview.md +++ b/docs/docs/03-light-clients/01-developer-guide/01-overview.md @@ -47,7 +47,7 @@ For example a light client module may need to: - recover and upgrade clients - verify membership and non-membership -The methods which make up this interface are detailed at a more granular level in the [LightClientModule section of this guide](02-light-client-module.md). +The methods which make up this interface are detailed at a more granular level in the [`LightClientModule` section of this guide](02-light-client-module.md). Please refer to the `07-tendermint`'s [`LightClientModule` definition](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/light-clients/07-tendermint/light_client_module.go#L17) for more information. @@ -63,7 +63,7 @@ For example: - Constraints used for client upgrades. The `ClientState` type maintained within the light client module *must* implement the [`ClientState`](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/modules/core/exported/client.go#L36) interface defined in `core/modules/exported/client.go`. -The methods which make up this interface are detailed at a more granular level in the [ClientState section of this guide](03-client-state.md). +The methods which make up this interface are detailed at a more granular level in the [`ClientState` section of this guide](03-client-state.md). Please refer to the `07-tendermint` light client module's [`ClientState` definition](https://github.com/cosmos/ibc-go/tree/02-client-refactor-beta1/proto/ibc/lightclients/tendermint/v1/tendermint.proto#L18) containing information such as chain ID, status, latest height, unbonding period and proof specifications. diff --git a/docs/docs/03-light-clients/01-developer-guide/03-client-state.md b/docs/docs/03-light-clients/01-developer-guide/03-client-state.md index cfacab611a2..f4545c46fd0 100644 --- a/docs/docs/03-light-clients/01-developer-guide/03-client-state.md +++ b/docs/docs/03-light-clients/01-developer-guide/03-client-state.md @@ -8,12 +8,12 @@ slug: /ibc/light-clients/client-state # Implementing the `ClientState` interface -Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface. This list of methods described here does not include all methods of the interface. Some methods are explained in detail in the relevant sections of the guide. +Learn how to implement the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface. ## `ClientType` method `ClientType` should return a unique string identifier of the light client. This will be used when generating a client identifier. -The format is created as follows: `ClientType-{N}` where `{N}` is the unique global nonce associated with a specific client. +The format is created as follows: `{client-type}-{N}` where `{N}` is the unique global nonce associated with a specific client (e.g `07-tendermint-0`). ## `Validate` method diff --git a/docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md b/docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md index cc54204d1dd..4edc43cb8fa 100644 --- a/docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md +++ b/docs/docs/03-light-clients/01-developer-guide/04-consensus-state.md @@ -20,9 +20,7 @@ This is the type of client consensus. It should be the same as the `ClientType` ## `GetTimestamp` method -*Deprecated*: soon to be removed from interface - -`GetTimestamp` should return the timestamp (in nanoseconds) of the consensus state snapshot. +`GetTimestamp` should return the timestamp (in nanoseconds) of the consensus state snapshot. This function has been deprecated and will be removed in a future release. ## `ValidateBasic` method diff --git a/docs/docs/05-migrations/13-v8-to-v9.md b/docs/docs/05-migrations/13-v8-to-v9.md index f253592b234..7038ec6e265 100644 --- a/docs/docs/05-migrations/13-v8-to-v9.md +++ b/docs/docs/05-migrations/13-v8-to-v9.md @@ -76,7 +76,7 @@ The following functions have also been removed from the `ClientState` interface: |`ExportMetadata` | | |`ZeroCustomFields` | | -Please check also the [light client developer guide](../03-light-clients/01-developer-guide/01-overview.md) for more information. The light client module implementation for `07-tendermint` may also be useful as reference. +Please check also the [Light client developer guide](../03-light-clients/01-developer-guide/01-overview.md) for more information. The light client module implementation for `07-tendermint` may also be useful as reference. ### 07-tendermint diff --git a/e2e/tests/transfer/localhost_test.go b/e2e/tests/transfer/localhost_test.go index 57ad937cd75..d4d62dda7a3 100644 --- a/e2e/tests/transfer/localhost_test.go +++ b/e2e/tests/transfer/localhost_test.go @@ -55,13 +55,15 @@ func (s *LocalhostTransferTestSuite) TestMsgTransfer_Localhost() { t.Run("verify begin blocker was executed", func(t *testing.T) { cs, err := s.QueryClientState(ctx, chainA, exported.LocalhostClientID) s.Require().NoError(err) - originalHeight := cs.(*localhost.ClientState).LatestHeight + + localhostClientState := cs.(*localhost.ClientState) + originalHeight := localhostClientState.LatestHeight s.Require().NoError(test.WaitForBlocks(ctx, 1, chainA), "failed to wait for blocks") cs, err = s.QueryClientState(ctx, chainA, exported.LocalhostClientID) s.Require().NoError(err) - s.Require().True(cs.(*localhost.ClientState).LatestHeight.GT(originalHeight), "client state height was not incremented") + s.Require().True(localhostClientState.LatestHeight.GT(originalHeight), "client state height was not incremented") }) t.Run("channel open init localhost", func(t *testing.T) { diff --git a/modules/core/02-client/keeper/grpc_query_test.go b/modules/core/02-client/keeper/grpc_query_test.go index 2d7090d38a5..a2dc1eb3377 100644 --- a/modules/core/02-client/keeper/grpc_query_test.go +++ b/modules/core/02-client/keeper/grpc_query_test.go @@ -344,22 +344,22 @@ func (suite *KeeperTestSuite) TestQueryConsensusStates() { path := ibctesting.NewPath(suite.chainA, suite.chainB) path.SetupClients() - height1 := path.EndpointA.GetClientLatestHeight() + height1 := path.EndpointA.GetClientLatestHeight().(types.Height) expConsensusStates = append( expConsensusStates, types.NewConsensusStateWithHeight( - height1.(types.Height), + height1, path.EndpointA.GetConsensusState(height1), )) err := path.EndpointA.UpdateClient() suite.Require().NoError(err) - height2 := path.EndpointA.GetClientLatestHeight() + height2 := path.EndpointA.GetClientLatestHeight().(types.Height) expConsensusStates = append( expConsensusStates, types.NewConsensusStateWithHeight( - height2.(types.Height), + height2, path.EndpointA.GetConsensusState(height2), )) diff --git a/modules/core/02-client/keeper/keeper_test.go b/modules/core/02-client/keeper/keeper_test.go index 034500b55ac..84be6a7ac24 100644 --- a/modules/core/02-client/keeper/keeper_test.go +++ b/modules/core/02-client/keeper/keeper_test.go @@ -337,20 +337,20 @@ func (suite *KeeperTestSuite) TestGetConsensusState() { // 2 clients in total are created on chainA. The first client is updated so it contains an initial consensus state // and a consensus state at the update height. func (suite *KeeperTestSuite) TestGetAllConsensusStates() { - path := ibctesting.NewPath(suite.chainA, suite.chainB) - path.SetupClients() + path1 := ibctesting.NewPath(suite.chainA, suite.chainB) + path1.SetupClients() - expConsensusHeight0 := path.EndpointA.GetClientLatestHeight() - consensusState0, ok := suite.chainA.GetConsensusState(path.EndpointA.ClientID, expConsensusHeight0) + expConsensusHeight0 := path1.EndpointA.GetClientLatestHeight() + consensusState0, ok := suite.chainA.GetConsensusState(path1.EndpointA.ClientID, expConsensusHeight0) suite.Require().True(ok) // update client to create a second consensus state - err := path.EndpointA.UpdateClient() + err := path1.EndpointA.UpdateClient() suite.Require().NoError(err) - expConsensusHeight1 := path.EndpointA.GetClientLatestHeight() + expConsensusHeight1 := path1.EndpointA.GetClientLatestHeight() suite.Require().True(expConsensusHeight1.GT(expConsensusHeight0)) - consensusState1, ok := suite.chainA.GetConsensusState(path.EndpointA.ClientID, expConsensusHeight1) + consensusState1, ok := suite.chainA.GetConsensusState(path1.EndpointA.ClientID, expConsensusHeight1) suite.Require().True(ok) expConsensus := []exported.ConsensusState{ @@ -369,7 +369,7 @@ func (suite *KeeperTestSuite) TestGetAllConsensusStates() { expConsensus2 := []exported.ConsensusState{consensusState2} expConsensusStates := types.ClientsConsensusStates{ - types.NewClientConsensusStates(path.EndpointA.ClientID, []types.ConsensusStateWithHeight{ + types.NewClientConsensusStates(path1.EndpointA.ClientID, []types.ConsensusStateWithHeight{ types.NewConsensusStateWithHeight(expConsensusHeight0.(types.Height), expConsensus[0]), types.NewConsensusStateWithHeight(expConsensusHeight1.(types.Height), expConsensus[1]), }), diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index 96401379336..4d345a62205 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -25,9 +25,16 @@ func NewRouter(key storetypes.StoreKey) *Router { } // AddRoute adds LightClientModule for a given module name. It returns the Router -// so AddRoute calls can be linked. It will panic if the Router is sealed. -// The store provider will be registered on the light client module. +// so AddRoute calls can be linked. The store provider will be registered on the +// light client module. This function will panic if: +// - the Router is sealed, +// - or a module is already registered for the provided client type, +// - or the client type is invalid. func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule) *Router { + if err := ValidateClientType(clientType); err != nil { + panic(err) + } + if rtr.HasRoute(clientType) { panic(fmt.Errorf("route %s has already been registered", module)) } diff --git a/modules/core/keeper/msg_server.go b/modules/core/keeper/msg_server.go index c721e2ce611..0b583eca379 100644 --- a/modules/core/keeper/msg_server.go +++ b/modules/core/keeper/msg_server.go @@ -27,7 +27,7 @@ var ( ) // CreateClient defines a rpc handler method for MsgCreateClient. -// NOTE: The raw bytes of the conrete types encoded into protobuf.Any is passed to the client keeper. +// NOTE: The raw bytes of the concrete types encoded into protobuf.Any is passed to the client keeper. // The 02-client handler will route to the appropriate light client module based on client type and it is the responsibility // of the light client module to unmarshal and interpret the proto encoded bytes. // Backwards compatibility with older versions of ibc-go is maintained through the light client module reconstructing and encoding @@ -64,7 +64,7 @@ func (k Keeper) UpdateClient(goCtx context.Context, msg *clienttypes.MsgUpdateCl } // UpgradeClient defines a rpc handler method for MsgUpgradeClient. -// NOTE: The raw bytes of the conrete types encoded into protobuf.Any is passed to the client keeper. +// NOTE: The raw bytes of the concrete types encoded into protobuf.Any is passed to the client keeper. // The 02-client handler will route to the appropriate light client module based on client identifier and it is the responsibility // of the light client module to unmarshal and interpret the proto encoded bytes. // Backwards compatibility with older versions of ibc-go is maintained through the light client module reconstructing and encoding diff --git a/modules/light-clients/06-solomachine/doc.go b/modules/light-clients/06-solomachine/doc.go index c4d15dfdc76..8a46b0430c3 100644 --- a/modules/light-clients/06-solomachine/doc.go +++ b/modules/light-clients/06-solomachine/doc.go @@ -1,5 +1,5 @@ /* -Package solomachine implements a concrete ClientState, ConsensusState, +Package solomachine implements a concrete LightClientModule, ClientState, ConsensusState, Header and Misbehaviour types for the Solo Machine light client. This implementation is based off the ICS 06 specification (https://github.com/cosmos/ibc/tree/master/spec/client/ics-006-solo-machine-client) diff --git a/modules/light-clients/06-solomachine/store.go b/modules/light-clients/06-solomachine/store.go index f974882dcac..87757942596 100644 --- a/modules/light-clients/06-solomachine/store.go +++ b/modules/light-clients/06-solomachine/store.go @@ -9,6 +9,8 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) +// getClientState retrieves the client state from the store using the provided KVStore and codec. +// It returns the unmarshaled ClientState and a boolean indicating if the state was found. func getClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { bz := store.Get(host.ClientStateKey()) if len(bz) == 0 { diff --git a/modules/light-clients/07-tendermint/doc.go b/modules/light-clients/07-tendermint/doc.go index 85f183b8d9d..d173dd7efe8 100644 --- a/modules/light-clients/07-tendermint/doc.go +++ b/modules/light-clients/07-tendermint/doc.go @@ -1,5 +1,5 @@ /* -Package tendermint implements a concrete ClientState, ConsensusState, +Package tendermint implements a concrete LightClientModule, ClientState, ConsensusState, Header, Misbehaviour and types for the Tendermint consensus light client. This implementation is based off the ICS 07 specification (https://github.com/cosmos/ibc/tree/main/spec/client/ics-007-tendermint-client) diff --git a/modules/light-clients/07-tendermint/internal/keeper/keeper.go b/modules/light-clients/07-tendermint/internal/keeper/keeper.go index 2e1e4711e1f..40fb037e220 100644 --- a/modules/light-clients/07-tendermint/internal/keeper/keeper.go +++ b/modules/light-clients/07-tendermint/internal/keeper/keeper.go @@ -16,7 +16,7 @@ type Keeper struct { authority string } -// NewKeeper returns a new instance of the Keeper +// NewKeeper returns a new instance of the Keeper. It panics if the authority is empty. func NewKeeper(cdc codec.BinaryCodec, authority string) Keeper { if strings.TrimSpace(authority) == "" { panic(errors.New("authority must be non-empty")) diff --git a/modules/light-clients/07-tendermint/store.go b/modules/light-clients/07-tendermint/store.go index 8b3cc1a551e..3c0bd6f55a5 100644 --- a/modules/light-clients/07-tendermint/store.go +++ b/modules/light-clients/07-tendermint/store.go @@ -50,6 +50,8 @@ func setClientState(clientStore storetypes.KVStore, cdc codec.BinaryCodec, clien clientStore.Set(key, val) } +// getClientState retrieves the client state from the store using the provided KVStore and codec. +// It returns the unmarshaled ClientState and a boolean indicating if the state was found. func getClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { bz := store.Get(host.ClientStateKey()) if len(bz) == 0 { diff --git a/modules/light-clients/08-wasm/doc.go b/modules/light-clients/08-wasm/doc.go index 1c4484759b5..e6329104356 100644 --- a/modules/light-clients/08-wasm/doc.go +++ b/modules/light-clients/08-wasm/doc.go @@ -1,5 +1,5 @@ /* -Package wasm implements a concrete ClientState, ConsensusState, +Package wasm implements a concrete LightClientModule, ClientState, ConsensusState, ClientMessage and types for the proxy light client module communicating with underlying Wasm light clients. This implementation is based off the ICS 08 specification diff --git a/modules/light-clients/08-wasm/keeper/msg_server_test.go b/modules/light-clients/08-wasm/keeper/msg_server_test.go index ad2b2dce326..c0a0a83c2ef 100644 --- a/modules/light-clients/08-wasm/keeper/msg_server_test.go +++ b/modules/light-clients/08-wasm/keeper/msg_server_test.go @@ -253,6 +253,7 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { for _, tc := range testCases { suite.Run(tc.name, func() { + var ok bool suite.SetupWasmWithMockVM() storeWasmCode(suite, wasmtesting.Code) @@ -263,7 +264,8 @@ func (suite *KeeperTestSuite) TestMsgMigrateContract() { suite.Require().NoError(err) // this is the old client state - expClientState = endpoint.GetClientState().(*types.ClientState) + expClientState, ok = endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) tc.malleate() diff --git a/modules/light-clients/08-wasm/types/client_state_test.go b/modules/light-clients/08-wasm/types/client_state_test.go index b69b6459251..5e06f5c73f9 100644 --- a/modules/light-clients/08-wasm/types/client_state_test.go +++ b/modules/light-clients/08-wasm/types/client_state_test.go @@ -86,7 +86,8 @@ func (suite *TypesTestSuite) TestStatus() { tc.malleate() clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) status := clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) suite.Require().Equal(tc.expStatus, status) @@ -153,7 +154,9 @@ func (suite *TypesTestSuite) TestGetTimestampAtHeight() { suite.Require().NoError(err) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) + height = clientState.LatestHeight tc.malleate() @@ -453,6 +456,7 @@ func (suite *TypesTestSuite) TestVerifyMembership() { for _, tc := range testCases { suite.Run(tc.name, func() { + var ok bool suite.SetupWasmWithMockVM() endpoint := wasmtesting.NewWasmEndpoint(suite.chainA) @@ -465,7 +469,8 @@ func (suite *TypesTestSuite) TestVerifyMembership() { value = []byte("value") clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState = endpoint.GetClientState().(*types.ClientState) + clientState, ok = endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) tc.malleate() @@ -594,6 +599,7 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { for _, tc := range testCases { suite.Run(tc.name, func() { + var ok bool suite.SetupWasmWithMockVM() endpoint := wasmtesting.NewWasmEndpoint(suite.chainA) @@ -605,7 +611,8 @@ func (suite *TypesTestSuite) TestVerifyNonMembership() { proofHeight = clienttypes.NewHeight(0, 1) clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState = endpoint.GetClientState().(*types.ClientState) + clientState, ok = endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) tc.malleate() diff --git a/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go b/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go index 9ab7c586832..eeb87cf4cd1 100644 --- a/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go +++ b/modules/light-clients/08-wasm/types/misbehaviour_handle_test.go @@ -77,7 +77,8 @@ func (suite *TypesTestSuite) TestCheckForMisbehaviour() { err := endpoint.CreateClient() suite.Require().NoError(err) - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) clientMessage = &types.ClientMessage{ Data: clienttypes.MustMarshalClientMessage(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientMisbehaviour), } diff --git a/modules/light-clients/08-wasm/types/proposal_handle_test.go b/modules/light-clients/08-wasm/types/proposal_handle_test.go index 400e997e8f9..b48bd25ce4a 100644 --- a/modules/light-clients/08-wasm/types/proposal_handle_test.go +++ b/modules/light-clients/08-wasm/types/proposal_handle_test.go @@ -95,7 +95,8 @@ func (suite *TypesTestSuite) TestCheckSubstituteAndUpdateState() { suite.Require().NoError(err) subjectClientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpointA.ClientID) - subjectClientState := endpointA.GetClientState().(*types.ClientState) + subjectClientState, ok := endpointA.GetClientState().(*types.ClientState) + suite.Require().True(ok) substituteEndpoint := wasmtesting.NewWasmEndpoint(suite.chainA) err = substituteEndpoint.CreateClient() diff --git a/modules/light-clients/08-wasm/types/querier_test.go b/modules/light-clients/08-wasm/types/querier_test.go index 9b0596cefc4..cd8f9b9bc37 100644 --- a/modules/light-clients/08-wasm/types/querier_test.go +++ b/modules/light-clients/08-wasm/types/querier_test.go @@ -108,7 +108,9 @@ func (suite *TypesTestSuite) TestCustomQuery() { tc.malleate() clientStore := suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) + clientState.Status(suite.chainA.GetContext(), clientStore, suite.chainA.App.AppCodec()) // reset query plugins after each test diff --git a/modules/light-clients/08-wasm/types/store.go b/modules/light-clients/08-wasm/types/store.go index c96e0b22493..fa7005e0ca5 100644 --- a/modules/light-clients/08-wasm/types/store.go +++ b/modules/light-clients/08-wasm/types/store.go @@ -32,6 +32,8 @@ var ( substitutePrefix = []byte("substitute/") ) +// GetClientState retrieves the client state from the store using the provided KVStore and codec. +// It returns the unmarshaled ClientState and a boolean indicating if the state was found. func GetClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { bz := store.Get(host.ClientStateKey()) if len(bz) == 0 { diff --git a/modules/light-clients/08-wasm/types/update_test.go b/modules/light-clients/08-wasm/types/update_test.go index 2c8ba4d1889..b24e4220661 100644 --- a/modules/light-clients/08-wasm/types/update_test.go +++ b/modules/light-clients/08-wasm/types/update_test.go @@ -79,7 +79,8 @@ func (suite *TypesTestSuite) TestUpdateState() { bz := store.Get(host.ClientStateKey()) suite.Require().NotEmpty(bz) - clientState := clienttypes.MustUnmarshalClientState(suite.chainA.Codec, bz).(*types.ClientState) + clientState, ok := clienttypes.MustUnmarshalClientState(suite.chainA.Codec, bz).(*types.ClientState) + suite.Require().True(ok) clientState.LatestHeight = mockHeight expectedClientStateBz = clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), expectedClientStateBz) @@ -146,7 +147,8 @@ func (suite *TypesTestSuite) TestUpdateState() { tc.malleate() - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) var heights []exported.Height updateState := func() { @@ -222,7 +224,8 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { // set new client state in store bz := store.Get(host.ClientStateKey()) suite.Require().NotEmpty(bz) - clientState := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), bz).(*types.ClientState) + clientState, ok := clienttypes.MustUnmarshalClientState(suite.chainA.App.AppCodec(), bz).(*types.ClientState) + suite.Require().True(ok) clientState.LatestHeight = mockHeight expectedClientStateBz = clienttypes.MustMarshalClientState(suite.chainA.App.AppCodec(), clientState) store.Set(host.ClientStateKey(), expectedClientStateBz) @@ -273,8 +276,8 @@ func (suite *TypesTestSuite) TestUpdateStateOnMisbehaviour() { clientMsg = &types.ClientMessage{ Data: clienttypes.MustMarshalClientMessage(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientMisbehaviour), } - clientState := endpoint.GetClientState().(*types.ClientState) - + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) tc.malleate() if tc.panicErr == nil { diff --git a/modules/light-clients/08-wasm/types/upgrade_test.go b/modules/light-clients/08-wasm/types/upgrade_test.go index bcf27763bdf..e88bc8e09d7 100644 --- a/modules/light-clients/08-wasm/types/upgrade_test.go +++ b/modules/light-clients/08-wasm/types/upgrade_test.go @@ -99,7 +99,8 @@ func (suite *TypesTestSuite) TestVerifyClientMessage() { suite.Require().NoError(err) clientStore = suite.chainA.App.GetIBCKeeper().ClientKeeper.ClientStore(suite.chainA.GetContext(), endpoint.ClientID) - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) clientMsg = &types.ClientMessage{ Data: clienttypes.MustMarshalClientMessage(suite.chainA.App.AppCodec(), wasmtesting.MockTendermintClientHeader), @@ -207,7 +208,8 @@ func (suite *TypesTestSuite) TestVerifyUpgradeAndUpdateState() { err := endpoint.CreateClient() suite.Require().NoError(err) - clientState := endpoint.GetClientState().(*types.ClientState) + clientState, ok := endpoint.GetClientState().(*types.ClientState) + suite.Require().True(ok) newLatestHeight := clienttypes.NewHeight(2, 10) wrappedUpgradedClient := wasmtesting.CreateMockTendermintClientState(newLatestHeight) diff --git a/modules/light-clients/09-localhost/doc.go b/modules/light-clients/09-localhost/doc.go new file mode 100644 index 00000000000..da32e440c0c --- /dev/null +++ b/modules/light-clients/09-localhost/doc.go @@ -0,0 +1,7 @@ +/* +Package solomachine implements a concrete LightClientModule, ClientState, ConsensusState, +Header and Misbehaviour types for the Localhost light client. +This implementation is based off the ICS 09 specification +(https://github.com/cosmos/ibc/blob/main/spec/client/ics-009-loopback-cilent) +*/ +package localhost diff --git a/modules/light-clients/09-localhost/store.go b/modules/light-clients/09-localhost/store.go index b66674f7022..39ff6e1297c 100644 --- a/modules/light-clients/09-localhost/store.go +++ b/modules/light-clients/09-localhost/store.go @@ -9,6 +9,8 @@ import ( host "github.com/cosmos/ibc-go/v8/modules/core/24-host" ) +// getClientState retrieves the client state from the store using the provided KVStore and codec. +// It returns the unmarshaled ClientState and a boolean indicating if the state was found. func getClientState(store storetypes.KVStore, cdc codec.BinaryCodec) (*ClientState, bool) { bz := store.Get(host.ClientStateKey()) if len(bz) == 0 { From c1c70aef8d2dc9f1b7734909dffdea529c1abbea Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 14 Mar 2024 16:45:03 +0100 Subject: [PATCH 73/74] Update e2e/tests/transfer/localhost_test.go --- e2e/tests/transfer/localhost_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/e2e/tests/transfer/localhost_test.go b/e2e/tests/transfer/localhost_test.go index d4d62dda7a3..a8909fa9675 100644 --- a/e2e/tests/transfer/localhost_test.go +++ b/e2e/tests/transfer/localhost_test.go @@ -63,7 +63,7 @@ func (s *LocalhostTransferTestSuite) TestMsgTransfer_Localhost() { cs, err = s.QueryClientState(ctx, chainA, exported.LocalhostClientID) s.Require().NoError(err) - s.Require().True(localhostClientState.LatestHeight.GT(originalHeight), "client state height was not incremented") + s.Require().True(cs.(*localhost.ClientState).LatestHeight.GT(originalHeight), "client state height was not incremented") }) t.Run("channel open init localhost", func(t *testing.T) { From 696f852a5a8a675c22453811b615c3bc6ea27c52 Mon Sep 17 00:00:00 2001 From: Damian Nolan Date: Thu, 14 Mar 2024 19:23:38 +0100 Subject: [PATCH 74/74] chore: godocs, rm ClientStore from expected keeper, rename events arg to initialHeight --- modules/core/02-client/keeper/events.go | 4 ++-- modules/core/02-client/types/router.go | 8 ++++---- modules/core/02-client/types/store.go | 7 +++---- modules/core/04-channel/types/expected_keepers.go | 3 --- 4 files changed, 9 insertions(+), 13 deletions(-) diff --git a/modules/core/02-client/keeper/events.go b/modules/core/02-client/keeper/events.go index 828aa4820ba..f030b6cf52c 100644 --- a/modules/core/02-client/keeper/events.go +++ b/modules/core/02-client/keeper/events.go @@ -15,13 +15,13 @@ import ( ) // emitCreateClientEvent emits a create client event -func emitCreateClientEvent(ctx sdk.Context, clientID, clientType string, latestHeight exported.Height) { +func emitCreateClientEvent(ctx sdk.Context, clientID, clientType string, initialHeight exported.Height) { ctx.EventManager().EmitEvents(sdk.Events{ sdk.NewEvent( types.EventTypeCreateClient, sdk.NewAttribute(types.AttributeKeyClientID, clientID), sdk.NewAttribute(types.AttributeKeyClientType, clientType), - sdk.NewAttribute(types.AttributeKeyConsensusHeight, latestHeight.String()), + sdk.NewAttribute(types.AttributeKeyConsensusHeight, initialHeight.String()), ), sdk.NewEvent( sdk.EventTypeMessage, diff --git a/modules/core/02-client/types/router.go b/modules/core/02-client/types/router.go index 4d345a62205..c13449274c1 100644 --- a/modules/core/02-client/types/router.go +++ b/modules/core/02-client/types/router.go @@ -31,14 +31,14 @@ func NewRouter(key storetypes.StoreKey) *Router { // - or a module is already registered for the provided client type, // - or the client type is invalid. func (rtr *Router) AddRoute(clientType string, module exported.LightClientModule) *Router { - if err := ValidateClientType(clientType); err != nil { - panic(err) - } - if rtr.HasRoute(clientType) { panic(fmt.Errorf("route %s has already been registered", module)) } + if err := ValidateClientType(clientType); err != nil { + panic(fmt.Errorf("failed to add route: %w", err)) + } + rtr.routes[clientType] = module module.RegisterStoreProvider(rtr.storeProvider) diff --git a/modules/core/02-client/types/store.go b/modules/core/02-client/types/store.go index 5d98cbe6901..d8d67c101fd 100644 --- a/modules/core/02-client/types/store.go +++ b/modules/core/02-client/types/store.go @@ -26,14 +26,13 @@ func NewStoreProvider(storeKey storetypes.StoreKey) exported.ClientStoreProvider } } -// ClientStore returns isolated prefix store for each client so they can read/write in separate -// namespace without being able to read/write other client's data +// ClientStore returns isolated prefix store for each client so they can read/write in separate namespaces. func (s storeProvider) ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore { clientPrefix := []byte(fmt.Sprintf("%s/%s/", host.KeyClientStorePrefix, clientID)) return prefix.NewStore(ctx.KVStore(s.storeKey), clientPrefix) } -// ModuleStore returns the 02-client module store -func (s storeProvider) ModuleStore(ctx sdk.Context, clientType string) storetypes.KVStore { +// ClientModuleStore returns the module store for a provided client type. +func (s storeProvider) ClientModuleStore(ctx sdk.Context, clientType string) storetypes.KVStore { return prefix.NewStore(ctx.KVStore(s.storeKey), host.PrefixedClientStoreKey([]byte(clientType))) } diff --git a/modules/core/04-channel/types/expected_keepers.go b/modules/core/04-channel/types/expected_keepers.go index b8dfea0d751..2d2fd8b7e65 100644 --- a/modules/core/04-channel/types/expected_keepers.go +++ b/modules/core/04-channel/types/expected_keepers.go @@ -1,8 +1,6 @@ package types import ( - storetypes "cosmossdk.io/store/types" - sdk "github.com/cosmos/cosmos-sdk/types" capabilitytypes "github.com/cosmos/ibc-go/modules/capability/types" @@ -13,7 +11,6 @@ import ( // ClientKeeper expected account IBC client keeper type ClientKeeper interface { - ClientStore(ctx sdk.Context, clientID string) storetypes.KVStore GetClientStatus(ctx sdk.Context, clientID string) exported.Status GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool)