Synopsis
This standard specifies the port allocation system by which modules can bind to uniquely named ports allocated by the IBC handler. Ports can then be used to open channels and can be transferred or later released by the module which originally bound to them.Motivation
The interblockchain communication protocol is designed to facilitate module-to-module traffic, where modules are independent, possibly mutually distrusted, self-contained elements of code executing on sovereign ledgers. In order to provide the desired end-to-end semantics, the IBC handler must permission channels to particular modules. This specification defines the port allocation and ownership system which realises that model. Conventions may emerge as to what kind of module logic is bound to a particular port name, such as “bank” for fungible token handling or “staking” for interchain collateralisation. This is analogous to port 80’s common use for HTTP servers — the protocol cannot enforce that particular module logic is actually bound to conventional ports, so users must check that themselves. Ephemeral ports with pseudorandom identifiers may be created for temporary protocol handling. Modules may bind to multiple ports and connect to multiple ports bound to by another module on a separate machine. Any number of (uniquely identified) channels can utilise a single port simultaneously. Channels are end-to-end between two ports, each of which must have been previously bound to by a module, which will then control that end of the channel. Optionally, the host state machine can elect to expose port binding only to a specially-permissioned module manager, by generating a capability key specifically for the ability to bind ports. The module manager can then control which ports modules can bind to with a custom rule-set, and transfer ports to modules only when it has validated the port name & module. This role can be played by the routing module (see ICS 26).Definitions
Identifier, get, set, and delete are defined as in ICS 24.
A port is a particular kind of identifier which is used to permission channel opening and usage to modules.
A module is a sub-component of the host state machine independent of the IBC handler. Examples include Ethereum smart contracts and Cosmos SDK & Substrate modules.
The IBC specification makes no assumptions of module functionality other than the ability of the host state machine to use object-capability or source authentication to permission ports to modules.
Desired Properties
- Once a module has bound to a port, no other modules can use that port until the module releases it
- A module can, on its option, release a port or transfer it to another module
- A single module can bind to multiple ports at once
- Ports are allocated first-come first-serve, and “reserved” ports for known modules can be bound when the chain is first started
| IBC Concept | TCP/IP Concept | Differences |
|---|---|---|
| IBC | TCP | Many, see the architecture documents describing IBC |
| Port (e.g. “bank”) | Port (e.g. 80) | No low-number reserved ports, ports are strings |
| Module (e.g. “bank”) | Application (e.g. Nginx) | Application-specific |
| Client | - | No direct analogy, a bit like L2 routing and a bit like TLS |
| Connection | - | No direct analogy, folded into connections in TCP |
| Channel | Connection | Any number of channels can be opened to or from a port simultaneously |
Technical Specification
Data Structures
The host state machine MUST support either object-capability reference or source authentication for modules. In the former object-capability case, the IBC handler must have the ability to generate object-capabilities, unique, opaque references which can be passed to a module and will not be duplicable by other modules. Two examples are store keys as used in the Cosmos SDK (reference) and object references as used in Agoric’s Javascript runtime (reference).newCapability must take a name and generate a unique capability key, such that the name is locally mapped to the capability key and can be used with getCapability later.
authenticateCapability must take a name & a capability and check whether the name is locally mapped to the provided capability. The name can be untrusted user input.
claimCapability must take a name & a capability (provided by another module) and locally map the name to the capability, “claiming” it for future usage.
getCapability must allow a module to lookup a capability which it has previously created or claimed by name.
releaseCapability must allow a module to release a capability which it owns.
newCapability, authenticateCapability, claimCapability, getCapability, and releaseCapability are then implemented as follows:
Store paths
portPath takes an Identifier and returns the store path under which the object-capability reference or owner module identifier associated with a port should be stored.
Sub-protocols
Identifier validation
Owner module identifier for ports are stored under a uniqueIdentifier prefix.
The validation function validatePortIdentifier MAY be provided.
validatePortIdentifier function will always return true.
Binding to a port
The IBC handler MUST implementbindPort. bindPort binds to an unallocated port, failing if the port has already been allocated.
If the host state machine does not implement a special module manager to control port allocation, bindPort SHOULD be available to all modules. If it does, bindPort SHOULD only be callable by the module manager.
Transferring ownership of a port
If the host state machine supports object-capabilities, no additional protocol is necessary, since the port reference is a bearer capability.Releasing a port
The IBC handler MUST implement thereleasePort function, which allows a module to release a port such that other modules may then bind to it.
releasePort SHOULD be available to all modules.
Warning: releasing a port will allow other modules to bind to that port and possibly intercept incoming channel opening handshakes. Modules should release ports only when doing so is safe.
Properties & Invariants
- By default, port identifiers are first-come-first-serve: once a module has bound to a port, only that module can utilise the port until the module transfers or releases it. A module manager can implement custom logic which overrides this.
Backwards Compatibility
Not applicable.Forwards Compatibility
Port binding is not a wire protocol, so interfaces can change independently on separate chains as long as the ownership semantics are unaffected.Example Implementations
- Implementation of ICS 05 in Go can be found in ibc-go repository.
- Implementation of ICS 05 in Rust can be found in ibc-rs repository.