概述
本标准规定了端口分配系统,模块可通过该系统绑定由 IBC 处理程序分配的唯一命名端口。 随后,这些端口可用于打开通道,并且可以由最初绑定它们的模块进行转移或稍后释放。动机
跨区块链通信协议旨在促进模块到模块的通信,其中模块是在主权账本上执行的、相互独立、可能彼此不信任且自包含的代码单元。为了提供所需的端到端语义,IBC 处理程序必须将通道权限授予特定模块。 本规范定义了实现该模型的端口分配与所有权系统。 对于某个特定端口名绑定何种模块逻辑,可能会逐渐形成约定,例如将bank 用于同质化代币处理,或将 staking 用于链间抵押。
这类似于端口 80 常用于 HTTP 服务器这一事实,但协议本身无法强制要求某种特定模块逻辑必须实际绑定到这些约定端口,因此用户必须自行检查。
也可以创建带有伪随机标识符的临时端口,用于临时性协议处理。
模块可以绑定多个端口,也可以连接到另一台机器上由其他模块绑定的多个端口。任意数量的(具有唯一标识的)通道都可以同时使用同一个端口。
通道是两个端口之间的端到端连接,而这两个端口都必须事先由某个模块完成绑定,随后该模块将控制通道对应的一端。
可选地,宿主状态机可以选择仅向一个具有特殊权限的模块管理器暴露端口绑定能力,
具体方式是专门为绑定端口这一能力生成一个 capability key。随后,模块管理器
就可以使用自定义规则集来控制模块可以绑定哪些端口,并且仅在它
验证了端口名和模块之后,才将端口转移给模块。该角色可以由路由模块承担(参见 ICS 26)。
定义
Identifier、get、set 和 delete 的定义见 ICS 24。
端口是一类特殊的标识符,用于将打开和使用通道的权限授予模块。
模块是宿主状态机中独立于 IBC 处理程序的子组件。示例包括 Ethereum 智能合约,以及 Cosmos SDK 和 Substrate 模块。
IBC 规范除了要求宿主状态机能够使用对象能力或来源认证机制将端口权限授予模块外,不对模块功能作其他假设。
期望属性
- 模块一旦绑定某个端口,在其释放该端口之前,其他模块都不能使用该端口
- 模块可以根据自身选择释放端口,或将其转移给另一个模块
- 单个模块可以同时绑定多个端口
- 端口按先到先得方式分配,而已知模块的“保留”端口可以在链首次启动时完成绑定
| IBC 概念 | TCP/IP 概念 | 差异 |
|---|---|---|
| IBC | TCP | 差异很多,参见描述 IBC 的架构文档 |
端口(例如 bank) | 端口(例如 80) | 没有低编号保留端口,端口是字符串 |
模块(例如 bank) | 应用程序(例如 Nginx) | 属于应用特定概念 |
| 客户端 | - | 没有直接类比,有点像二层路由,也有点像 TLS |
| 连接 | - | 没有直接类比,在 TCP 中被折叠进连接语义 |
| 通道 | 连接 | 任意数量的通道都可以同时向某个端口打开或从某个端口发起 |
技术规范
数据结构
宿主状态机必须为模块支持对象能力引用或来源认证中的至少一种。 在前一种对象能力场景下,IBC 处理程序必须能够生成对象能力,即唯一且不透明的引用, 它们可以传递给某个模块,并且不能被其他模块复制。两个示例分别是 Cosmos SDK 中使用的存储键(reference) 以及 Agoric Javascript 运行时中使用的对象引用(reference)。newCapability 必须接收一个名称并生成唯一的 capability key,使该名称在本地映射到该 capability key,之后可通过 getCapability 使用它。
authenticateCapability 必须接收一个名称和一个 capability,并检查该名称是否在本地映射到了所提供的 capability。该名称可以是不受信任的用户输入。
claimCapability 必须接收一个名称和一个 capability(由另一个模块提供),并在本地将该名称映射到此 capability,从而“声明”其供未来使用。
getCapability 必须允许模块通过名称查找其先前创建或声明的 capability。
releaseCapability 必须允许模块释放其拥有的 capability。
newCapability、authenticateCapability、claimCapability、getCapability 和 releaseCapability 的实现如下:
存储路径
portPath 接收一个 Identifier,并返回与某个端口关联的对象能力引用或所有者模块标识符应当存储的路径。
子协议
标识符校验
端口的所有者模块标识符存储在某个唯一的Identifier 前缀之下。
可以提供校验函数 validatePortIdentifier。
validatePortIdentifier 函数始终返回 true。
绑定到端口
IBC 处理程序必须实现bindPort。bindPort 会绑定一个尚未分配的端口;如果该端口已经被分配,则必须失败。
如果宿主状态机未实现用于控制端口分配的特殊模块管理器,则 bindPort 应当对所有模块可用。如果实现了,则 bindPort 应当只能由模块管理器调用。
转移端口所有权
如果宿主状态机支持对象能力,则无需额外协议,因为端口引用本身就是一种持有者能力。释放端口
IBC 处理程序必须实现releasePort 函数,它允许模块释放某个端口,以便其他模块随后可以绑定该端口。
releasePort 应当对所有模块可用。
警告:释放端口将允许其他模块绑定到该端口,并可能拦截传入的通道打开握手。模块仅应在确认安全的情况下释放端口。
属性与不变量
- 默认情况下,端口标识符按先到先得方式分配:一旦某个模块绑定了某个端口,在该模块转移或释放该端口之前,只有该模块可以使用该端口。模块管理器可以实现覆盖此行为的自定义逻辑。
向后兼容性
不适用。向前兼容性
端口绑定不是线协议,因此只要所有权语义不受影响,不同链上的接口可以独立演进。示例实现
- ICS 05 的 Go 实现可见于 ibc-go repository。
- ICS 05 的 Rust 实现可见于 ibc-rs repository。
历史
2019 年 6 月 29 日 - 初始草案版权
此处所有内容均基于 Apache 2.0 许可。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.