变更记录
- 12-12-2022:初始草案
状态
提议中背景
ibc-go 有 3 个主要使用方:- IBC 轻客户端
- IBC 应用
- 中继器
ClientState 和 ConsensusState 接口进行调用。
02-client 子模块会从 IBC 存储中获取 ClientState 或 ConsensusState,以执行对轻客户端的回调。
这种设计要求轻客户端运行所需的全部信息都存储在 ClientState 或 ConsensusState 中,或者可能存储在特定客户端实例的元数据键下。
如果某些信息足够通用、对所有 IBC 轻客户端都有价值,IBC 核心也可以通过已定义的接口参数提供这些附加信息。
这一约束已被证明存在问题,因为透传型客户端(例如 wasm)无法方便地持续访问某个 VM 实例。
此外,在不扩展已定义 ClientState 接口规模的前提下,轻客户端也无法利用 SDK 提供的一些基础内置能力,例如创世导入/导出和迁移。
另一种执行回调逻辑的方法是通过已注册的 SDK 模块。
IBC 核心正是通过这种方式与 IBC 应用交互。
IBC 应用会在编译期将其回调注册到 IBC 路由器上。
当数据包到达时,IBC 核心会使用 IBC 路由器查找与该数据包对应的已注册回调函数。
与接口函数相比,注册回调的优势在于可以通过外部 keeper 访问额外信息。
由于 IBC 应用本身也是 SDK 模块,因此它们还能获得 SDK 提供的一整套能力。
其中包括:创世导入/导出、迁移、查询/交易 CLI 命令、类型注册、gRPC 查询注册以及消息服务端注册。
如 ADR 006 所述,对轻客户端行为进行泛化是困难的。
通过已注册 SDK 模块的方式,IBC 轻客户端将获得更大的灵活性和控制力。
决策
IBC 轻客户端不应再与另一套回调调用方式并存,而应作为 SDK 模块被调用。 随着时间推进,并在必要时,IBC 核心应调整其与轻客户端的交互方式,使其基于 SDK 模块而非接口。 一个已经立即落地的决定是:通过在链的ModuleManager 中纳入 AppModuleBasic,正式化轻客户端类型注册。
tendermint 和 solo machine 客户端已经重构为包含这一 AppModuleBasic 实现,IBC 核心也将不再默认注册这两种类型。
更长期的方案包括在 SDK 上采用 ADR 033 所描述的模块间内部通信。
以下函数应转变为通过模块间通信触发的回调:
StatusGetTimestampAtHeightVerifyMembershipVerifyNonMembershipInitializeVerifyClientMessageCheckForMisbehaviourUpdateStateOnMisbehaviourUpdateStateCheckSubstituteAndUpdateStateVerifyUpgradeAndUpdateState
ClientState 接口最终应收敛为类似如下的形式:
ClientState 的接口函数存在。
ExportMetadata 最终应被轻客户端自行导入/导出其创世信息的能力所取代。
模块间通信
为了尽可能平滑地从接口回调过渡到 SDK 模块回调,在模块间通信可用时,应使用它来路由到轻客户端模块。 如果没有模块间通信,就需要开发并维护一套路由系统来注册回调。 这种路由到另一个 SDK 模块的能力应当也将由 SDK 提供。 一旦可以路由到 SDK 模块,ClientState 类型就可以暴露 Route 函数,用于返回调用轻客户端模块时使用的回调路由。
影响
正面
- 使用单一方式与回调交互
- 为 IBC 轻客户端提供更大的灵活性和控制力
- 无需再开发另一套路由系统
负面
- 需要引入破坏性变更
- 需要等待模块间通信能力落地
中性
不适用Changelog
- 12-12-2022: initial draft
Status
ProposedContext
ibc-go has 3 main consumers:- IBC light clients
- IBC applications
- relayers
ClientState and ConsensusState interface as defined by core IBC.
The 02-client submodule will retrieve the ClientState or ConsensusState from the IBC store in order to perform callbacks to the light client.
This design requires all required information for the light client to function to be stored in the ClientState or ConsensusState or potentially under metadata keys for a specific client instance.
Additional information may be provided by core IBC via the defined interface arguments if that information is generic enough to be useful to all IBC light clients.
This constraint has proved problematic as pass through clients (such as wasm) cannot maintain easy access to a VM instance.
In addition, without increasing the size of the defined ClientState interface, light clients are unable to take advantage of basic built-in SDK functionality such as genesis import/export and migrations.
The other approach used to perform callback logic is via registered SDK modules.
This approach is used by core IBC to interact with IBC applications.
IBC applications will register their callbacks on the IBC router at compile time.
When a packet comes in, core IBC will use the IBC router to lookup the registered callback functions for the provided packet.
The benefit of registered callbacks opposed to interface functions is that additional information may be accessed via external keepers.
Because the IBC applications are also SDK modules, they additionally get access to a host of functionality provided by the SDK.
This includes: genesis import/export, migrations, query/transaction CLI commands, type registration, gRPC query registration, and message server registration.
As described in ADR 006, generalizing light client behaviour is difficult.
IBC light clients will obtain greater flexibility and control via the registered SDK module approach.
Decision
Instead of using two different approaches to invoking callbacks, IBC light clients should be invoked as SDK modules. Over time and as necessary, core IBC should adjust its interactions with light clients such that they are SDK modules as opposed to interfaces. One immediate decision that has already been applied is to formalize light client type registration via the inclusion of anAppModuleBasic within the ModuleManager for a chain.
The tendermint and solo machine clients were refactored to include this AppModuleBasic implementation and core IBC will no longer include either type as registered by default.
Longer term solutions include using internal module communication as described in ADR 033 on the SDK.
The following functions should become callbacks invoked via intermodule communication:
StatusGetTimestampAtHeightVerifyMembershipVerifyNonMembershipInitializeVerifyClientMessageCheckForMisbehaviourUpdateStateOnMisbehaviourUpdateStateCheckSubstituteAndUpdateStateVerifyUpgradeAndUpdateState
ClientState.
ExportMetadata should eventually be replaced by a light client’s ability to import/export it’s own genesis information.
Intermodule communication
To keep the transition from interface callbacks to SDK module callbacks as simple as possible, intermodule communication (when available) should be used to route to light client modules. Without intermodule communication, a routing system would need to be developed/maintained to register callbacks. This functionality of routing to another SDK module should and will be provided by the SDK. Once it is possible to route to SDK modules, aClientState type could expose the function Route which returns the callback route used to call the light client module.
Consequences
Positive
- use a single approach for interacting with callbacks
- greater flexibility and control for IBC light clients
- does not require developing another routing system
Negative
- requires breaking changes
- requires waiting for intermodule communication