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

refactor: require light clients to set initial client and consensus state #2936

Merged
merged 11 commits into from
Dec 15, 2022
5 changes: 3 additions & 2 deletions docs/ibc/light-clients/client-state.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,10 @@ This value is used to facilitate timeouts by checking the packet timeout timesta

## `Initialize` method

Clients must validate the initial consensus state, and may store any client-specific metadata necessary.
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 client-specific metadata necessary.
damiannolan marked this conversation as resolved.
Show resolved Hide resolved

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

## `VerifyMembership` method

Expand Down
4 changes: 3 additions & 1 deletion docs/migrations/v6-to-v7.md
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,9 @@ The `VerifyUpgradeAndUpdateState` function has been modified. The client state a

Light clients **must** handle all management of client and consensus states including the setting of updated client state and consensus state in the client store.

The `CheckHeaderAndUpdateState` function has been split into 4 new functions:
The `Initialize` method is now expected to set the initial client state, consensus state and any client-specific metadata in the provided store upon client creation.

The `CheckHeaderAndUpdateState` method has been split into 4 new methods:

- `VerifyClientMessage` verifies a `ClientMessage`. A `ClientMessage` could be a `Header`, `Misbehaviour`, or batch update. 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.

Expand Down
15 changes: 5 additions & 10 deletions modules/core/02-client/keeper/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ import (
"github.com/cosmos/ibc-go/v6/modules/core/exported"
)

// CreateClient creates a new client state and populates it with a given consensus
// state as defined in https://github.com/cosmos/ibc/tree/master/spec/core/ics-002-client-semantics#create
// 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, clientState exported.ClientState, consensusState exported.ConsensusState,
) (string, error) {
Expand All @@ -24,18 +25,12 @@ func (k Keeper) CreateClient(
}

clientID := k.GenerateClientIdentifier(ctx, clientState.ClientType())
clientStore := k.ClientStore(ctx, clientID)

k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String())
damiannolan marked this conversation as resolved.
Show resolved Hide resolved

// verifies initial consensus state against client state and initializes client store with any client-specific metadata
// e.g. set ProcessedTime in Tendermint clients
if err := clientState.Initialize(ctx, k.cdc, k.ClientStore(ctx, clientID), consensusState); err != nil {
if err := clientState.Initialize(ctx, k.cdc, clientStore, consensusState); err != nil {
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
return "", err
}

k.SetClientState(ctx, clientID, clientState)
k.SetClientConsensusState(ctx, clientID, clientState.GetLatestHeight(), consensusState)

k.Logger(ctx).Info("client created at height", "client-id", clientID, "height", clientState.GetLatestHeight().String())

defer telemetry.IncrCounterWithLabels(
Expand Down
5 changes: 2 additions & 3 deletions modules/core/exported/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,8 @@ type ClientState interface {
height Height,
) (uint64, error)

// Initialization function
// Clients must validate the initial consensus state, and may store any client-specific metadata
// necessary for correct light client operation
// 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 sdk.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.
Expand Down
8 changes: 6 additions & 2 deletions modules/light-clients/06-solomachine/client_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,12 +77,16 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState {
panic("ZeroCustomFields is not implemented as the solo machine implementation does not support upgrades.")
}

// Initialize will check that initial consensus state is equal to the latest consensus state of the initial client.
func (cs ClientState) Initialize(_ sdk.Context, _ codec.BinaryCodec, _ sdk.KVStore, consState exported.ConsensusState) error {
// Initialize checks that the initial consensus state is equal to the latest consensus state of the initial client and
// sets the client state in the provided client store.
func (cs ClientState) Initialize(_ sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error {
if !reflect.DeepEqual(cs.ConsensusState, consState) {
return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "consensus state in initial client does not equal initial consensus state. expected: %s, got: %s",
cs.ConsensusState, consState)
}

setClientState(clientStore, cdc, &cs)
colin-axner marked this conversation as resolved.
Show resolved Hide resolved

return nil
}

Expand Down
14 changes: 9 additions & 5 deletions modules/light-clients/07-tendermint/client_state.go
Original file line number Diff line number Diff line change
Expand Up @@ -188,15 +188,19 @@ func (cs ClientState) ZeroCustomFields() exported.ClientState {
}
}

// Initialize will check that initial consensus state is a Tendermint consensus state
// and will store ProcessedTime for initial consensus state as ctx.BlockTime()
func (cs ClientState) Initialize(ctx sdk.Context, _ codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error {
if _, ok := consState.(*ConsensusState); !ok {
// Initialize checks that the initial consensus state is a 07-tendermint consensus state and
damiannolan marked this conversation as resolved.
Show resolved Hide resolved
// sets the client state, consensus state and associated metatdata in the provided client store.
damiannolan marked this conversation as resolved.
Show resolved Hide resolved
func (cs ClientState) Initialize(ctx sdk.Context, cdc codec.BinaryCodec, clientStore sdk.KVStore, consState exported.ConsensusState) error {
consensusState, ok := consState.(*ConsensusState)
if !ok {
return sdkerrors.Wrapf(clienttypes.ErrInvalidConsensus, "invalid initial consensus state. expected type: %T, got: %T",
&ConsensusState{}, consState)
}
// set metadata for initial consensus state.

setClientState(clientStore, cdc, &cs)
setConsensusState(clientStore, cdc, consensusState, cs.GetLatestHeight())
colin-axner marked this conversation as resolved.
Show resolved Hide resolved
setConsensusMetadata(ctx, clientStore, cs.GetLatestHeight())

return nil
}

Expand Down