Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs: updates due to 02-client routing refactoring #6049

Merged
merged 9 commits into from
May 22, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ Learn how to build IBC light client modules and fulfill the interfaces required

IBC uses light clients in order to provide trust-minimized interoperability between sovereign blockchains. Light clients operate under a strict set of rules which provide security guarantees for state updates and facilitate the ability to verify the state of a remote blockchain using merkle proofs.

The following aims to provide a high level IBC light client module developer guide. Access to IBC light clients are gated by the core IBC `MsgServer` which utilizes the abstractions set by the `02-client` submodule to call into a light client module. A light client module developer is only required to implement a set interfaces as defined in the `modules/core/exported` package of ibc-go.
The following aims to provide a high level IBC light client module developer guide. Access to IBC light clients are gated by the core IBC `MsgServer` which utilizes the abstractions set by the `02-client` submodule to call into a light client module. A light client module developer is only required to implement a set of interfaces as defined in the `modules/core/exported` package of ibc-go.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved

A light client module developer should be concerned with three main interfaces:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ slug: /ibc/light-clients/light-client-module

# Implementing the `LightClientModule` interface

## `RegisterStoreProvider` method

`RegisterStoreProvider` is called by core IBC when a `LightClientModule` is added to the router. It allows the `LightClientModule` to set a `ClientStoreProvider` ([interface defined in `modules/core/exported`](https://github.com/cosmos/ibc-go/blob/06fd8eb5ee1697e3b43be7528a6e42f5e4a4613c/modules/core/exported/client.go#L49-L52)) which supplies isolated prefix client stores to IBC light client instances.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small note: we might remove this #6028. Leaving comment to keep track.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clarify the beginning of the sentence for grammatical consistency.

- `RegisterStoreProvider` is called by core IBC when a `LightClientModule` is added to the router.
+ The `RegisterStoreProvider` method is called by core IBC when a `LightClientModule` is added to the router.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
`RegisterStoreProvider` is called by core IBC when a `LightClientModule` is added to the router. It allows the `LightClientModule` to set a `ClientStoreProvider` ([interface defined in `modules/core/exported`](https://github.com/cosmos/ibc-go/blob/06fd8eb5ee1697e3b43be7528a6e42f5e4a4613c/modules/core/exported/client.go#L49-L52)) which supplies isolated prefix client stores to IBC light client instances.
`RegisterStoreProvider` is called by core IBC when a `LightClientModule` is added to the router. It allows the `LightClientModule` to set a `ClientStoreProvider` ([interface defined in `modules/core/exported`](https://github.com/cosmos/ibc-go/blob/06fd8eb5ee1697e3b43be7528a6e42f5e4a4613c/modules/core/exported/client.go#L49-L52)) which supplies isolated prefix client stores to IBC light client instances.
```
```suggestion
The `RegisterStoreProvider` method is called by core IBC when a `LightClientModule` is added to the router. It allows the `LightClientModule` to set a `ClientStoreProvider` ([interface defined in `modules/core/exported`](https://github.com/cosmos/ibc-go/blob/06fd8eb5ee1697e3b43be7528a6e42f5e4a4613c/modules/core/exported/client.go#L49-L52)) which supplies isolated prefix client stores to IBC light client instances.


## `Status` method

`Status` must return the status of the client.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -26,13 +30,25 @@ This field is returned in the response of the gRPC [`ibc.core.client.v1.Query/Cl
`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.

## `LatestHeight` method

`LatestHeight` should return the latest block height that the client state represents.

## `Initialize` method

Clients must validate the initial consensus state, and set the initial client state and consensus state in the provided client store.
Clients may also store any necessary client-specific metadata.

`Initialize` is called when a [client is created](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L30).

## `UpdateState` method

`UpdateState` updates and stores as necessary any associated information for an IBC client, such as the `ClientState` and corresponding `ConsensusState`. See section [`UpdateState`](05-updates-and-misbehaviour.md#updatestate) for more information.

## `UpdateStateOnMisbehaviour` method

`UpdateStateOnMisbehaviour` should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. See section [`UpdateStateOnMisbehaviour`](05-updates-and-misbehaviour.md#updatestateonmisbehaviour) for more information.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Insert a comma for better readability.

- `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.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
`UpdateStateOnMisbehaviour` should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. See section [`UpdateStateOnMisbehaviour`](05-updates-and-misbehaviour.md#updatestateonmisbehaviour) for more information.
`UpdateStateOnMisbehaviour` should perform appropriate state changes on a client state, given that misbehaviour has been detected and verified. See section [`UpdateStateOnMisbehaviour`](05-updates-and-misbehaviour.md#updatestateonmisbehaviour) for more information.


## `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
Expand All @@ -48,9 +64,17 @@ see the [Existence and non-existence proofs section](07-proofs.md).
`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.
if the ClientMessage fails to verify. See section [`VerifyClientMessage`](05-updates-and-misbehaviour.md#verifyclientmessage) for more information.

## `CheckForMisbehaviour` method

Checks for evidence of a misbehaviour in `Header` or `Misbehaviour` type. It assumes the `ClientMessage`
has already been verified.
has already been verified. See section [`CheckForMisbehaviour`](05-updates-and-misbehaviour.md#checkformisbehaviour) for more information.

## `RecoverClient` method

`RecoverClient` is used to recover an expired or frozen client by updating the client with the state of a substitute client. The method must verify that the provided substitute may be used to update the subject client. See section [Implementing `RecoverClient`](./08-proposals.md#implementing-recoverclient) for more information.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved

## `VerifyUpgradeAndUpdateState` method

`VerifyUpgradeAndUpdateState` provides a path to upgrading clients given an upgraded `ClientState`, upgraded `ConsensusState` and proofs for each. See section [Implementing `VerifyUpgradeAndUpdateState`](./06-upgrades.md#implementing-verifyupgradeandupdatestate) for more information.
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,16 @@ slug: /ibc/light-clients/updates-and-misbehaviour

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
- a single header,
charleenfei marked this conversation as resolved.
Show resolved Hide resolved
- a batch of headers,
- evidence of misbehaviour,
- or any type which when verified produces a change to the consensus state of the IBC client.

This interface has been purposefully kept generic in order to give the maximum amount of flexibility to the light client implementer.

## Implementing the `ClientMessage` interface

Find the `ClientMessage`interface in `modules/core/exported`:
Find the `ClientMessage` interface in `modules/core/exported`:

```go
type ClientMessage interface {
Expand All @@ -30,20 +30,20 @@ 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](03-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 `LightClientModule` by client type (parsed from the client ID available in `MsgUpdateClient`). This `LightClientModule` implements the [`LightClientModule` interface](02-light-client-module.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`.
`UpdateClient` will then handle a number of cases including misbehaviour and/or updating the consensus state, utilizing the specific methods defined in the relevant `LightClientModule`.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved

```go
VerifyClientMessage(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) error
CheckForMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) bool
UpdateStateOnMisbehaviour(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage)
UpdateState(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, clientMsg ClientMessage) []Height
VerifyClientMessage(ctx sdk.Context, clientID string, clientMsg ClientMessage) error
CheckForMisbehaviour(ctx sdk.Context, clientID string, clientMsg ClientMessage) bool
UpdateStateOnMisbehaviour(ctx sdk.Context, clientID string, clientMsg ClientMessage)
UpdateState(ctx sdk.Context, clientID string, clientMsg ClientMessage) []Height
```

## Handling updates and misbehaviour

The functions for handling updates to a light client and evidence of misbehaviour are all found in the [`ClientState`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L36) interface, and will be discussed below.
The functions for handling updates to a light client and evidence of misbehaviour are all found in the [`LightClientModule`](https://github.com/cosmos/ibc-go/blob/501a8462345da099144efe91d495bfcfa18d760d/modules/core/exported/client.go#L51) interface, and will be discussed below.

> It is important to note that `Misbehaviour` in this particular context is referring to misbehaviour on the chain level intended to fool the light client. This will be defined by each light client.

Expand All @@ -53,46 +53,52 @@ The functions for handling updates to a light client and evidence of misbehaviou

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.

For an example of a `VerifyClientMessage` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/update.go#L20).
For an example of a `VerifyClientMessage` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/76730ff030b52a351096ee941b7e4da44af9f059/modules/light-clients/07-tendermint/update.go#L23).

## `CheckForMisbehaviour`

Checks for evidence of a misbehaviour in `Header` or `Misbehaviour` type. It assumes the `ClientMessage` has already been verified.

For an example of a `CheckForMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/misbehaviour_handle.go#L19).
For an example of a `CheckForMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/76730ff030b52a351096ee941b7e4da44af9f059/modules/light-clients/07-tendermint/misbehaviour_handle.go#L22).

> The Tendermint light client [defines `Misbehaviour`](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/misbehaviour.go) as two different types of situations: a situation where two conflicting `Header`s with the same height have been submitted to update a client's `ConsensusState` within the same trusting period, or that the two conflicting `Header`s have been submitted at different heights but the consensus states are not in the correct monotonic time ordering (BFT time violation). More explicitly, updating to a new height must have a timestamp greater than the previous consensus state, or, if inserting a consensus at a past height, then time must be less than those heights which come after and greater than heights which come before.
charleenfei marked this conversation as resolved.
Show resolved Hide resolved

## `UpdateStateOnMisbehaviour`

`UpdateStateOnMisbehaviour` should perform appropriate state changes on a client state given that misbehaviour has been detected and verified. This method should only be called when misbehaviour is detected, as it does not perform any misbehaviour checks. Notably, it should freeze the client so that calling the `Status` function on the associated client state no longer returns `Active`.

For an example of a `UpdateStateOnMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/update.go#L199).
For an example of a `UpdateStateOnMisbehaviour` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/76730ff030b52a351096ee941b7e4da44af9f059/modules/light-clients/07-tendermint/update.go#L202).

## `UpdateState`

`UpdateState` updates and stores as necessary any associated information for an IBC client, such as the `ClientState` and corresponding `ConsensusState`. It should perform a no-op on duplicate updates.

It assumes the `ClientMessage` has already been verified.

For an example of a `UpdateState` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/update.go#L131).
For an example of a `UpdateState` implementation, please check the [Tendermint light client](https://github.com/cosmos/ibc-go/blob/76730ff030b52a351096ee941b7e4da44af9f059/modules/light-clients/07-tendermint/update.go#L134).

## Putting it all together

The `02-client` `Keeper` module in ibc-go offers a reference as to how these functions will be used to [update the client](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/02-client/keeper/client.go#L48).

```go
if err := clientState.VerifyClientMessage(clientMessage); err != nil {
clientModule, found := k.router.GetRoute(clientID)
if !found {
return errorsmod.Wrap(types.ErrRouteNotFound, clientID)
}

if err := clientModule.VerifyClientMessage(ctx, clientID, clientMsg); err != nil {
return err
}

foundMisbehaviour := clientState.CheckForMisbehaviour(clientMessage)
foundMisbehaviour := clientModule.CheckForMisbehaviour(ctx, clientID, clientMsg)
if foundMisbehaviour {
clientState.UpdateStateOnMisbehaviour(clientMessage)
clientModule.UpdateStateOnMisbehaviour(ctx, clientID, clientMsg)
// emit misbehaviour event
return
}

clientState.UpdateState(clientMessage) // expects no-op on duplicate header
clientModule.UpdateState(ctx, clientID, clientMsg) // expects no-op on duplicate header
// emit update event
return
```
19 changes: 11 additions & 8 deletions docs/docs/03-light-clients/01-developer-guide/06-upgrades.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,23 @@ It is vital that high-value IBC clients can upgrade along with their underlying
The IBC protocol allows client implementations to provide a path to upgrading clients given the upgraded `ClientState`, upgraded `ConsensusState` and proofs for each. This path is provided in the `VerifyUpgradeAndUpdateState` method:

```go
// 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.
// 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.
func (cs ClientState) VerifyUpgradeAndUpdateState(
func (l LightClientModule) VerifyUpgradeAndUpdateState(
ctx sdk.Context,
cdc codec.BinaryCodec,
store sdk.KVStore,
newClient ClientState,
newConsState ConsensusState,
clientID string,
newClient []byte,
newConsState []byte,
upgradeClientProof,
upgradeConsensusStateProof []byte,
) error
```

> Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/light-clients/07-tendermint/upgrade.go#L27) as an example for implementation.
> Please refer to the [Tendermint light client implementation](https://github.com/cosmos/ibc-go/blob/47162061bcbfe74df791161059715a635e31c604/modules/light-clients/07-tendermint/light_client_module.go#L257) as an example for implementation.

It is important to note that light clients **must** handle all management of client and consensus states including the setting of updated `ClientState` and `ConsensusState` in the client store. This can include verifying that the submitted upgraded `ClientState` is of a valid `ClientState` type, that the height of the upgraded client is not greater than the height of the current client (in order to preserve BFT monotonic time), or that certain parameters which should not be changed have not been altered in the upgraded `ClientState`.

Expand All @@ -38,6 +40,7 @@ Developers must ensure that the `MsgUpgradeClient` does not pass until the last
### Upgrade path

Clients should have **prior knowledge of the merkle path** that the upgraded client and upgraded consensus states will use. The height at which the upgrade has occurred should also be encoded in the proof.

> The Tendermint client implementation accomplishes this by including an `UpgradePath` in the `ClientState` itself, which is used along with the upgrade height to construct the merkle path under which the client state and consensus state are committed.

## Chain specific vs client specific client parameters
Expand Down
17 changes: 11 additions & 6 deletions docs/docs/03-light-clients/01-developer-guide/07-proofs.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ For the purposes of ibc-go, there are two types of proofs which are important: e

Existence proofs are used in IBC transactions which involve verification of counterparty state for transactions which will result in the writing of provable state. For example, this includes verification of IBC store state for handshakes and packets.

Put simply, existence proofs prove that a particular key and value exists in the tree. Under the hood, an IBC existence proof comprises of two proofs: an IAVL proof that the key exists in IBC store/IBC root hash, and a proof that the IBC root hash exists in the multistore root hash.
Put simply, existence proofs prove that a particular key and value exists in the tree. Under the hood, an IBC existence proof is comprised of two proofs: an IAVL proof that the key exists in IBC store/IBC root hash, and a proof that the IBC root hash exists in the multistore root hash.

## Non-existence proofs

Expand All @@ -32,13 +32,16 @@ In some cases, there is a necessity to "mock" non-existence proofs if the counte

The state verification functions for all IBC data types have been consolidated into two generic methods, `VerifyMembership` and `VerifyNonMembership`.

From the [`ClientState` interface definition](https://github.com/cosmos/ibc-go/blob/v7.0.0/modules/core/exported/client.go#L68-L91), we find:
From the [`LightClientModule` interface definition](https://github.com/cosmos/ibc-go/blob/main/modules/core/exported/client.go#L56), we find:

```go
// 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 sdk.KVStore,
cdc codec.BinaryCodec,
clientID string,
height Height,
delayTimePeriod uint64,
delayBlockPeriod uint64,
charleenfei marked this conversation as resolved.
Show resolved Hide resolved
Expand All @@ -47,8 +50,10 @@ VerifyMembership(
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 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 sdk.KVStore,
Expand Down