diff --git a/store/types/store.go b/store/types/store.go index 5b5e64742552..bd8a3d58c85a 100644 --- a/store/types/store.go +++ b/store/types/store.go @@ -277,6 +277,10 @@ type StoreKey interface { String() string } +// CapabilityKey represent the Cosmos SDK keys for object-capability +// generation in the IBC protocol as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#data-structures +type CapabilityKey StoreKey + // KVStoreKey is used for accessing substores. // Only the pointer value should ever be used - it functions as a capabilities key. type KVStoreKey struct { diff --git a/types/store.go b/types/store.go index c34b6d437d09..db18b127b69d 100644 --- a/types/store.go +++ b/types/store.go @@ -69,6 +69,7 @@ const ( // nolint - reexport type ( StoreKey = types.StoreKey + CapabilityKey = types.CapabilityKey KVStoreKey = types.KVStoreKey TransientStoreKey = types.TransientStoreKey ) diff --git a/x/ibc/05-port/alias.go b/x/ibc/05-port/alias.go new file mode 100644 index 000000000000..a74c7fe61537 --- /dev/null +++ b/x/ibc/05-port/alias.go @@ -0,0 +1,39 @@ +package port + +// nolint +// autogenerated code using github.com/rigelrozanski/multitool +// aliases generated for the following subdirectories: +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper +// ALIASGEN: github.com/cosmos/cosmos-sdk/x/ibc/05-port/types + +import ( + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/keeper" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" +) + +const ( + DefaultCodespace = types.DefaultCodespace + CodePortExists = types.CodePortExists + CodePortNotFound = types.CodePortNotFound + CodePortNotAuthenticated = types.CodePortNotAuthenticated + CodeInvalidPortID = types.CodeInvalidPortID + SubModuleName = types.SubModuleName + StoreKey = types.StoreKey + RouterKey = types.RouterKey + QuerierRoute = types.QuerierRoute +) + +var ( + // functions aliases + NewKeeper = keeper.NewKeeper + ErrPortExists = types.ErrPortExists + ErrPortNotFound = types.ErrPortNotFound + ErrPortNotAuthenticated = types.ErrPortNotAuthenticated + ErrInvalidPortID = types.ErrInvalidPortID + PortPath = types.PortPath + KeyPort = types.KeyPort +) + +type ( + Keeper = keeper.Keeper +) diff --git a/x/ibc/05-port/keeper/keeper.go b/x/ibc/05-port/keeper/keeper.go new file mode 100644 index 000000000000..5a7a9fb05bae --- /dev/null +++ b/x/ibc/05-port/keeper/keeper.go @@ -0,0 +1,77 @@ +package keeper + +import ( + "fmt" + + "github.com/cosmos/cosmos-sdk/codec" + sdk "github.com/cosmos/cosmos-sdk/types" + "github.com/cosmos/cosmos-sdk/x/ibc/05-port/types" + host "github.com/cosmos/cosmos-sdk/x/ibc/24-host" +) + +// Keeper defines the IBC connection keeper +type Keeper struct { + storeKey sdk.StoreKey + cdc *codec.Codec + codespace sdk.CodespaceType + prefix []byte // prefix bytes for accessing the store + ports map[sdk.CapabilityKey]string + bound []string +} + +// NewKeeper creates a new IBC connection Keeper instance +func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { + return Keeper{ + storeKey: key, + cdc: cdc, + codespace: sdk.CodespaceType(fmt.Sprintf("%s/%s", codespace, types.DefaultCodespace)), // "ibc/port", + prefix: []byte{}, + // prefix: []byte(types.SubModuleName + "/"), // "port/" + ports: make(map[sdk.CapabilityKey]string), // map of capabilities to port ids + } +} + +// GetPorts returns the list of bound ports. +// (these ports still must have been bound statically) +func (k Keeper) GetPorts() []string { + return k.bound +} + +// GetPort retrieves a given port ID from keeper map +func (k Keeper) GetPort(ck sdk.CapabilityKey) (string, bool) { + portID, found := k.ports[ck] + return portID, found +} + +// BindPort binds to a port and returns the associated capability. +// Ports must be bound statically when the chain starts in `app.go`. +// The capability must then be passed to a module which will need to pass +// it as an extra parameter when calling functions on the IBC module. +func (k Keeper) BindPort(portID string) sdk.CapabilityKey { + if err := host.DefaultPortIdentifierValidator(portID); err != nil { + panic(err.Error()) + } + + for _, b := range k.bound { + if b == portID { + panic(fmt.Sprintf("port %s is already bound", portID)) + } + } + + key := sdk.NewKVStoreKey(portID) + k.ports[key] = portID + k.bound = append(k.bound, portID) + return key +} + +// Authenticate authenticates a capability key against a port ID +// by checking if the memory address of the capability was previously +// generated and bound to the port (provided as a parameter) which the capability +// is being authenticated against. +func (k Keeper) Authenticate(key sdk.CapabilityKey, portID string) bool { + if err := host.DefaultPortIdentifierValidator(portID); err != nil { + panic(err.Error()) + } + + return k.ports[key] == portID +} diff --git a/x/ibc/05-port/types/errors.go b/x/ibc/05-port/types/errors.go new file mode 100644 index 000000000000..20031c826107 --- /dev/null +++ b/x/ibc/05-port/types/errors.go @@ -0,0 +1,37 @@ +package types + +import ( + "fmt" + + sdk "github.com/cosmos/cosmos-sdk/types" +) + +// port error codes +const ( + DefaultCodespace sdk.CodespaceType = SubModuleName + + CodePortExists sdk.CodeType = 101 + CodePortNotFound sdk.CodeType = 102 + CodePortNotAuthenticated sdk.CodeType = 103 + CodeInvalidPortID sdk.CodeType = 104 +) + +// ErrPortExists implements sdk.Error +func ErrPortExists(codespace sdk.CodespaceType, portID string) sdk.Error { + return sdk.NewError(codespace, CodePortExists, fmt.Sprintf("port with ID %s is already binded", portID)) +} + +// ErrPortNotFound implements sdk.Error +func ErrPortNotFound(codespace sdk.CodespaceType, portID string) sdk.Error { + return sdk.NewError(codespace, CodePortNotFound, fmt.Sprintf("port with ID %s not found", portID)) +} + +// ErrPortNotAuthenticated implements sdk.Error +func ErrPortNotAuthenticated(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodePortNotAuthenticated, "port failed authentication") +} + +// ErrInvalidPortID implements sdk.Error +func ErrInvalidPortID(codespace sdk.CodespaceType) sdk.Error { + return sdk.NewError(codespace, CodeInvalidPortID, "invalid port ID") +} diff --git a/x/ibc/05-port/types/keys.go b/x/ibc/05-port/types/keys.go new file mode 100644 index 000000000000..b1250e0e4463 --- /dev/null +++ b/x/ibc/05-port/types/keys.go @@ -0,0 +1,31 @@ +package types + +import ( + "fmt" +) + +const ( + // SubModuleName defines the IBC port name + SubModuleName = "port" + + // StoreKey is the store key string for IBC ports + StoreKey = SubModuleName + + // RouterKey is the message route for IBC ports + RouterKey = SubModuleName + + // QuerierRoute is the querier route for IBC ports + QuerierRoute = SubModuleName +) + +// The following paths are the keys to the store as defined in https://github.com/cosmos/ics/tree/master/spec/ics-005-port-allocation#store-paths + +// PortPath defines the path under which ports paths are stored +func PortPath(portID string) string { + return fmt.Sprintf("ports/%s", portID) +} + +// KeyPort returns the store key for a particular port +func KeyPort(portID string) []byte { + return []byte(PortPath(portID)) +} diff --git a/x/ibc/keeper/keeper.go b/x/ibc/keeper/keeper.go index dafe8892d167..c9708a6e79a1 100644 --- a/x/ibc/keeper/keeper.go +++ b/x/ibc/keeper/keeper.go @@ -5,21 +5,25 @@ import ( sdk "github.com/cosmos/cosmos-sdk/types" client "github.com/cosmos/cosmos-sdk/x/ibc/02-client" connection "github.com/cosmos/cosmos-sdk/x/ibc/03-connection" + port "github.com/cosmos/cosmos-sdk/x/ibc/05-port" ) // Keeper defines each ICS keeper for IBC type Keeper struct { ClientKeeper client.Keeper ConnectionKeeper connection.Keeper + PortKeeper port.Keeper } // NewKeeper creates a new ibc Keeper func NewKeeper(cdc *codec.Codec, key sdk.StoreKey, codespace sdk.CodespaceType) Keeper { clientKeeper := client.NewKeeper(cdc, key, codespace) connectionKeeper := connection.NewKeeper(cdc, key, codespace, clientKeeper) + portKeeper := port.NewKeeper(cdc, key, codespace) return Keeper{ ClientKeeper: clientKeeper, ConnectionKeeper: connectionKeeper, + PortKeeper: portKeeper, } }