Polkadot Xcm -- 从基础到实践(实现跨链转账)

  • 时间:
  • 浏览:204
  • 来源:区块链技术网

这个转账模型只有两个参与者,源(Source)和目的地(Destination)。例子(伪代码):

olkadot Xcm 从基础到实践

XCM 基础部分:

指引:

Parachain Development · Polkadot Wiki[2]

XCM: The Cross-Consensus Message Format[3]

XCM 消息格式

Overview of XCM: A Format, Not a Protocol

xcm-format 参考资料[4]

XCM is related to cross-chain in the same way that REST is related RESTful.

XCM 是一种消息格式,而不是消息传递协议, 因为它无法在系统之间发送任何消息,仅仅是一种应如何执行消息传输的格式,也就是表达接收者应该做什么。XCM 还可用于通过 UMP(向上信息传递)、DMP(向下消息传递)、XCMP(跨链消息传递)通信通道中的任意一个来表发消息的含义。

  • xcm 消息里带有执行消息和位置信息
  • 例如:链和链之间,合约与合约之间的 xcm 消息传递都可以用这套规范来实现,这些东西不能依托于链来实现,因为这套规范,如果依托于链本身,那每次链的升级都相当于做了一次 xcm 版本的升级。这很影响兼容性。
  • XCM 不仅仅是跨链,而是跨共识消息格式!-技术圈[5]

    XCM 的核心 — XCVM(交叉共识虚拟机)

    XCM format 的核心是 XCVM(交叉共识虚拟机),它是一种超高级非图灵完备计算机,它的指令设计和交易大致处于同一水平。

    XCM中的”消息“(就是上文的 messages/消息)实际上只是 XCVM 上运行的程序。它是一个或多个 XCM指令。程序一直执行,直到它运行到最后或遇到错误,此时它完成并停止。

    XCVM 包括许多寄存器,以及对托管它的共识系统的整体状态的访问。指令可能会更改寄存器,它们可能会更改共识系统的状态或两者兼而有之。

    MultiLocations

    可以理解为共识系統语义下的“位置”

  • 需要注意的是,所有位置都是从消息解释器的相对角度来看的。就如下面的例如...
  • 从 Parachain A 的⻆度来看:

    • Relay Chain: X1(Parent)
    • Parachain A: Self
    • Parachain B: X2(Parent, Parachain B)
    • Contract A: X1(Contract A)
    • Contract B: X3(Parent, Parachain B, Contract B)
    • Alice: X2(Contract A, AcountId32{Alice})
    • Bob: X1(AcountId32{Bob})
    • Charlie: X3(Parent, Parachain B, AcountId32{Charlie})
    • Dave: X4(Parent, Parachain B, Contract B, AcountId32{Dave})

    Polkadot Messaging Guide - HackMD[6]

    消息路由

    Cross-Consensus Protocols

    随着 XCM Format 的正式建立,这些 messages 需要协议的通用模式,Polkadot 实现了两个,用于在其组成的 parachain 之间处理 XCM messages。

    (分别是VMP和XCMP)

    注:下文中的“消息” 意指上面提到的 messages。

    VMP(垂直消息传递)

    实际上,有两种垂直消息传递传输协议。

    • UMP (向上消息传递):允许平行链向他的中继链发送消息
    • DMP (向下消息传递):允许中继链将消息向下传递到他们的平行链之一。

    注意,  的消息也可能来自平行链,例如:平行链 A 转给平行链 B的情况,这个过程是这样子的。

    DMP

    首先平行链 A将使用,将消息传递给中继链,其次中继链再根据将消息向下传递给平行链 B

    UMP

    DMP

    XCMP(跨链消息传递)

    XCMP 允许平行链与其中继链上其他的平行链交换消息。

    跨链交易使用基于 Merkle 树的简单排队机制来解决,以确保fidelity(保真度)。中继链验证人的任务是将一个平行链的输出队列上的交易移动到目标平行链的输入队列中。但是,只有关联的 metadata 作为 hash 存储在中继链的存储中。

    输入和输出队列有时在 Polkadot 代码库和相关文档中分别称为(输入队列)和(输出队列)消息。

    ingress

    egress

    (这里队列的概念下文会提到。)

    XCMP-精简版(HRMP)

    水平中继路由消息传递协议 (HRMP) 协议是未完全完成的功能的临时替代品。虽然 XCMP 本身仍在开发中,但 HRMP 是一个有效的替代品。

    HRMP 具有与 XCMP 相同的接口和功能,但对资源的要求更高,因为它将所有消息存储在中继链存储中。当 XCMP 实施后,HRMP 计划被弃用并逐步淘汰以支持它。

    XCMP

    (思想:中继链只保存相关元数据的 hash 值,只做关于 xcm 的相关验证。)

    由于现在 XCMP 还没有被完全开发出来,现在主要使用的是 HRMP,上文也提到了,HRMP 需要用到许多的资源,现在吞吐量 可能会是 42 条平行链上下。不过现在 parity 的开发者已经在把其他模块交易移到其他平行链 比如国库财政部分来提高吞吐能力和承载链数量。

    小问题:xcm 消息执行失败了,怎么办呢(因为中继链最后敲定区块,所以能够解决回滚的问题)题外话:波卡网络上平行链只负责出块,所以没有 grandpa 共识,最后敲定区块上交给中继链决定的。

    消息分发

    Polkadot's Messaging Scheme[7]

    Polkadot 的跨链消息传递方案(XCMP)[8]

    平⾏链阶段中,收集⼈打包区块的同时,也会将跨链交易放到平⾏链的出队列中。跨链交易通过 XCMP 协议进⾏传输,根据收集⼈和验证⼈的⽹络连接情况,

    具体的传输⽅法有三种:

    1. 发起链收集⼈直接发送给⽬标链收集⼈;
    2. 发起链验证⼈发送给⽬标链收集⼈; 发起链收集⼈发送给发起链验证⼈,发起链验证⼈传递给⽬标链验证⼈,⽬标链验证⼈再传递给⽬ 标链收集⼈。
    3. 跨链交易传递到⽬标链后,会把跨链交易放到平⾏链⼊队列中。通过以上步骤,就完成了跨链交易在 链间的传递。

    如果 A 和 B 不共享全节点,则需要依靠中继链上的验证⼈来传递消息。

    队列

    中继链验证者应负责将某⼀平⾏链上输出队列中的交易移⾄⽬标平⾏链上的输⼊队列中。

    • 收集⼈节点负责把平⾏链之间的信息传递。
    • 收集⼈产⽣"出⼝"列表信息并会在"⼊⼝"接收到其它平⾏ 链信息。
    • 当收集⼈产⽣了区块并提交给验证⼈,它会收集最新⼊⼝队列信息并且处理它(构造新区块 时会把以⾃⼰为⽬的地、还未被处理的跨链消息都处理下)。
    • 验证⼈将会对收集⼈提交的平⾏链区块进⾏验证,包括处理到该平⾏链预期⼊⼝的信息(看看跨链消息是否真的被处理过了,因此消息的⼀ 些元数据还是会上中继链的)。

    cumulus 的 pallets 中两种队列:

    MQC(Message Queue Chain,消息队列链)

    消息队列链是由验证人创建的一个通用哈希链,用于跟踪从发送方发送到单个接收方的每条消息以及顺序。

    MQC 本身不保存在任何地方,而是只提供所有接受到的消息的最终证明。当验证器接收到候选消息时,它从放置在 upward_messages 中的消息中按升序生成MQC

    跨链资产转账详解:从基础到实践

    上方都是关于 XCM 的基础部分,有了上面的知识,我们就进一步扩展讲讲其中的一些应用实现,例如跨链资产转账。

    关于平行链之间进行资产转账会有一些细节。

    跨链资产转账方式

    XCM 其实定义了两种转账的方式,一种是Asset Teleportation一种是Reserve Asset Transfer。 参考:How can I transfer assets using XCM?[9]

    Asset Teleportation

    // 链A的Alice向链B的Bob转账100个链A的native token_aTransfer_teleport_asset(source_alice, dest_bob, token_a, 100);

    过程:

    1. 首先先会在链 A burn掉 Alice 的 100 个 token_a,并记下burn掉的资产总量,
    2. 然后链 A 会创建一个名为 "ReceiveTeleportedAssets" 的 XCM 指令,并将 burn 掉的资产数量和链 B 的相对位置(这里的相对位置其实就是上文中 Mulitilocation 的概念)作为这条 XCM 指令的参数,然后它会将这条指令发送到目的地(就是链 B),在那里它被处理并根据参数里的信息mint新的资产。
    3. 最后链 B 会将新锻造的资产存入 Bob 账户中。

    缺点:它要求来源和目的地都具有高度的相互信任。目的地必须相信来源已经烧毁了发送过来的资产,并且来源还必须相信目的地铸造在来源处被烧毁的资产。

    不支持这两个条件中的任何一个都将导致资产的总发行量发生变化(在可替代代币的情况下)或 NFT 的完全丢失/重复。

    Reserve Asset Transfer

    过程:chain A 上的 account1 想转移某个资产到 chain B 上的 account2 账⼾⾥,那⾸先将 account 1 的资产转移⾄ chain A 上 的 chain B 代表账⼾,再发送⼀条通知消息给 chain B,chain B 将对应的资产分配给 account2。

  • ps: 其实业界里更推崇后者(reserve),相较于前者会更有保障。像 orml-xtokens 其实就是基于 reserve 方式实现的平行链多资产转账模块。
  • 为平行链添加跨链资产转移的功能

    我们接下来的目的就是创建两条平行链,让这两条平行链并且实现。实验环境我们会准备 4 个中继链的验证人节点以支持两条平行链。因为我们要模拟链 A 到链 B 的跨链资产转移以及平行链到中继链的跨链资产转移。

    支持多资产

    跨链资产转账

    - 4个验证人的中继链- 平行链A- 平行链B

    平行链的跨链转账一共有两种场景:

    1. 平行链转中继链(向上转账) 平行链转中继链都是转的中继链代币,如果想让自己的平行链能支持向中继链跨链转账的功能其实只需要配置 XcmConfig 就行。
    2. 平行链 A 转平行链 B(横向转账) 平行链之间的转账会稍微复杂些,因为会涉及多资产转账的问题,这里只需要配置 XcmConfig 以及添加模块就行。
    3. orml

    接下来我们直接分析整个完整的 runtime 配置来介绍一下配置跨链资产转账时需要注意的配置项以及其含义。

    平行链转中继链

    为两条平行链添加支持向中继链进行跨链转账的功能。

    进行 runtime 配置

    其实是关于XcmExecutor的配置,其中一项 XcmConfig 就是指定 XcmSender. 这是你需要包含实现 XCMP 协议的 pallet 的地方。根据您要将 XCM 发送给谁,如果是要发送到中继链,则需要包含parachain-system-pallet[10],或者如果你要发送到同级平行链,则需要包含 xcmp-queue-pallet[11]。

    /// queues.
    pub type XcmRouter = (
     // Two routers - use UMP to communicate with the relay chain:
     // ================================
     // 需要修改的地方:最后我们是需要支持平行链到中继链,平行链到平行链,所以两个配置我们都要加。
     cumulus_primitives_utility::ParentAsUmp<ParachainSystem, PolkadotXcm>,
     // ..and XCMP to communicate with the sibling chains.
     XcmpQueue,
     // ================================
    );
    // ......
    // ......
    // ......
    pub struct XcmConfig;
    impl xcm_executor::Config for XcmConfig {
     type Call = Call;
     type XcmSender = XcmRouter;
     // How to withdraw and deposit an asset.
     type AssetTransactor = LocalAssetTransactor;
     type OriginConverter = XcmOriginToTransactDispatchOrigin;
     type IsReserve = NativeAsset;
     type IsTeleporter = (); // Teleporting is disabled.
     type LocationInverter = LocationInverter<Ancestry>;
     type Barrier = Barrier;
     type Weigher = FixedWeightBounds<UnitWeightCost, Call, MaxInstructions>;
     type Trader = UsingComponents<IdentityFee<Balance>, RelayLocation, AccountId, Balances, ()>;
     type ResponseHandler = PolkadotXcm;
     type AssetTrap = PolkadotXcm;
     type AssetClaims = PolkadotXcm;
     type SubscriptionService = PolkadotXcm;
    }

    平行链 A 转平行链 B

    为平行链 A 和平行链 B 配置 ORML 相关库以实现平行链之间的跨链资产转移 将会用到ORML的一些依赖库: