全长 2760 字,预计阅读 10 分钟 作者:DaviRain 撰文:MiX
章鱼网络 DaviRain 受邀参加 RUST.CC 中国大会,分享主题为《通过 Substrate - IBC 实现 Substrate 资产跨链》的 Workshop。主要讨论了 IBC 跨链通信协议,以及 Substrate-IBC 在 Substrate 上实现的 IBC 协议,最后通过实战,在 Substrate 的模版上配置 Substrate-IBC 完成一笔 ICS20 的跨链转账演示。
https://github.com/octopus-network/substrate-ibc
主要内容分为四个部分:
- 什么是 IBC 协议以及 IBC 生态的现状
- Substrate-IBC 架构的介绍
- 在 Barnacle 模版配置 Substrate-IBC Pallet
- 演示 IBC 协议的同质化代币跨链转账功能
以下为分享实录:
我们先看看 Substrate-IBC 的来源。
Substrate-IBC 是由 Interchain 基金会资助,由章鱼网络提案并开发的一个 Substrate Pallet 模块,是连接 Polkadot 和 Kusama 与 Cosmos 的重要一步,使两个生态系统之间的资产和数据的安全交换成为可能。Substrate-IBC 模块,使开发者能够创建带有 IBC 功能的 Substrate 区块链。这个模块的目标是让建立在 Substrate 上的区块链可以通过 IBC 协议以无信任方式与其他支持 IBC 的区块链进行交互。为最终的区块链互联网章鱼网络贡献出自己的一份力量。
背景讲完了,下面让我看看 IBC 协议具体到底是什么,以及 IBC 生态的现状。
IBC 是 Inter-Blockchain Communication(跨链通信)的缩写。IBC 协议是一个端到端的、面向连接的、有状态的协议,用于可靠有序和认证的分布式账本上的模块之间的通信。
IBC 协议采用分层设计,主要分为2层:IBC/TAO 和 IBC/APP。
1、IBC/TAO:TAO 是指 Transport,Authorization,Organization,该协议处理分布式账本数据之间的传输,认证、排序。
2、IBC/APP:基于 TAO 构建的上层应用层,定义了从传输层发送过来的数据的处理方式,如同质化代币转移和非同质化代币转移。
实现 IBC 协议的大多数工作集中在 TAO 层,一旦 TAO 层实现,则很容易在 TAO 层之上实现不同的 APP 层。
这里有几点需要注意的是,链之间的通信依赖 Relayer 通信,Relayer 相当于 IBC 协议的物理层,Relayer 会扫描运行 IBC 协议的区块链,并负责向其他区块链报告最新的状态。多个 Relayer 可以为多个 Channel 传输数据,Relayer 使用每个链上的 Light Client 来交易发送过来的消息。
下面我们详细的来看下 IBC 的 TAO 层,IBC 的 TAO 层很清晰的分成了3个模块:Channel、Connection 还有 Light Client。
这也是 IBC 生态内的人都叫 IBC 协议为区块链的 TCP/IP 协议的原因。
当初的 TCP/IP 协议之所以能作为标准互联网协议存在长达近50年之久,是由于它足够简洁和灵活。迄今为止,个人电脑,服务器,智能手机均采用这一协议。这一协议甚至也被用在小型物联网设备上并且经受住了多轮互联网技术更新和迭代的考验。
和 TCP/IP 协议类似,IBC 的特殊性在于它可以将应用层(Application Layer)从传输层和网络层(TAO, Transport, Authorization, Organization)中剥离出来。
这意味着 IBC 定义了数据是如何跨链被发送和接受,并且没有明确具体的数据以及这些数据是如何组织结构的。这使得 IBC 从其他一些需要在应用层实现大量标准化的互联互通解决方案中脱颖而出。
IBC/TAO 层的主要作用,在两个链之间以 Reliable,Rodered and Authenticated 方式传递数据包。
- Reliable 是指原链仅发送一个 Packet,目标链仅接受一次,二者无需信任任何第三方。
- Ordered:是指目标链接受 Packet 的顺序与原链发送 Packet 的顺序一致。
- Authenticated:每个 Channel 分配给特定的模块,只有分配导 Channel 的模块可以通过这个 Channel 发送 Packet,任何其他模块无法使用该 Channel 发送 Packet。
讲完了IBC/TAO的大概分层模块,让我们具体的看下各个模块的具体的实现,我们先看下Light client这个模块。
这个模块是整个 IBC 协议的核心。
从名字我就可以知道这是轻客户端,轻客户端的历史可以很早就在比特币中提出了,也称为轻节点,相当于全节点来说,当时主要用于比特币的简化支付验证(SPV)。这样的轻客户端往往不与链进行直接交互,而依赖全节点作为中介,从全节点请求某种信息,例如发送交易、验证账户余额和请求区块头。
IBC 协议的核心就是一种无第三方信任的密码学验证的轻客户端验证逻辑。IBC 中用于验证远程状态机的状态更新的算法称为“合法性判定”。将合法性判定与一个可信的状态组合在一起,就可以实现远程状态机基于本地状态机的“轻客户端”功能。除了验证状态的更新,每个轻客户端也有能力通过“不良行为判定”来检测不良行为。不良行为判断用来惩戒作恶行为。通过维护轻客户端的状态,来验证连接和通道的状态。
轻客户端是 IBC/TAO 的基础,轻客户端有一个为一个 Client ID 作为标识,Light Client 会追踪其他区块链的共识状态,并且会基于共识状态验证对方区块链发送过来数据的合法性。Relayer 只负责消息的传递,消息的合法性是依赖于轻客户端做验证,所以IBC的安全性并不依赖于第三方服务比如Relayer。这是为什么 IBC 协议称为无需信任的原因。这是密码学证明提供的安全性来实现的。
然后我们看下 Connection。Connection 是建立在 Light Client 之上的一个模块。是连接两个分布式账本的通道。一个 Light Client 可以接受任意数量的 Connection。Connection 通过四次握手完成,所有操作都是由 Relayer 发起交易来触发,下面就是从一个链到另一个链之间连接建立的过程:
- connOpenInit:在 AppChian0 链上会创建并存储 INIT 状态。之后 Relayer 会中继产生的 ConnectionOpenInit 事件,事件中有密码学相关的证明。
- connOpenTry:之后 AppChain1 链若验证 AppChian0 链上该 Connection 状态为 INIT,则在 AppChian1 链上创建并存储 TRYOPEN 状态。再由 Relayer 中继产生的 ConnectionOpenTry 事件。
- connOpenAck:然后 AppChian0 链若验证 AppChian1 链上该 Connection 状态为 TRYOPEN ,则将 AppChian0 链上该 Connection 的状态由 INIT 更新为 OPEN。**再由 Relayer 中继产生的 ConnectionOpenAck事件。
- connOpenConfirm:然后 AppChian1 链若验证 AppChian0 链上该 Connection 状态已由 INIT 更新为 OPEN,则将 AppChian1 链上该 Connection 状态由 TRYOPEN 更新为 OPEN。
至此整个 Connection 创建完成。连接说完了下面在看一些 Channel。
Connection 和 Light Client 构成了 IBC 中传输层的主要组件。但是,IBC 中的应用程序之间的通信是通过 Channel 进行的,Channel 在应用程序模块与另一条链上的相应应用程序模块之间进行路由。这些应用程序由端口标识符命名,例如 ICS-20 Token 传输的 Transfer。Channel 通过四次握手完成,所有操作都是由 Relayer 发起交易来触发。
下面就是从一个链到另一个链之间连接建立的过程。
可以看到 Channel 的创建和 Connection 是类似的,有一点不同的是,所有上层的应用的逻辑实现都是在这些 ChannelOpenInit,chanOpenTry 等等发生事件之后回调接口实现的,当这些事件发生的时候也会触发应用层的逻辑。
chanOpenInit:在 AppChain0 链上会创建并存储INIT状态。之后Relayer 会中继产生的 chanOpenInit 事件,事件中有密码学相关的证明,
chanOpenTry:之后 AppChain1 链若验证 AppChain0 链上该 Channel 为 INIT 状态,则在 AppChain1 链上创建并存储 TRYOPEN 状态。再由 Relayer 中继产生的 ChanOpenTry 事件。
chanOpenAck:然后 AppChain0 链若验证 AppChain1 链上该 Channel 为 TRYOPEN 状态,则将 AppChain0 链上该 Channel 的状态由 INIT 更新为 OPEN。再由 Relayer 中继产生的 chanOpenAck 事件。
chanOpenConfirm:然后 AppChain1 链若验证 AppChain0 链上该 Channel 状态已由 INIT 更新为 OPEN ,则将 AppChain1 链上该 Channel 状态由 TRYOPEN 更新为 OPEN。
至此整个 Channel 创建完成。
这里有关 IBC/TAO 模块的部分讲完了,让我们继续看下 IBC/APP 模块。
IBC/APP 模块这里,我们主要讲 ICS20 模块也就是同质化代币转移模块,这也是这次 Workshop 最终的目标。
使用 IBC 的 Ics20 模块可以构建跨链转移 Token 的应用,在做跨链转移的时候最重要的是需要确定转移的 Token 是不是当前链。
- 如果 Token 是当前链的 Native Token,那么当前链是 Token 的源链。
- 如果 Token 是当前链通过 Channel 从其他链接受的 Token,那么当前链不是 Token 的源链。
区分好了当前 Token 的链是否是原链就可以做 Token 转移了,这是因为 Token 从原链到目标链和 Token 从目标链到原链的逻辑是不同的,可以看到 AC0 Token 从 Appchain0 到 Appchain1,AC0 Token 将在 Appchain0 链上被托管,在 Appchain1上将 Mint 出 AC0 等额度的 Token。AC0 Token 从 Appchain1到 Appchain0,AC0 Token 将在 Appchain1 上被销毁,在 Appchain0 上释放出托管的 ACO Token 。
ICS20 的核心原理就是这个样子的,总结来说, Appchain0 链上的 IBC 模块会不断的同步 Appchain1 链上的区块头信息, Appchain1 链上的 IBC 模块同理。通过这种方式,双方能够实现跟踪对方区块链上的验证者集合的变化,本质上来说,就是 Appchain0 链、 Appchain1 链相互维护了一个对方的轻节点。当使用 IBC 开始一笔跨链转账之后, Appchain0 链上的10个 AC0 Token 就会处于锁定的状态。一份证明 AC0 链上已经锁定10 AC0 Token 的 Proof会被路由到 Appchain1 链上的 IBC 模块。
Appchain1 链结合 Appchain0 链的轻节点信息,对这份 Proof 验证通过之后, Appchain1 链上会“铸造”10份 AC0 跨链资产,这些跨链资产可以进行后续的流通使用。当然这些跨链资产也可以通过同样的跨链方式返回到 Appchain0 链, Appchain0 链上的 AC0 Token 相应执行解锁的操作。
最后给出一个 IBC 消息通信的总结:
1、IBC 跨链通信双方先建立起客户端,建立连接通道。
2、从一个用户发送一笔交易,需要经过 ISC20 模块的在 Token 发送的原链上托管代币,然后经过 Relayer 的中继在目标链上 Mint 出接受到 Token 数量。
原理介绍了这么多,我们来看看 IBC 的现状以及生态。
从这张图,我们看到从去年的9月份到现在,整个的 IBC 的网络在逐渐的繁荣。测试网于之前相比多一倍还要多。
通过 IBC 连接的网络有 Cosmos hub, Osmosis, Crypto.com, Juno network, IRIS, Incective 等等40多个的链已经都在主网上线。
这个是现在最近的一些网络,启动 IBC 互联的区块链。
然而这仅仅是 Cosmos SDK 开发的链,对于使用 Substrate 开发框架来说,我们没有看到,这也是我们开发 Substrate-IBC 的一部分原因,当然对比到别的跨链协议 IBC 协议可以说是最简明且安全的协议了。这里说的安全是是对于第三方是无须信任的。Relayer 仅仅只是中继数据包。通过集成 Substrate-IBC 就可以使得使用 Substrate 框架开发的单链具有了和带有 IBC 协议实现的区块链(不仅仅是 Cosmos SDK实现)之间跨链通信的功能成为了可能。
这里我们看下 Substrate-IBC 这个项目的框架。
分成两部分,一个是链的部分另一个是 Replayer 的部分。Substrate 链的部分包括 Substrate-IBC Pallet 的开发,IBC-RS 中的 ICS10 Beefy 轻客户端 /ICS20 Fungible Token Transfer 的开发,Substrate-IBC Pallet和 IBC-RS 的集成; Replayer 的部分包括 Relayer 对 Substrate 的支持,Octopusxt 的开发。
我们已经在 Interchain 的 Grant 之前两个里程碑实现了 IBC/CORE 核心标准(ICS02-Client, ICS03-Connection, ICS04-Channel&Packet, ICS05-Port, ICS26-Router)。在此基础上,建立了 IBC 中最重要的应用 ICS20 Fungible Token Transfer。更多的 IBC 应用未来将在 Substrate-IBC 模块中实现。Substrate-IBC 模块是 Substrate 的一个模块化组件,它提供了 IBC 相关的能力,包括创建客户端、连接、通道等。Substrate 应用程序开发人员可以导入这个模块,只需很小的配置,就可以实现 IBC 通信。
之后我们看下 Substate-IBC 和 IBC-RS 之间的调用关系。
由于 IBC 的链上数据只能由 IBC Pallet读写,而不是 IBC-RS , 所以 IBC-RS 最终要调用 Substate-IBC 模块实现连上数据的读写。这里以 Update Client 这个请求为例。
1、Relayer 通过调用 Substate-IBC 的 Deliver 方法,提交了 Update Client 这个请求。
2、这个请求被传递给了 IBC-RS 的 ICS-26 Router 路由模块。
3、路由模块把请求传给了ICS20 Client 中的 Update Client 的处理逻辑,处理的过程中会调用 Substrate-IBC Pallet 中的 Clientreader, 读取相应的 Client 的状态。
IBC 的原理和 Substrate-IBC 的项目的结构讲解完了,我们看下在 Substrate 的一个模版中需要配置 Substrate-IBC Pallet 信息。主要包括 Runtime 的的配置,Node 中的配置两个部分。
Substrate-IBC 同其他 Substrate Pallet 一样也是一个运行时逻辑处理模块,在使用一个 Pallet 模块时需要在 Runtime 中配置实例和配置的 Pallet 模块。
这里我们就在 Runtime 中配置 Substate-IBC 需要用到的关联类型的配置还有 Substrate-IBC 的在 Runtime 中的实例化配置。
Node 中配置的信息是由我们设定这个链代币名称的配置,跨链资产的配置
配置完了,我们看下最终通过 Substrate-IBC 实现跨链转账的步骤。主要有8个步骤:
1、启动两条 Substrate 链 Appchain0, Appchain1
2、为已启动两条链 Appchain0, Appchain1 创建通道
3、启动 Relayer 中继IBC消息
4、在 Appchain0, Appchain1 上分别创建跨链资产
5、分别在 Polkadot.js 上导入两个账户
6、向 Appchain0 链的 David 账户转入原生Token ,以便让 David 账户随后有余额进行跨链转帐
7、从 Appchain0 链的 David 向 Appchain1 链的 Davidrain 跨链转帐
8、从 Appchain1链 的 Davidrain 向 Appchain0 链的 David 跨链转帐
这里我们使用的是章鱼网络的提供的 Substate-Node-Template 定制化的 Substarte 模版创建两条链,这个定制化的模版使得应用链开发团队很容易地加入章鱼网络生态。
之后我们需要在两个链之间建立起通道。这个创建 Channel命令会自动检测下层的 Client,Connection是否已经创建。
这里直接通过创建 Channel 逐步先创建出 Client,Connection,Channel。
因为下层的 Client, Connection 都还没有创建,所以 Hermes 会先创建 Client,创建 Client 不需要握手,我们从日志可以看出 Client 比较快的创建好了。
现在创建 Connection, 创建 Connection 需要握手,握手过程中有四个事务:connectionOpenInit,connectionOpenTry,connectionOpenAck,connectionOpenConfirm. 这四个事务日志中会顺序展示。
Connection创建完成后,开始创建 Channel。创建 Channel 也需要握手,握手过程中有四个事务:channelOpenInit,channelOpenTry, channelOpenAck, channelOpenConfirm. 这四个事务日志中会顺序展示。
最终整个通道就会创建完成。
通道创建完成之后,在启动 Relayer 中继服务。
在 Appchain0, Appchain1 链上分别创建跨链资产。
通过管理员(sudo)账户调用 OctopusAssets 中的 Frocecreate 创建资产,这里的跨链资产都是1号资产,我们在前面配置的 Substarte-IBC 的时候给到的跨链资产的资产 Id 都是1。
向 Appchain0 链的 David 账户转入一定量的 Token。
通过 Balance 模块的 transfer 函数我们从Alice账户转移500000000000000000000000 Naive Token 给 David 账户。
从 Appchain0 链的 David 向 Appchain1 的 Davirain 跨链转账。
在这里,我们可以看到在通道通过中继器和 IBC-RS 被启动后,两个底层链之间使用 IBC 来传输可 Token 的流程逻辑。
一个用户通过 Hermes 命令 tx raw ft-transfer 向AppcChain0提交一个交易。
Appchain0 中的 IBC 模块发出一个 SendPacket 事件。中继器检测到 Appchain0 发送出来的 SendPacket 事件,然后向 Appchain1 提交一个 RecvPacket 事务。
Appchain1 处理来自 Relayer 的 RecvPacket 交易请求,并发出一个 [WriteAcknowledgement] 事件。中继器检测到 Appchain1 发出的事件 WriteAcknowledgement,然后向 Appchain0 提交一个确认 AcknowledgePacket。
Appchain0 中的 IBC 模块处理来自 Relayer 的 AcknowledgePacket,然后发出一个事件 Acknowledge Event。
从 Appchain1 链的 Davirian 向 Appchain0 链的 David 跨链转账。
我们来看 IBC/APP 同质化代币跨链转账示意图。
一个用户通过 Hermes 命令 tx raw ft-transfer 向 AppcChain1 提交一个交易。
Appchain1 中的 IBC 模块发出一个SendPacket 事件。中继器检测到 Appchain1 发送出来的 SendPacket 事件,然后向 Appchain0 提交一个RecvPacket 事务。
Appchain0 处理来自 Relayer 的 RecvPacket 交易请求,并发出一个[WriteAcknowledgement]事件。中继器检测到 Appchain0 发出的事件 WriteAcknowledgement,然后向 Appchain1 提交一个确认AcknowledgePacket。
Appchain1 中的 IBC 模块处理来自 Relayer 的 AcknowledgePacket,然后发出一个事件 Acknowledge Event。
那么,关于 IBC 协议的介绍和启动一条带有 IBC 模块的 Appchain 就讲解完了。
最后这里给出一些关于 IBC 的资源还有一些联系方式 :
Substrate-IBC:https://github.com/octopus-network/substrate-ibc
IBC-RC:https://github.com/informalsystems/ibc-rs
IBC Spec:https://github.com/cosmos/ibc
IBC Spec-zh:https://github.com/octopus-network/ibc/tree/zh-cn-2022/translation/zh-CN
IBC Paper:https://github.com/cosmos/ibc/raw/old/papers/2020-05/build/paper.pdf