Skip to content

Commit

Permalink
chore: Add HasConnection and HasChannel methods. (#3082)
Browse files Browse the repository at this point in the history
(cherry picked from commit b2fb119)

# Conflicts:
#	CHANGELOG.md
#	modules/core/02-client/migrations/v7/store.go
#	modules/light-clients/07-tendermint/types/store.go
  • Loading branch information
fedekunze authored and mergify[bot] committed May 5, 2023
1 parent 2d8f1e0 commit 2e5f08a
Show file tree
Hide file tree
Showing 9 changed files with 272 additions and 19 deletions.
30 changes: 30 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,36 @@ Ref: https://keepachangelog.com/en/1.0.0/

### Improvements

<<<<<<< HEAD
=======
* (core) [\#3082](https://github.com/cosmos/ibc-go/pull/3082) Add `HasConnection` and `HasChannel` methods.
* (tests) [\#2926](https://github.com/cosmos/ibc-go/pull/2926) Lint tests
* (apps/transfer) [\#2643](https://github.com/cosmos/ibc-go/pull/2643) Add amount, denom, and memo to transfer event emission.
* (core) [\#2746](https://github.com/cosmos/ibc-go/pull/2746) Allow proof height to be zero for all core IBC `sdk.Msg` types that contain proofs.
* (light-clients/06-solomachine) [\#2746](https://github.com/cosmos/ibc-go/pull/2746) Discard proofHeight for solo machines and use the solo machine sequence instead.
* (modules/light-clients/07-tendermint) [\#1713](https://github.com/cosmos/ibc-go/pull/1713) Allow client upgrade proposals to update `TrustingPeriod`. See ADR-026 for context.
* (modules/core/02-client) [\#1188](https://github.com/cosmos/ibc-go/pull/1188/files) Routing `MsgSubmitMisbehaviour` to `UpdateClient` keeper function. Deprecating `SubmitMisbehaviour` endpoint.
* (modules/core/02-client) [\#1208](https://github.com/cosmos/ibc-go/pull/1208) Replace `CheckHeaderAndUpdateState` usage in 02-client with calls to `VerifyClientMessage`, `CheckForMisbehaviour`, `UpdateStateOnMisbehaviour` and `UpdateState`.
* (modules/light-clients/09-localhost) [\#1187](https://github.com/cosmos/ibc-go/pull/1187/) Removing localhost light client implementation as it is not functional. An upgrade handler is provided in `modules/migrations/v5` to prune `09-localhost` clients and consensus states from the store.
* [\#1186](https://github.com/cosmos/ibc-go/pull/1186/files) Removing `GetRoot` function from ConsensusState interface in `02-client`. `GetRoot` is unused by core IBC.
* (modules/core/02-client) [\#1196](https://github.com/cosmos/ibc-go/pull/1196) Adding VerifyClientMessage to ClientState interface.
* (modules/core/02-client) [\#1198](https://github.com/cosmos/ibc-go/pull/1198) Adding UpdateStateOnMisbehaviour to ClientState interface.
* (modules/core/02-client) [\#1170](https://github.com/cosmos/ibc-go/pull/1170) Updating `ClientUpdateProposal` to set client state in lightclient implementations `CheckSubstituteAndUpdateState` methods.
* (modules/core/02-client) [\#1197](https://github.com/cosmos/ibc-go/pull/1197) Adding `CheckForMisbehaviour` to `ClientState` interface.
* (modules/core/02-client) [\#1195](https://github.com/cosmos/ibc-go/pull/1210) Removing `CheckHeaderAndUpdateState` from `ClientState` interface & associated light client implementations.
* (modules/core/02-client) [\#1189](https://github.com/cosmos/ibc-go/pull/1212) Removing `CheckMisbehaviourAndUpdateState` from `ClientState` interface & associated light client implementations.
* (modules/core/exported) [\#1206](https://github.com/cosmos/ibc-go/pull/1206) Adding new method `UpdateState` to `ClientState` interface.
* (modules/core/02-client) [\#1741](https://github.com/cosmos/ibc-go/pull/1741) Emitting a new `upgrade_chain` event upon setting upgrade consensus state.
* (client) [\#724](https://github.com/cosmos/ibc-go/pull/724) `IsRevisionFormat` and `IsClientIDFormat` have been updated to disallow newlines before the dash used to separate the chainID and revision number, and the client type and client sequence.
* (02-client/cli) [\#897](https://github.com/cosmos/ibc-go/pull/897) Remove `GetClientID()` from `Misbehaviour` interface. Submit client misbehaviour cli command requires an explicit client id now.
* (06-solomachine) [\#1972](https://github.com/cosmos/ibc-go/pull/1972) Solo machine implementation of `ZeroCustomFields` fn now panics as the fn is only used for upgrades which solo machine does not support.
* (light-clients/06-solomachine) Moving `verifyMisbehaviour` function from update.go to misbehaviour_handle.go.
* [\#2434](https://github.com/cosmos/ibc-go/pull/2478) Removed all `TypeMsg` constants
* (modules/core/exported) [#1689] (https://github.com/cosmos/ibc-go/pull/2539) Removing `GetVersions` from `ConnectionI` interface.
* (core/02-connection) [#2419](https://github.com/cosmos/ibc-go/pull/2419) Add optional proof data to proto definitions of `MsgConnectionOpenTry` and `MsgConnectionOpenAck` for host state machines that are unable to introspect their own consensus state.
* (modules/light-clients/07-tendermint) [#2007](https://github.com/cosmos/ibc-go/pull/3046) Moved non-verification misbehaviour checks to `CheckForMisbehaviour`

>>>>>>> b2fb1192 (chore: Add `HasConnection` and `HasChannel` methods. (#3082))
### Features

### Bug Fixes
Expand Down
2 changes: 1 addition & 1 deletion modules/apps/29-fee/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -291,7 +291,7 @@ func (k Keeper) GetFeesInEscrow(ctx sdk.Context, packetID channeltypes.PacketId)
store := ctx.KVStore(k.storeKey)
key := types.KeyFeesInEscrow(packetID)
bz := store.Get(key)
if bz == nil {
if len(bz) == 0 {
return types.PacketFees{}, false
}

Expand Down
2 changes: 1 addition & 1 deletion modules/apps/transfer/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ func (k Keeper) SetPort(ctx sdk.Context, portID string) {
func (k Keeper) GetDenomTrace(ctx sdk.Context, denomTraceHash tmbytes.HexBytes) (types.DenomTrace, bool) {
store := prefix.NewStore(ctx.KVStore(k.storeKey), types.DenomTraceKey)
bz := store.Get(denomTraceHash)
if bz == nil {
if len(bz) == 0 {
return types.DenomTrace{}, false
}

Expand Down
6 changes: 3 additions & 3 deletions modules/core/02-client/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (k Keeper) GenerateClientIdentifier(ctx sdk.Context, clientType string) str
func (k Keeper) GetClientState(ctx sdk.Context, clientID string) (exported.ClientState, bool) {
store := k.ClientStore(ctx, clientID)
bz := store.Get(host.ClientStateKey())
if bz == nil {
if len(bz) == 0 {
return nil, false
}

Expand All @@ -85,7 +85,7 @@ func (k Keeper) SetClientState(ctx sdk.Context, clientID string, clientState exp
func (k Keeper) GetClientConsensusState(ctx sdk.Context, clientID string, height exported.Height) (exported.ConsensusState, bool) {
store := k.ClientStore(ctx, clientID)
bz := store.Get(host.ConsensusStateKey(height))
if bz == nil {
if len(bz) == 0 {
return nil, false
}

Expand All @@ -104,7 +104,7 @@ func (k Keeper) SetClientConsensusState(ctx sdk.Context, clientID string, height
func (k Keeper) GetNextClientSequence(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get([]byte(types.KeyNextClientSequence))
if bz == nil {
if len(bz) == 0 {
panic("next client sequence is nil")
}

Expand Down
205 changes: 205 additions & 0 deletions modules/core/02-client/migrations/v7/store.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
package v7

import (
"fmt"
"strings"

"github.com/cosmos/cosmos-sdk/codec"
codectypes "github.com/cosmos/cosmos-sdk/codec/types"
storetypes "github.com/cosmos/cosmos-sdk/store/types"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"

clienttypes "github.com/cosmos/ibc-go/v7/modules/core/02-client/types"
host "github.com/cosmos/ibc-go/v7/modules/core/24-host"
"github.com/cosmos/ibc-go/v7/modules/core/exported"
solomachine "github.com/cosmos/ibc-go/v7/modules/light-clients/06-solomachine"
ibctm "github.com/cosmos/ibc-go/v7/modules/light-clients/07-tendermint"
)

// Localhost is the client type for a localhost client. It is also used as the clientID
// for the localhost client.
const Localhost string = "09-localhost"

// MigrateStore performs in-place store migrations from ibc-go v6 to ibc-go v7.
// The migration includes:
//
// - Migrating solo machine client states from v2 to v3 protobuf definition
// - Pruning all solo machine consensus states
// - Removing the localhost client
// - Asserting existing tendermint clients are properly registered on the chain codec
func MigrateStore(ctx sdk.Context, storeKey storetypes.StoreKey, cdc codec.BinaryCodec, clientKeeper ClientKeeper) error {
store := ctx.KVStore(storeKey)

if err := handleSolomachineMigration(ctx, store, cdc, clientKeeper); err != nil {
return err
}

if err := handleTendermintMigration(ctx, store, cdc, clientKeeper); err != nil {
return err
}

if err := handleLocalhostMigration(ctx, store, cdc, clientKeeper); err != nil {
return err
}

return nil
}

// handleSolomachineMigration iterates over the solo machine clients and migrates client state from
// protobuf definition v2 to v3. All consensus states stored outside of the client state are pruned.
func handleSolomachineMigration(ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, clientKeeper ClientKeeper) error {
clients, err := collectClients(ctx, store, exported.Solomachine)
if err != nil {
return err
}

for _, clientID := range clients {
clientStore := clientKeeper.ClientStore(ctx, clientID)

bz := clientStore.Get(host.ClientStateKey())
if len(bz) == 0 {
return sdkerrors.Wrapf(clienttypes.ErrClientNotFound, "clientID %s", clientID)
}

var any codectypes.Any
if err := cdc.Unmarshal(bz, &any); err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into solo machine client state")
}

var clientState ClientState
if err := cdc.Unmarshal(any.Value, &clientState); err != nil {
return sdkerrors.Wrap(err, "failed to unmarshal client state bytes into solo machine client state")
}

updatedClientState := migrateSolomachine(clientState)

// update solomachine in store
clientKeeper.SetClientState(ctx, clientID, &updatedClientState)

removeAllClientConsensusStates(clientStore)
}

return nil
}

// handlerTendermintMigration asserts that the tendermint client in state can be decoded properly.
// This ensures the upgrading chain properly registered the tendermint client types on the chain codec.
func handleTendermintMigration(ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, clientKeeper ClientKeeper) error {
clients, err := collectClients(ctx, store, exported.Tendermint)
if err != nil {
return err
}

if len(clients) == 0 {
return nil // no-op if no tm clients exist
}

if len(clients) > 1 {
return sdkerrors.Wrap(sdkerrors.ErrLogic, "more than one Tendermint client collected")
}

clientID := clients[0]

// unregistered tendermint client types will panic when unmarshaling the client state
// in GetClientState
clientState, ok := clientKeeper.GetClientState(ctx, clientID)
if !ok {
return sdkerrors.Wrapf(clienttypes.ErrClientNotFound, "clientID %s", clientID)
}

_, ok = clientState.(*ibctm.ClientState)
if !ok {
return sdkerrors.Wrap(clienttypes.ErrInvalidClient, "client state is not tendermint even though client id contains 07-tendermint")
}

return nil
}

// handleLocalhostMigration removes all client and consensus states associated with the localhost client type.
func handleLocalhostMigration(ctx sdk.Context, store sdk.KVStore, cdc codec.BinaryCodec, clientKeeper ClientKeeper) error {
clients, err := collectClients(ctx, store, Localhost)
if err != nil {
return err
}

for _, clientID := range clients {
clientStore := clientKeeper.ClientStore(ctx, clientID)

// delete the client state
clientStore.Delete(host.ClientStateKey())

removeAllClientConsensusStates(clientStore)
}

return nil
}

// collectClients will iterate over the provided client type prefix in the client store
// and return a list of clientIDs associated with the client type. This is necessary to
// avoid state corruption as modifying state during iteration is unsafe. A special case
// for tendermint clients is included as only one tendermint clientID is required for
// v7 migrations.
func collectClients(ctx sdk.Context, store sdk.KVStore, clientType string) (clients []string, err error) {
clientPrefix := []byte(fmt.Sprintf("%s/%s", host.KeyClientStorePrefix, clientType))
iterator := sdk.KVStorePrefixIterator(store, clientPrefix)

defer sdk.LogDeferred(ctx.Logger(), func() error { return iterator.Close() })
for ; iterator.Valid(); iterator.Next() {
path := string(iterator.Key())
if !strings.Contains(path, host.KeyClientState) {
// skip non client state keys
continue
}

clientID := host.MustParseClientStatePath(path)
clients = append(clients, clientID)

// optimization: exit after a single tendermint client iteration
if strings.Contains(clientID, exported.Tendermint) {
return clients, nil
}
}

return clients, nil
}

// removeAllClientConsensusStates removes all client consensus states from the associated
// client store.
func removeAllClientConsensusStates(clientStore sdk.KVStore) {
iterator := sdk.KVStorePrefixIterator(clientStore, []byte(host.KeyConsensusStatePrefix))
var heights []exported.Height

defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
keySplit := strings.Split(string(iterator.Key()), "/")
// key is in the format "consensusStates/<height>"
if len(keySplit) != 2 || keySplit[0] != string(host.KeyConsensusStatePrefix) {
continue
}

// collect consensus states to be pruned
heights = append(heights, clienttypes.MustParseHeight(keySplit[1]))
}

// delete all consensus states
for _, height := range heights {
clientStore.Delete(host.ConsensusStateKey(height))
}
}

// migrateSolomachine migrates the solomachine from v2 to v3 solo machine protobuf definition.
// Notably it drops the AllowUpdateAfterProposal field.
func migrateSolomachine(clientState ClientState) solomachine.ClientState {
consensusState := &solomachine.ConsensusState{
PublicKey: clientState.ConsensusState.PublicKey,
Diversifier: clientState.ConsensusState.Diversifier,
Timestamp: clientState.ConsensusState.Timestamp,
}

return solomachine.ClientState{
Sequence: clientState.Sequence,
IsFrozen: clientState.IsFrozen,
ConsensusState: consensusState,
}
}
13 changes: 10 additions & 3 deletions modules/core/03-connection/keeper/keeper.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ func (k Keeper) GenerateConnectionIdentifier(ctx sdk.Context) string {
func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.ConnectionEnd, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.ConnectionKey(connectionID))
if bz == nil {
if len(bz) == 0 {
return types.ConnectionEnd{}, false
}

Expand All @@ -76,6 +76,13 @@ func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.Conne
return connection, true
}

// HasConnection returns a true if the connection with the given identifier
// exists in the store.
func (k Keeper) HasConnection(ctx sdk.Context, connectionID string) bool {
store := ctx.KVStore(k.storeKey)
return store.Has(host.ConnectionKey(connectionID))
}

// SetConnection sets a connection to the store
func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) {
store := ctx.KVStore(k.storeKey)
Expand Down Expand Up @@ -105,7 +112,7 @@ func (k Keeper) GetTimestampAtHeight(ctx sdk.Context, connection types.Connectio
func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]string, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.ClientConnectionsKey(clientID))
if bz == nil {
if len(bz) == 0 {
return nil, false
}

Expand All @@ -126,7 +133,7 @@ func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths
func (k Keeper) GetNextConnectionSequence(ctx sdk.Context) uint64 {
store := ctx.KVStore(k.storeKey)
bz := store.Get([]byte(types.KeyNextConnectionSequence))
if bz == nil {
if len(bz) == 0 {
panic("next connection sequence is nil")
}

Expand Down
Loading

0 comments on commit 2e5f08a

Please sign in to comment.