关于IBC Channel的一切信息(第一部分)

  • IBCteam
  • 发布于 2023-02-18 19:17
  • 阅读 34

这篇文章深入探讨了IBC通道的基本概念,包括通道的类型、握手过程、包的超时机制等。作者通过丰富的实例和图示,清晰地解释了通道在跨链通信中的作用,并对开发者可能遇到的问题进行了解释。文章结构清晰,逻辑严谨,是对IBC通道的优秀介绍。

Channel排序、握手、超时等

渠道核心跨链通信(IBC) 协议的重要组成部分。它们充当在一条链上的 模块/应用和另一条链上的模块之间传输数据包的通道。对于应用开发者来说,渠道是 IBC 抽象中最重要的层次。

这篇博客旨在解释渠道,并解答开发者对 IBC Channel的常见问题/误解。涵盖的主要主题包括频道排序、握手、关闭、重新打开、渠道的安全属性以及数据包超时。

内容很多,所以这是一个两部分系列的第一部分。第一部分关注 IBC Channel的基础知识,而第二部分将解答应用开发者对渠道的一些常见问题。

Channel类型

一个渠道是用于在两条不同链上的两个不同模块/应用之间传输数据包的通道。它们确保数据包仅执行一次,并且仅交付给拥有渠道另一端的对应模块。

每个渠道与特定的 连接 相关联,一个连接可以有任意数量的相关渠道。

图 1: 从链 A 上的模块发送到链 B 上模块的数据包的高层次描绘

目前,主要有两种类型的渠道:

  1. 有序: 数据包按发送顺序(从源)精确地送达(到目的地)。
  2. 无序: 数据包可以以任意顺序送达,与它们被发送的顺序无关。

渠道排序是通过 数据包 序列 来强制执行的。

每个数据包都有一个数据包序列,表示发送和接收数据包的顺序。序列号为 1 的数据包将在序列号为 2 或更高的数据包之前在目的地被接收和处理。

一个渠道端维护三个不同的序列 — nextSequenceSendnextSequenceRecvnextSequenceAck。每当一个渠道发送、接收或确认一个数据包时,nextSequenceSendnextSequenceRecvnextSequenceAck 计数器分别递增。

图 2: 有序渠道中数据包与渠道序列的关系

有序渠道中,只有当数据包序列与渠道端预期的 nextSequenceRecv 相符时,数据包才会被接收和处理。如果数据包序列小于 nextSequenceRecv,意味着数据包已被接收,则核心 IBC 进行无操作,如这里所示

如果数据包序列大于 nextSequenceRecv,意味着在当前的数据包之前还有一个较早序列的数据包需要接收,数据包将被拒绝,并且中继者最终会提交正确的数据包。

当数据包在无序渠道上被接收时,核心 IBC 仅确保它尚未被接收(因排序无关紧要),通过查找数据包收据 — 一个指示数据包已经接收的单个位。如果收据已存在,则渠道无操作。如果不存在,则 收据被设置,并处理数据包。

Channel开启/关闭握手

渠道通过四步握手建立。在握手过程的每一步,核心 IBC 执行基本验证和逻辑,同时回调可以执行自定义握手逻辑的应用。

在握手过程中,两个模块之间进行版本协商。这使得应用可以就将通过该渠道发送的数据包数据的结构、与使用中间件相关的逻辑等达成一致。

ICS-20 的情况下,渠道握手如下:

  1. 中继者在链 A 上调用 chanOpenInit 函数。随后,onChanOpenInit 回调允许链 A 上的应用执行自定义逻辑。这将渠道端状态(在 A 上)设置为 INIT。中继者将此版本传递给链 B,作为第 2 步的 counterpartyVersion 字符串
  2. 在链 B 上调用 chanOpenTry,其中应用执行自定义握手逻辑 onChanOpenTry,将渠道端状态设置为 TRY。链 B 上的应用确保其版本与对方应用所提议的版本相同, 如这里所示
  3. 在 A 上调用 chanOpenAck。此步骤中版本协商已经完成,A 上的渠道端状态被设置为 OPEN。
  4. 在 B 上调用 chanOpenConfirm,其中渠道端也设置为 OPEN。

图 3: Channel开启握手

¹chanOpenInit 也可以由应用模块(例如 ICA)调用

在握手过程的任何阶段,回调函数都可能返回错误。在这种情况下,渠道握手失败,需要协商新的握手。

一旦在两个模块之间建立了渠道,升级该模块或使用中间件包裹模块是不可行的,除非打开新的渠道或协调整个网络的升级。我们目前关于 渠道可升级性 的工作解决了这一问题,以便模块能够升级以利用新功能,或在两侧添加中间件,同时保持相同的渠道。

一个渠道仅在异常情况下关闭。我们将在系列的第二部分中讨论所有关闭渠道的原因。关闭渠道通过两步渠道关闭握手进行。中继者提交 ChannelCloseInit,这允许该链上的应用执行自定义逻辑 onChanCloseInitChannelCloseConfirm 在对方链提交,其中调用 onChanCloseConfirm 回调。

图 4: Channel关闭握手

数据包超时

核心 IBC 提供的关键保证之一是 如果超时已过,则数据包不会在目的链上被接收。超时是在 数据包接口 中由 timeoutHeighttimoutTimestamp 设置为对方(接收)链的。

func NewPacket(
 data []byte,
 sequence uint64, sourcePort, sourceChannel,
 destinationPort, destinationChannel string,
 timeoutHeight clienttypes.Height, timeoutTimestamp uint64,
) Packet {
 return Packet{
  Data:               data,
  Sequence:           sequence,
  SourcePort:         sourcePort,
  SourceChannel:      sourceChannel,
  DestinationPort:    destinationPort,
  DestinationChannel: destinationChannel,
  TimeoutHeight:      timeoutHeight,
  TimeoutTimestamp:   timeoutTimestamp,
 }
}

注意: 超时需要在发送链上进行证明,基于接收链的超时高度或超时时间戳。

根据接收者的本地时钟指定超时确保不会出现以下情况:发送者认为数据包超时并采取行动,例如在Token转移中释放托管Token,而数据包实际上被对方及时接收,对方继续铸造Token——导致双重支出。

有两个场景可能导致数据包超时:1) 标准情况下接收链上的超时时间戳或超时高度已过,或者 2) Channel关闭,因此所有未接收的数据包将超时。

我们将分别深入探讨这两种情况。首先,让我们看看最常见的场景。

标准数据包超时

  1. 当数据包被发送到超时时间戳/高度已过的目的链时,RecvPacket 函数返回错误。
  2. 中继者扫描这些错误( ErrPacketTimeout )并向源链发送 TimeoutPacket
  3. TimeoutPacket 包含一个 proof 和一个 ProofHeightproof 用于证明在这个 特定高度,数据包未被接收。
  4. 如果你熟悉轻客户端的工作原理,你会知道,每个 ProofHeight 与特定 ConsensusState 相关联。每个 ConsensusState 都有特定的时间戳。因此,我们使用 GetTimestampAtHeight 函数获取与特定 ProofHeight 相关的时间戳。
  5. 因此,ProofHeight 证明对方时间戳(与 ProofHeight 相关)大于在数据包中指定的超时时间戳。
  6. 如果指定超时高度而不是时间戳,则我们证明 ProofHeight 大于或等于超时高度。
  7. 一旦证明了第 5 或 6 步,我们继续证明在此高度上数据包未被接收。此步骤根据渠道排序有所不同:

7.a. 在无序渠道的简单情况下,我们证明在此 ProofHeight 上不存在数据包收据。换句话说,这是一个某个键在状态树中不存在的证明。²

7.b. 对于有序渠道,我们验证 nextSequenceReceive 小于或等于数据包序列。这确保目的链未接收该数据包。例如,如果 nextSequenceReceive 为 3,而数据包序列为 4,则渠道期望在接收 4 之前接收序列为 3 的数据包。与第 7.a 不同,这是 nextSequenceReceive 的成员资格证明。³

一旦我们证明了第 5(或 6)和第 7 步,发送模块调用 OnTimeoutPacket 以恢复任何状态更改或执行自定义逻辑。在 ICS-20 代币转账的情况下,托管的代币会被 解托管并退还给用户

² 也称为 不成员/不存在的证明 。 IBC 模块在 IAVL 树 (与其他 Cosmos SDK 模块类似) 中维护其状态。在 IAVL 树中,子键按字母顺序排列。因此,要证明键 'b' 不存在(即不存在证明),需要证明 'a' 和 'c' 存在,并且在它们之间不存在其他键。

³ _除了超时,IBC 中的所有证明都是 成员资格证明 ,即证明特定键在状态树中存在。

Channel关闭时的超时

发送模块调用 TimeoutOnClose 函数,以证明发送数据包的渠道已关闭。

在渠道关闭时执行超时逻辑是直接的。与上述提到的超时不同,核心 IBC 证明对方的时间已超过数据包超时,在这种情况下,我们只需证明对方的渠道状态已关闭(如 此处所示)。

代币可替代性

在 IBC 中,通过两条不同渠道发送的相同代币并不可替代。这不是一个错误,而是 IBC 安全模型的一个基本方面。

即使存在两条不同的渠道 12,连接同两条链 AB,通过这些渠道发送的相同代币 $FOO 也不可替代。这是因为每条渠道都有其自己的安全属性。例如,两个不同的渠道可能具有不同的版本。或者这些渠道可能与不同的连接相关联,而不是与同一个连接(可能连接不同的轻客户端)。但最重要的是,模块无法知道对方的渠道端属于哪个链。换句话说,模块只知道它们正在发送数据的渠道,而不知道它们正在与哪个链进行通信。

因此,必须确保每个渠道的安全边界是隔离的,并且不要对渠道及其相关轻客户端做出天真的假设。

结论

如上所述,渠道在 IBC 内的数据包传输和排序中起着重要作用。由于模块和渠道紧密耦合,应用开发者了解 IBC Channel的方方面面是有益的。

在系列的第二部分中,我们将澄清应用开发者关于渠道的一些常见问题。同时,请随时查看我们的 开发者门户,了解更多关于 IBC Channel的信息。

IBC 是保证跨区块链之间以最小信任、安全和可扩展的方式进行任意数据传输的基本范式转变。请查看这里 以了解 IBC 的工作原理的介绍。

关于作者:

Adi Ravi Raj Interchain GmbH 工作,是 IBC 团队的协议分析师。

感谢 Susannah Evans, 和 Thomas Dekeyser 审阅本文草稿。

  • 原文链接: medium.com/the-interchai...
  • 登链社区 AI 助手,为大家转译优秀英文文章,如有翻译不通的地方,还请包涵~
点赞 0
收藏 0
分享
本文参与登链社区写作激励计划 ,好文好收益,欢迎正在阅读的你也加入。

0 条评论

请先 登录 后评论
IBCteam
IBCteam
江湖只有他的大名,没有他的介绍。