cosmos-sdk/x/ibc/03-connection/keeper/keeper.go

191 lines
6.3 KiB
Go

package keeper
import (
"fmt"
"github.com/tendermint/tendermint/libs/log"
"github.com/cosmos/cosmos-sdk/codec"
sdk "github.com/cosmos/cosmos-sdk/types"
sdkerrors "github.com/cosmos/cosmos-sdk/types/errors"
clientexported "github.com/cosmos/cosmos-sdk/x/ibc/02-client/exported"
clienttypes "github.com/cosmos/cosmos-sdk/x/ibc/02-client/types"
"github.com/cosmos/cosmos-sdk/x/ibc/03-connection/types"
commitmentexported "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/exported"
commitmenttypes "github.com/cosmos/cosmos-sdk/x/ibc/23-commitment/types"
host "github.com/cosmos/cosmos-sdk/x/ibc/24-host"
)
// Keeper defines the IBC connection keeper
type Keeper struct {
storeKey sdk.StoreKey
aminoCdc *codec.Codec // amino codec. TODO: remove after clients have been migrated to proto
cdc codec.Marshaler // hybrid codec
clientKeeper types.ClientKeeper
}
// NewKeeper creates a new IBC connection Keeper instance
func NewKeeper(aminoCdc *codec.Codec, cdc codec.Marshaler, key sdk.StoreKey, ck types.ClientKeeper) Keeper {
return Keeper{
storeKey: key,
aminoCdc: aminoCdc,
cdc: cdc,
clientKeeper: ck,
}
}
// Logger returns a module-specific logger.
func (k Keeper) Logger(ctx sdk.Context) log.Logger {
return ctx.Logger().With("module", fmt.Sprintf("x/%s/%s", host.ModuleName, types.SubModuleName))
}
// GetCommitmentPrefix returns the IBC connection store prefix as a commitment
// Prefix
func (k Keeper) GetCommitmentPrefix() commitmentexported.Prefix {
return commitmenttypes.NewMerklePrefix([]byte(k.storeKey.Name()))
}
// GetConnection returns a connection with a particular identifier
func (k Keeper) GetConnection(ctx sdk.Context, connectionID string) (types.ConnectionEnd, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.KeyConnection(connectionID))
if bz == nil {
return types.ConnectionEnd{}, false
}
var connection types.ConnectionEnd
k.cdc.MustUnmarshalBinaryBare(bz, &connection)
return connection, true
}
// SetConnection sets a connection to the store
func (k Keeper) SetConnection(ctx sdk.Context, connectionID string, connection types.ConnectionEnd) {
store := ctx.KVStore(k.storeKey)
bz := k.cdc.MustMarshalBinaryBare(&connection)
store.Set(host.KeyConnection(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 uint64) (uint64, error) {
consensusState, found := k.clientKeeper.GetClientConsensusState(
ctx, connection.GetClientID(), height,
)
if !found {
return 0, sdkerrors.Wrapf(
clienttypes.ErrConsensusStateNotFound,
"clientID (%s), height (%d)", connection.GetClientID(), height,
)
}
return consensusState.GetTimestamp(), nil
}
// GetClientConnectionPaths returns all the connection paths stored under a
// particular client
func (k Keeper) GetClientConnectionPaths(ctx sdk.Context, clientID string) ([]string, bool) {
store := ctx.KVStore(k.storeKey)
bz := store.Get(host.KeyClientConnections(clientID))
if bz == nil {
return nil, false
}
var clientPaths types.ClientPaths
k.cdc.MustUnmarshalBinaryBare(bz, &clientPaths)
return clientPaths.Paths, true
}
// SetClientConnectionPaths sets the connections paths for client
func (k Keeper) SetClientConnectionPaths(ctx sdk.Context, clientID string, paths []string) {
store := ctx.KVStore(k.storeKey)
clientPaths := types.ClientPaths{Paths: paths}
bz := k.cdc.MustMarshalBinaryBare(&clientPaths)
store.Set(host.KeyClientConnections(clientID), bz)
}
// GetAllClientConnectionPaths returns all stored clients connection id paths. It
// will ignore the clients that haven't initialized a connection handshake since
// no paths are stored.
func (k Keeper) GetAllClientConnectionPaths(ctx sdk.Context) []types.ConnectionPaths {
var allConnectionPaths []types.ConnectionPaths
k.clientKeeper.IterateClients(ctx, func(cs clientexported.ClientState) bool {
paths, found := k.GetClientConnectionPaths(ctx, cs.GetID())
if !found {
// continue when connection handshake is not initialized
return false
}
connPaths := types.NewConnectionPaths(cs.GetID(), paths)
allConnectionPaths = append(allConnectionPaths, connPaths)
return false
})
return allConnectionPaths
}
// IterateConnections provides an iterator over all ConnectionEnd objects.
// For each ConnectionEnd, cb will be called. If the cb returns true, the
// iterator will close and stop.
func (k Keeper) IterateConnections(ctx sdk.Context, cb func(types.ConnectionEnd) bool) {
store := ctx.KVStore(k.storeKey)
iterator := sdk.KVStorePrefixIterator(store, host.KeyConnectionPrefix)
defer iterator.Close()
for ; iterator.Valid(); iterator.Next() {
var connection types.ConnectionEnd
k.cdc.MustUnmarshalBinaryBare(iterator.Value(), &connection)
if cb(connection) {
break
}
}
}
// GetAllConnections returns all stored ConnectionEnd objects.
func (k Keeper) GetAllConnections(ctx sdk.Context) (connections []types.ConnectionEnd) {
k.IterateConnections(ctx, func(connection types.ConnectionEnd) bool {
connections = append(connections, connection)
return false
})
return connections
}
// addConnectionToClient is used to add a connection identifier to the set of
// connections associated with a client.
func (k Keeper) addConnectionToClient(ctx sdk.Context, clientID, connectionID string) error {
_, found := k.clientKeeper.GetClientState(ctx, clientID)
if !found {
return clienttypes.ErrClientNotFound
}
conns, found := k.GetClientConnectionPaths(ctx, clientID)
if !found {
conns = []string{}
}
conns = append(conns, connectionID)
k.SetClientConnectionPaths(ctx, clientID, conns)
return nil
}
// removeConnectionFromClient is used to remove a connection identifier from the
// set of connections associated with a client.
//
// CONTRACT: client must already exist
// nolint: unused
func (k Keeper) removeConnectionFromClient(ctx sdk.Context, clientID, connectionID string) error {
conns, found := k.GetClientConnectionPaths(ctx, clientID)
if !found {
return sdkerrors.Wrap(types.ErrClientConnectionPathsNotFound, clientID)
}
conns, ok := host.RemovePath(conns, connectionID)
if !ok {
return sdkerrors.Wrap(types.ErrConnectionPath, clientID)
}
k.SetClientConnectionPaths(ctx, clientID, conns)
return nil
}