XCM上线,波卡达成跨链里程碑

OneBlock Community发布于2022-06-07更新于2022-06-07

文章摘要

随着 Polkadot 1.0 的最终发布,以及平行链的完成,跨共识消息格式,简称 XCM,正在接近其第一个可生产的版本。

随着 Polkadot 1.0 的最终发布,以及平行链的完成,跨共识消息格式,简称 XCM,正在接近其第一个可生产的版本。这是对该格式的介绍,它的目标,它是如何工作的,可以用来实现典型的跨链任务。

首先要说明一个有趣的事实......XCM 是 "跨共识"的消息传递格式,而不仅仅是 "跨链"。这一区别表明了该格式的目标,它是为交流各种想法而设计的,不仅在链之间,而且在智能合约和 pallet 之间,以及在桥和分片的聚居地(如 Polkadot 的 Spree)上发送。

一个格式,而不是协议

为了更好地了解 XCM,必须了解它的边界以及它在 Polkadot 技术栈中的位置。XCM 是一种消息传递格式。它不是一个消息传输协议。它不能用来在系统之间实际 "发送" 任何消息;它的作用只是表达接收方应该做什么。

不包括桥和合约 pallet,Polkadot 有三个不同的系统,用于在其组成链之间实际交流 XCM 消息。UMP、DMP 和 XCMP。UMP(向上消息传递)允许平行链链向其中继链发送消息。DMP(向下消息传递) 允许中继链将消息向下传递给他们的一个平行链。XCMP,也许是其中最著名的,这允许平行链在它们之间发送消息。XCM 可以用来表达这三个通信通道上的每一个消息的含义。

除了在链之间发送消息外,XCM 在其他情况下也很有用,比如与一个你不一定提前知道交易格式的链进行交易。对于业务逻辑变化不大的链(比如,比特币),交易格式 -- 或者说钱包用来向链发送指令的格式 -- 往往会无限期地保持完全相同,或者至少是兼容。有了高度可进化的基于元协议的链,如 Polkadot 及其组成的平行链,商业逻辑可以通过一个交易在整个网络中升级。这可以改变任何东西,包括交易格式,为钱包维护者带来了潜在的问题,特别是对于那些需要保持离线的钱包(如 Parity Signer)。由于 XCM 是良好版本管理的,抽象的和通用的,它可以作为一种手段,为钱包提供一个持久的交易格式,用来创建许多常见的交易。

目标

XCM 的目标是成为一种在共识系统之间交流思想的语言。它应该具有足够的通用性,以便在一个不断增长的生态系统中适当地发挥作用。它应该是可扩展的。由于可扩展性将不可避免地意味着变化,它也应该是面向未来和向前兼容的。最后,它应该足够高效,可以在链上运行,也可能在计量环境中运行。

像所有的语言一样,有些人倾向于使用一些元素而不是其他。XCM 的设计方式并不是让每个支持 XCM 的系统都能解释任何可能的 XCM 消息。有些信息在某些系统下将没有合理的解释。其他情况信息可能是合理的,但由于资源限制,或由于同样的内容可以用更清晰、更规范的方式表达,解释器仍然有意不支持。系统将不可避免地只支持可能的消息的一个子集。资源严重受限的系统(如智能合约)可能只支持非常有限的 "方言"。

这种通用性甚至延伸到了执行 XCM 消息的费用支付等概念。由于我们知道 XCM 可能用于不同的系统,包括 gas 计量的智能合约平台和社区平行链,一直到系统平行链和其中继链之间的可信互动,我们不想在协议中过深和不可逆地烘托诸如费用支付等元素。

为什么不直接使用本地信息格式?

在某些情况下,利用链或智能合约的原生消息/交易格式是很有用的,但也有一些很大的缺点,使其对 XCM 的目标不太有用。首先,链与链之间缺乏兼容性,所以一个打算向多个目的地发送消息的系统需要了解如何为每个目的地编写消息。在这一点上,即使是单一的目的地也可能随着时间的推移而改变其本地交易/消息格式。智能合约可能会得到升级,区块链可能会引入新的功能或改变现有的功能,这样就会改变其交易格式。

其次,区块链上的常见使用情况不容易被纳入单一交易;可能需要特殊的技巧来提取资金,交换资金,然后将结果存入单一交易中。连贯的储备资产框架所需的转账通知,在不了解其他链的情况下是不存在的。

第三,像支付费用这样的操作并不容易适应一个假设费用支付已经像智能合约信息一样被协商好的模型。相比之下,交易信封提供了一些处理支付的系统,但一般也被设计为包含签名,这在共识系统之间通信时是没有意义的。

一些初步的使用案例

虽然 XCM 的目标是通用的、灵活的和面向未来的,但当然也有它必须解决的实际需求,特别是链之间的代币转移。可选的费用支付(也许使用这些代币)是另一个问题,还有一个问题是进行交换服务的通用接口,这在整个 DeFi 世界是很常见的。最后,应该可以使用 XCM 语言来进行一些平台特定的行动;例如,在一个 Substrate 链中,可能希望向其一个 pallet 发出一个远程调用,以访问一个利基功能。

除此之外,还有许多我们想要支持的转移代币的模式。我们可能想简单地控制一个远程链上的账户,允许本地链在远程链上有一个地址用于接收资金,并最终将其控制的这些资金转移到该远程链上的其他账户。

我们可能有两个共识系统,这两个系统都是某一特定代币的本地家园。想象一下,像 USDT 或 USDC 这样的代币,在几个不同的链上都有实例,都是完全可替换的。应该可以在一个链上销毁这样的代币,并在另一个支持的链上铸造一个相应的代币。在 XCM 的术语中,我们称之为远程传输 (teleport),因为资产的表面移动实际上是通过在一侧摧毁它并在另一侧创建一个克隆来实现的。

最后,可能有两条链想提名第三条链,一条链上的资产可能被认为是原生的,作为该资产的储备。这些链上的资产的衍生形式将得到充分支持,允许衍生资产与支持它的储备链上的基础资产进行交换。这种情况可能是两个链不一定相互信任,但(至少就有关资产而言)愿意信任该资产的原生链。这里的一个例子是,我们有几个社区平行链,它们想在彼此之间发送 DOT。他们每个人都有一个本地形式的 DOT,由 Statemint 链(DOT 的本地枢纽)上的平行链控制的 DOT 完全支持。当本地形式的 DOT 在链之间发送时,在后台,"真正的" DOT 在 Statemint 的平行链账户之间移动。

即使是这种明显的适度的功能水平,也有相对大量的配置,其可用性是可取的,需要一些有趣的设计,以避免过度拟合。

XCM 的剖析

XCM 格式的核心是 XCVM。与一些人的看法相反,这不是一个(有效的)罗马数字(尽管如果是的话,它可能意味着 905)。事实上,这代表了跨共识虚拟机。它是一种超高层的非图灵完备计算机,其指令被设计成与交易大致处于同一水平。

XCM 中的 "消息" 实际上只是一个在 XCVM 上运行的程序。它是一条或多条 XCM 指令。该程序一直运行到最后或遇到错误为止,这时它就会结束(我暂时故意不解释)并停止。

XCVM 包括一些寄存器,以及对承载它的共识系统整体状态的访问。指令可能会改变一个寄存器,也可能会改变共识系统的状态,或者两者都改变。

这种指令的一个例子是 TransferAsset,它被用来将资产转移到远程系统的一些其他地址。它需要被告知要转移哪些资产,以及资产要被转移到谁/哪里。在 Rust 中,它是这样声明的:

enum Instruction {

TransferAsset {

assets: MultiAssets,

beneficiary: MultiLocation,

}

/* snip */

}

正如你可能猜到的那样,assets 是表达哪些资产将被转移的参数,而beneficiary则说明这些资产将被放到谁/哪里。当然,我们还缺少另外一个信息,即资产将从谁/哪里获得。这一点可以从 Origin Register 中自动推断出来。当程序开始时,这个寄存器一般根据传输系统(桥接器、XCMP 或其他什么)进行设置,以反映信息的实际来源,它与受益人的信息类型相同。Origin Register 作为一个受保护的寄存器运行 -- 程序不能任意设置它,尽管有两条指令可以用来以某些方式改变它。

在 XCM 中,所使用的类型是相当基本的想法:资产,由 MultiAsset 代表,以及共识内的地址,由 MultiLocation 代表。Origin Register 是一个可选的 MultiLocation(可选的,因为如果需要的话,它可以被完全清除)。

在 XCM 中的位置

MultiLocation 类型标识了存在于共识世界中的任何单一位置。它是一个相当抽象的概念,可以代表存在于共识中的各种事物,从可扩展的多分片区块链,如 Polkadot,一直到平行链上的低级 ERC-20 资产账户。在计算机科学术语中,它实际上只是一个全局性的单例数据结构,无论其大小或复杂性如何。

MultiLocation 总是表达一个相对于当前位置的位置。你可以认为它有点像文件系统路径,但没有办法直接表达文件系统树的"根"。这是因为一个简单的原因:在 Polkadot 的世界里,区块链可以被合并到其他区块链中,也可以从其他区块链中分离出来。一个区块链可以开始非常孤独的生活,并最终被提升到成为一个更大的共识中的一个平行链。如果它这样做了,那么,"根"的含义将在一夜之间改变,这可能会给 XCM 信息和其他使用 MultiLocation 的东西带来混乱。为了使事情简单化,我们完全排除了这种可能性。

XCM 中的位置是分层次的;共识中的一些地方完全被封装在共识中的其他地方。Polkadot 的一个平行链完全存在于整个 Polkadot 共识中,我们称它为内部位置。更严格地说,我们可以说,只要有一个共识系统,其中的任何变化都意味着另一个共识系统的变化,那么前一个系统就是在后者的内部。例如,一个 Canvas 智能合约对承载它的合约 pallet 来说是内部的。比特币中的 UTXO 是比特币区块链的内部。

这意味着 XCM 并不区分 "谁" 和 "哪里?"这两个问题。从 XCM 这种相当抽象的角度来看,这种区别其实并不重要 -- 这两个问题模糊不清,本质上是同一件事。

MultiLocations 用于识别发送 XCM 信息的地方,可以接收资产的地方,然后甚至可以帮助描述资产本身的类型,我们将看到非常有用的东西。

当把它们写成本文这样的文本时,它们被表达为一些..(或 "父级",封装的共识系统)组件,后面是一些交叉点,都用/隔开。(当我们用 Rust 这样的语言表达它们时,一般不会出现这种情况,但在写作中是有意义的,因为它很像人们熟悉的目录路径,被广泛使用。)交叉点在其封装的共识系统中识别一个内部位置。如果根本就没有父节点/交叉点,那么我们就说这个位置是这里。

一些例子

../Parachain(1000): 在一个平行链中进行评估,这将确定我们的同级平行链的索引为 1000。(在 Rust 中我们会写 ParentThen(Parachain(1000)).into())

../AccountId32(0x1234...cdef): 在平行链中进行评估,这将确定中继链上的 32 字节账户 0x1234...cdef。

Parachain(42)/AccountKey20(0x1234...abcd): 在中继链上评估,这将识别 42 号平行链上的 20 字节账户 0x1234...abcd(估计是像 Moonbeam 那样的东西,它承载着与 Ethereum 兼容的账户)。

XCM 上的资产

在 XCM 中工作时,经常需要提及某种资产。这是因为几乎所有现存的公链都依赖一些本地数字资产来为其内部经济和安全机制提供支柱。对于工作证明区块链,如比特币,原生资产(BTC)被用来奖励发展区块链的矿工,并防止重复消费。对于像 Polkadot 这样的基于权益证明的区块链,原生资产(DOT)被用作一种抵押品,网络维护者(被称为 stakers)必须冒着风险,以生成有效的区块并获得实物奖励。

一些区块链管理多种资产,例如,以太坊的 ERC-20 框架允许在链上管理许多不同的资产。有些管理的资产不是可替代资产 (如以太坊的 ETH),而是不可替代资产 (NFT) -- 独一无二的实例;Crypto-kitties 是这种不可替代的代币或 NFT 的早期例子。

XCM 的设计是为了能够处理所有这类资产而不费力。为此,有一个数据类型 MultiAsset 及其相关类型 MultiAssets、WildMultiAsset 和 MultiAssetFilter。让我们来看看 Rust 中的 MultiAsset:

struct MultiAsset {

id: AssetId,

fun: Fungibility,

}

因此,有两个字段定义了我们的资产:id 和 fun,这很好地说明了 XCM 是如何处理资产的。首先,必须提供一个整体的资产身份。对于可替代的资产来说,这只是确定了资产的身份。对于 NFT 来说,这确定了整个资产的 class--不同的资产实例可能在这个class中。

enum AssetId {

Concrete(MultiLocation),

Abstract(BinaryBlob),

}

资产身份以两种方式之一表达;具体或抽象。抽象的方式并没有真正使用,但它允许资产 ID 通过名称来指定。这很方便,但依赖于接收者以发送者期望的方式解释名称,这可能并不总是那么容易。具体的方式被普遍使用,它使用一个位置来明确地识别资产。对于本地资产(如 DOT),资产往往被识别为铸造该资产的链(本例中的 Polkadot 中继链,这将是其平行链中的一个位置)。主要在一个链的 pallet 内管理的资产可以通过一个位置来识别,包括其在该 pallet 内的索引。例如,Karura 平行链可能指的是 Statemine 链上的资产,位置为:../Parachain(1000)/PalletInstance(50)/GeneralIndex(42)。

enum Fungibility {

Fungible(NonZeroAmount),

NonFungible(AssetInstance),

}

其次,它们必须是可替代的或不可替代的。如果它们是可替代资产,那么就应该有一些相关的非零金额。如果它们是不可替代资产,那么就应该有一些指示来说明它们是哪一个实例,而不是一个数额。这通常用一个索引来表示,但 XCM 也允许使用其他各种数据类型,如数组和二进制 blobs。

这涵盖了 MultiAsset,但我们有时也会使用其他三种相关类型。MultiAssets 是其中之一,实际上只是指一组 MultiAsset 项目。然后我们有 WildMultiAsset;这是一个通配符,可以用来与一个或多个 MultiAsset 项目相匹配。实际上,它只支持两种通配符。All(与所有资产匹配)和 AllOf(与具有特定身份(AssetId)和可替代的所有资产匹配)。值得注意的是,对于后者,不需要指定金额(对于可替代资产)或实例(对于非可替代资产),所有资产都被匹配。

最后,还有 MultiAssetFilter。这是最常用的,实际上只是 MultiAssets 和 WildMultiAsset 的组合,允许指定通配符或明确的(即非通配符)资产列表。

在 Rust XCM API 中,我们提供了大量的转换功能,以使这些数据类型的工作尽可能不费力。例如,当我们在 Polkadot 中继链上时,要指定相当于 100 个不可分割的 DOT 资产单位(Planck,对于那些知道的人来说)的可替代的 MultiAsset,那么我们将使用(Here, 100).into()。

保留寄存器

让我们来看看另一条 XCM 指令:WithdrawAsset。从表面上看,这有点像 TransferAsset 的前半部分:它从 Origin Register 指定的地方的账户中提取一些资产。但它是如何处理这些资产的呢?- 如果它们没有被存放在任何地方,那么这肯定是一个非常无用的操作。让我们看一下它的 Rust 声明:

WithdrawAsset(MultiAssets),

所以,这次只有一个参数(MultiAssets类型,决定了哪些资产必须从 Origin Register 的所有权中撤出)。但并没有指定把资产放在什么地方。

已提取和未使用的资产被暂时保存在所谓的Holding Register(保留寄存器) 中("holding"是因为它们处于临时位置,不能无限期地存在)。有许多指令在Holding Register上操作。其中一个非常简单的指令是 DepositAsset 指令。让我们来看看它:

enum Instruction {

DepositAsset {

assets: MultiAssetFilter,

max_assets: u32,

beneficiary: MultiLocation,

},

/* snip */

}

精明的读者会发现,这看起来很像 TransferAsset 指令中缺少的那一半。我们有 assets 参数,指定哪些资产应该从Holding Register中取出来存入链上。max_assets 让 XCM 作者通知接收者打算存入多少个独特的资产。(这在事先了解 c 的内容而计算费用时很有帮助,因为存入资产可能是一项昂贵的操作)。最后是beneficiary(受益人),也就是我们之前在 TransferAsset 操作中遇到的那个参数。

有许多指令表达了对 beneficiary 的操作,DepositAsset 是其中最简单的一个。其他的一些指令则比较复杂。

XCM 中支付手续费

XCM 中的手续费支付是一个相当重要的用例。Polkadot 社区中的大多数链会要求他们的对话者为他们想要进行的任何操作支付手续费,否则他们会让自己受到"交易垃圾邮件"和拒绝服务攻击。当链有充分的理由相信他们的对话者会表现良好时,就会出现例外情况 -- 当 Polkadot 中继链与 Polkadot Statemint 共同利益链相对应时就是这种情况。然而对于一般情况,收费是确保 XCM 消息及其传输协议不能被过度使用的好方法。让我们来看看当 XCM 消息到达 Polkadot 时如何支付手续费。

正如已经提到的,XCM 并没有把手续费和手续费支付的想法作为第一等公民纳入其中。与以太坊的交易模式不同,手续费支付并不是协议中的内容,没有必要的用例必须明显地规避。就像 Rust 的零成本抽象一样,在 XCM 中,手续费支付没有很大的设计开销。

不过对于那些需要支付手续费的系统,XCM 提供了用资产购买执行资源的能力。概括地说,这样做包括三个部分。

首先,需要提供一些资产。

其次,必须就用资产换取计算时间(用 Substrate 的说法就是权重)进行协商。

最后,XCM 的操作将按照指示进行。

第一部分是由若干提供资产的 XCM 指令之一管理的。我们已经知道其中一条指令(WithdrawAsset),但还有其他几条,我们将在后面看到。当然,持有寄存器中的资产将用于支付与执行 XCM 相关的手续费。任何未用于支付费用的资产,我们都将存入某个目标账户中。在我们的例子中,我们假设 XCM 发生在 Polkadot 中继链上,而且是 1 DOT(即 10,000,000,000 不可分割的单位)。

到目前为止,我们的 XCM 指令看起来像:

WithdrawAsset((Here, 10_000_000_000).into()),

这给我们带来了第二部分,用这些资产的(部分)换取计算时间来支付我们的 XCM 的费用。为此,我们有一个 XCM 指令 BuyExecution。让我们来看看它。

enum Instruction {

/* snip */

BuyExecution {

fees: MultiAsset,

weight: u64,

},

}

第一项 fees 是应从 Holding Register 中提取并用于支付手续费的金额。从技术上讲,这只是最高限额,因为任何未使用的余额都会立即退回。

最终花费的金额由解释系统决定 -- fees 只是限制它,如果解释系统需要为所需的执行支付更多的费用,那么 BuyExecution 指令将导致错误。第二项是指定要购买的执行时间的数量。这一般应不低于 XCM 程序 (programme) 的总权重。

在我们的例子中,我们假设所有的 XCM 指令都需要一百万的权重,所以到目前为止,我们的两个项目(WithdrawAsset 和 BuyExecution)是两百万,还有一个是接下来的内容。我们将使用所有我们拥有的 DOT 来支付这些费用(这只是一个好主意,如果我们相信目的地链不会有疯狂的费用 -- 我们将假设我们有)。让我们看看到目前为止我们的 XCM:

WithdrawAsset((Here, 10_000_000_000).into()),

BuyExecution {

fees: (Here, 10_000_000_000).into(),

weight: 3_000_000,

},

我们的 XCM 的第三部分是将剩余的资金存入 Holding Register。为此,我们将使用 DepositAsset 指令。我们实际上不知道持有 Holding Register 中还有多少资金,但这并不重要,因为我们可以为应该存入的资产指定一个通配符。我们将把它们存入 Statemint 的主权账户(该账户被识别为 Parachain(1000))。

因此,我们最终的 XCM 指令看起来像这样:

WithdrawAsset((Here, 10_000_000_000).into()),

BuyExecution {

fees: (Here, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositAsset {

assets: All.into(),

max_assets: 1,

beneficiary: Parachain(1000).into(),

},

在 XCM 不同链之间移动资产

向另一条链发送资产可能是链间信息传递的最常见的使用情况。允许一条链管理另一条链的原生资产,可以实现各种衍生用途(不是双关语),最简单的是去中心化的交易所,但通常被归类为去中心化的金融或 DeFi。

一般来说,有两种方式可以让资产在链之间移动,这取决于链之间是否信任对方的安全和逻辑。

Teleporting(远程传送)

对于相互信任的链(如同一整体共识和安全保护伞下的同质分片),我们可以使用 Polkadot 称为远程传送 (Teleporting) 的框架,这基本上只是意味着在发送方销毁资产,在接收方铸币。这很简单,也很高效 -- 它只需要两个链的协调,而且只涉及任何一方的一个动作。不幸的是,如果接收链不能 100% 相信发送链会真正销毁它正在铸造的资产(并且确实不会在商定的资产规则之外铸造资产),那么发送链就真的没有依据在消息的背后铸造资产了。

让我们看看从 Polkadot 中继链上传送(大部分)1 DOT 到 Statemint 上的主权账户的 XCM 会是什么样子。我们将假设 Polkadot 方面已经支付了手续费。

WithdrawAsset((Here, 10_000_000_000).into()),

InitiateTeleport {

assets: All.into(),

dest: Parachain(1000).into(),

xcm: Xcm(vec![

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositAsset {

assets: All.into(),

max_assets: 1,

beneficiary: Parent.into(),

},

]),

}

正如你所看到的,这看起来与我们上次看到的直接提款 - 购买 - 存款模式相当相似。不同的是 InitiateTeleport 指令,它被插入到最后两条指令(BuyExecution 和 DepositAsset)的周围。在幕后,发送方(Polkadot Relay)链在执行 InitiateTeleport 指令时,正在创建一个全新的消息;它采用 xcm 字段,并将其置于一个新的 XCM,ReceiveTeleportedAsset,并将这个 XCM 发送给接收方(Statemint)链。Statemint 相信 Polkadot 中继链在发送消息之前已经销毁了它那边的 1 DOT。(它确实如此!)。

beneficiary(受益人) 被表述为 Parent.into(),精明的读者可能会想,在 Polkadot 中继链的上下文中,这可能指的是什么。答案是 "没有什么",但这里没有错。xcm 参数中的所有内容都是从接收方的角度编写的,所以尽管这是整个 XCM 的一部分,被送入 Polkadot 中继链,但它实际上只在 Statemint 上执行,因此它是在 Statemint 的上下文中编写的。

当 Statemint 最终得到消息时,它看起来像这样:

ReceiveTeleportedAsset((Parent, 10_000_000_000).into()),

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositAsset {

assets: All.into(),

max_assets: 1,

beneficiary: Parent.into(),

},

你可能会注意到,这看起来与之前的 WithdrawAsset XCM 相当相似。唯一的区别是,不是通过从本地账户取款来资助费用和存款,而是通过相信 DOT 在发送方(Polkadot 中继链)被忠实地销毁,并遵守 ReceiveTeleportedAsset 消息而 "神奇" 地存在。

值得注意的是,我们在 Polkadot 中继链上发送的 1 个 DOT 的资产标识符(这里指的是中继链本身是 DOT 的原生家园)已经自动变异为 Statemint 上的表示。Parent.into(),这是 Statemint 上下文中的中继链的位置。

beneficiary(受益人) 也被指定为 Polkadot 中继链,因此它的主权账户(在 Statemint 上)被记入新造的 1 DOT 减去手续费。XCM 可能只是很容易地为受益人指定一个账户或其他地方。就像现在这样,后来从中继链发送的 TransferAsset 可以用来转移这 1 DOT。

储备金

跨链转移资产的另一种方式稍微复杂一些。一个被称为储备金的第三方被使用。这个名字来自于储备银行业务,在这种业务中,资产被"储备"起来,以使一些发行的承诺具有可信度。例如,如果我们可以合理地相信,在一个独立的平行链上发行的每一个"衍生 " DOT 都可以赎回 1 个 "真实"(如 Statemint 或 中继链)DOT,那么我们可以将平行链的 DOT 视为经济上等同于真实的 DOT,(大多数银行做的是所谓的部分储备银行,这意味着他们保留的储备少于面值)。这种做法很好,直到有太多的人希望赎回,然后一切都会很快出问题。

因此,储备金是储存 "真实" 资产的地方,而且为了转让的目的,其逻辑和安全性得到了发送方和接收方的信任。然后,发送方和接收方的任何相应资产将是衍生品,但它们将由 "真正的" 储备资产 100% 支持。假设平行链表现良好(即它没有错误,其治理者没有决定带着储备金逃跑),这将使衍生品 DOT 或多或少具有与基础储备 DOT 相同的价值。储备资产被存放在储备链上的发送方/接收方的主权账户(即发送方或接收方链可控制的账户),所以有充分的理由认为,除非平行链出了问题,否则它们会被很好地保护起来。

回到转移机制,发送方将指示储备金将发送方拥有的资产(并作为其自身版本的相同资产的储备金)转移到接收方的主权账户,而储备金 (而不是发送方!) 通知接收方他们的有新存款。这意味着发送方和接收方不需要相信对方的逻辑或安全,而只需要相信用作储备的链。然而,这确实意味着三方需要协调,这增加了整体成本、时间和复杂性。

让我们来看看所需的 XCM。这一次,我们将从 parachain 2000 向 parachain 2001 发送 1 个 DOT,这在 parachain 1000 上使用储备金支持的 DOT。同样,我们将假设费用在发送方已经支付。

WithdrawAsset((Parent, 10_000_000_000).into()),

InitiateReserveWithdraw {

assets: All.into(),

dest: ParentThen(Parachain(1000)).into(),

xcm: Xcm(vec![

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositReserveAsset {

assets: All.into(),

max_assets: 1,

dest: ParentThen(Parachain(2001)).into(),

xcm: Xcm(vec![

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositAsset {

assets: All.into(),

max_assets: 1,

beneficiary: ParentThen(Parachain(2000)).into(),

},

]),

},

]),

},

这是一个有点复杂的问题,正如承诺的那样。让我们来看看。外部部分处理在发送方提取 1 DOT(parachain 2000)和在 Statemint 提取相应的 1 DOT(parachain 1000)-- 它为此目的使用 InitiateReserveWithdraw,这一点不言而喻。

WithdrawAsset((Parent, 10_000_000_000).into()),

InitiateReserveWithdraw {

assets: All.into(),

dest: ParentThen(Parachain(1000)).into(),

xcm: /* snip */

}

现在我们在 Statemint 的持有寄存器中有 1 个 DOT。在我们做其他事情之前,我们需要在 Statemint 购买一些执行时间。这一点,再次看起来非常熟悉。

/*snip*/

xcm: Xcm(vec![

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositReserveAsset {

assets: All.into(),

max_assets: 1,

dest: ParentThen(Parachain(2001)).into(),

xcm: /* snip */

},

]),

/*snip*/

我们用我们的 1 个 DOT 来支付手续费,我们假设每个 XCM 操作有 100 万。在支付了这一操作后,我们将 1 DOT(减去费用,我们很懒,所以我们只用 All.into())存入 parachain 2001 的主权账户,但作为储备资产这样做,意味着我们还要求 Statemint 向接收链发送通知 XCM,告知它转移的情况以及一些要对所产生的衍生资产执行的指令。DepositReserveAsset 指令并不总是有意义的;要想有意义,目的地必须是一个可以在储备链上合理持有资金的位置,同时也是储备链可以发送 XCM 的位置。兄弟平行链恰好完全符合这个要求。

/*snip*/

xcm: Xcm(vec![

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositAsset {

assets: All.into(),

max_assets: 1,

beneficiary: ParentThen(Parachain(2000)).into(),

},

]),

/*snip*/

最后一部分定义了到达 parachain 2001 的消息的一部分。就像启动远程传送 (teleport) 操作一样,DepositReserveAsset 组成并发送一个新的消息,在此情况下是 ReserveAssetDeposited。正是这个消息,尽管包含了我们定义的 XCM 程序,到达了接收的平行链。它看起来会像这样:

ReserveAssetDeposited((Parent, 10_000_000_000).into()),

BuyExecution {

fees: (Parent, 10_000_000_000).into(),

weight: 3_000_000,

},

DepositAsset {

assets: All.into(),

max_assets: 1,

beneficiary: ParentThen(Parachain(2000)).into(),

},

(这是假设 Statemint 没有实际收取任何费用,而且整个 1 DOT 都是由它提供的。这并不特别现实,所以assets这一行可能会有一个较低的数字)。

该消息的大部分内容看起来都很熟悉;与我们在上一节看到的 ReceiveTeleportedAsset 消息的唯一显著区别是顶层指令:ReserveAssetDeposited。

它实现了类似的目的,只是它的意思不是 "发送链烧毁了资产,所以你可以铸造同等资产",而是 "发送链收到了资产并为你持有它们的储备金,所以你可以铸造完全支持的衍生资产"。无论哪种方式,目的链都会将其铸币到 Holding Register 中,而我们则将其存入接收链上的发送方主权账户。

总结

本文对于 XCM 以及它的设计和工作原理进行了深入浅出的探讨。此外,我们还深入探讨了 XCVM 的架构、执行模型和错误处理、XCM 的版本系统和如何在一个相互关联的生态系统中管理格式的升级,以及它的查询 - 响应系统和 XCM 如何在 Substrate 中工作。以及 XCM 的一些未来方向、计划中的功能和发展过程。

你可能也喜欢

交易

现货
合约

热门文章

如何购买DOT

欢迎来到HTX.com!我们已经让购买Polkadot(DOT)变得简单而便捷。跟随我们的逐步指南,放心开始您的加密货币之旅。第一步:创建您的HTX账户使用您的电子邮件、手机号码注册一个免费账户在HTX上。体验无忧的注册过程并解锁所有平台功能。立即注册第二步:前往买币页面,选择您的支付方式信用卡/借记卡购买:使用您的Visa或Mastercard即时购买Polkadot(DOT)。余额购买:使用您HTX账户余额中的资金进行无缝交易。第三方购买:探索诸如Google Pay或Apple Pay等流行支付方法以增加便利性。C2C购买:在HTX平台上直接与其他用户交易。HTX场外交易台(OTC)购买:为大量交易者提供个性化服务和竞争性汇率。第三步:存储您的Polkadot(DOT)购买完您的Polkadot(DOT)后,将其存储在您的HTX账户钱包中。您也可以通过区块链转账将其发送到其他地方或者用于交易其他加密货币。第四步:交易Polkadot(DOT)在HTX的现货市场轻松交易Polkadot(DOT)。访问您的账户,选择您的交易对,执行您的交易,并实时监控。HTX为初学者和经验丰富的交易者提供了友好的用户体验。

1.1k人学过发布于 2024.03.29更新于 2025.03.21

如何购买DOT

相关讨论

欢迎来到HTX社区。在这里,您可以了解最新的平台发展动态并获得专业的市场意见。以下是用户对DOT(DOT)币价的意见。

活动图片