XCM 参考

⚠️ Update Notice:

Please read Substrate to Polkadot SDK page first.


请参考 Rust 文档 以获取有关此主题的最新文档。

本节提供跨共识消息 (XCM) 格式的参考信息。

指令

正如您在 跨共识通信 中了解到的那样,XCM 执行器是一个程序,它在接收方共识系统上运行的虚拟机中执行有序的指令集。 值得注意的是,一些指令依赖于其他指令。 Instruction 枚举中列出的指令顺序反映了其中一些依赖关系。 例如,必须将资产添加到持有注册表中,然后才能将其存入其他位置。 通常,在构建要发送到接收系统的消息时,您也会对指令使用类似的顺序。 但是,为了方便起见,本参考部分按字母顺序而不是定义顺序列出指令。

BuyExecution

通过从持有注册表中删除资产来支付当前消息的执行费用。 您必须指定 fees 参数才能识别要从持有注册表中删除以支付执行费用的资产。 您还可以为要购买的最大费用指定 weight_limit。 如果您指定的 weight_limit 低于消息的估计权重,则 XCM 执行器将停止执行,并显示 TooExpensive 错误。

参数说明
fees指定要从持有注册表中删除以支付交易费用的资产。
weight_limit指定要购买以支付执行费用的最大权重。如果您没有指定限制,则权重将被视为无限,直到您指定要从持有注册表中删除的最大值。

以下示例说明了 BuyExecution 指令的设置:

{
  BuyExecution: {
    fees: {
      id: {
        Concrete: {
          parents: 0
          interior: Here
        }
      }
      fun: {
        Fungible: 1,000,000
      }
    }
    weightLimit: {
      Limited: 1,000,000
    }
  }
}

以下示例说明了在 Rust 程序中使用该指令:

BuyExecution { fees, weight_limit } => {
    if let Some(weight) = Option::<u64>::from(weight_limit) {
        // 使用持有注册表中最多 `fees` 的金额来支付 `weight`。
        let max_fee =
            self.holding.try_take(fees.into()).map_err(|_| XcmError::NotHoldingFees)?;
        let unspent = self.trader.buy_weight(weight, max_fee)?;
        self.holding.subsume_assets(unspent);
    }
    Ok(())
},

ClaimAsset

创建代表来源注册表中标识的位置持有的资产。 您必须指定 assets 参数才能识别要声明的资产。 您指定的资产必须与来源可以使用给定 ticket 声明的资产完全匹配。 您必须使用 MultiLocation 类型指定 ticket。 资产的声明票据是一个抽象标识符,用于帮助查找要声明的资产。

参数说明
assets指定要声明的资产。
ticket指定一个位置来帮助识别要声明的资产。

ClearError

清除错误注册表。 您可以使用此指令手动清除错误注册表中的最后一个错误。

ClearOrigin

清除来源注册表。 您可以使用此指令确保后续指令无法接管原始来源的权限。 例如,如果您有来自不受信任的来源转发的指令,就像 ReserveAssetDeposited 经常出现的情况一样,您可以使用 ClearOrigin 来防止使用原始来源执行指令。

以下示例将 ReserveAssetDeposited 和 ClearOrigin 指令添加到现有消息中:

let mut message = vec![ReserveAssetDeposited(assets), ClearOrigin];
message.extend(xcm.0.into_iter());

DepositAsset

从持有注册表中减去指定的资产,并在指定 beneficiary 的所有权下在链上存入等效资产。 您必须使用 MultiAssetFilter 类型指定要删除的 assets

参数说明
assets指定要从持有注册表中删除的资产。
max_assets指定要从持有注册表中删除的唯一资产或资产实例的最大数量。仅删除与指定的 assets 匹配的、按标准资产顺序排列的前 max_assets 个唯一资产或资产实例。如果还有其他唯一资产或资产实例,它们将保留在持有注册表中。
beneficiary指定资产的新所有者。

以下示例说明包含 DepositAsset 指令的简单消息:

ParaA::execute_with(|| {
        let message = Xcm(vec![
            WithdrawAsset((Here, send_amount).into()),
            buy_execution((Here, send_amount)),
            DepositAsset { assets: All.into(), max_assets: 1, beneficiary: Parachain(2).into() },
        ]);
        // 发送提取和存款
        assert_ok!(ParachainPalletXcm::send_xcm(Here, Parent, message.clone()));
    });

DepositReserveAsset

从持有注册表中删除资产,并将等效资产存入目标的主权帐户中。 此指令还会向 ReserveAssetDeposited 指令的目标发送带有给定效果的后续消息。

参数说明
assets指定要从持有注册表中删除的资产。
max_assets指定要从持有注册表中删除的唯一资产或资产实例的最大数量。仅删除与指定的 assets 匹配的、按标准资产顺序排列的前 max_assets 个唯一资产或资产实例。如果还有其他唯一资产或资产实例,它们将保留在持有注册表中。
destination指定其主权帐户将拥有资产并因此成为资产的有效受益者以及储备资产存款消息的通知目标的位置。
xcm指定在 ReserveAssetDeposited 指令后在 destination 位置执行的其他指令。

DescendOrigin

将来源更改为来源注册表中当前值上下文中的某个内部位置。

参数说明
interior指定要放在来源注册表中的内部位置。

ExchangeAsset

将持有注册表中的资产减少到 give 参数指定的数量,并使用 receive 参数指定的最少数量的替代资产增加持有注册表中的资产。

参数说明
give指定要从持有注册表中删除的资产。
receive指定要在持有注册表中增加的资产。为 receive 参数指定的任何可替代资产都可以增加超过表达的数量,但持有注册表不能累积 receive 中未声明的资产。

HrmpChannelAccepted

发送一条通知消息,通知接收方已接受打开通道请求。 发送此通知后,当中继链会话更改时,通道将打开。 此消息应直接源于中继链,并旨在由中继链发送到 Parachain。

参数说明
recipient指定已接受先前开通通道请求的接收方 Parachain 的 Parachain 标识符。

HrmpChannelClosing

发送消息以通知接收方,启动打开通道请求的发送方已决定关闭通道。 发送此通知后,当中继链会话更改时,通道将关闭。 此消息应直接源于中继链,并旨在由中继链发送到 Parachain。

参数说明
initiator指定启动通道关闭操作的 Parachain 的 Parachain 标识符。
sender指定正在关闭的通道的发送方侧的 Parachain 标识符。
recipient指定正在关闭的通道的接收方侧的 Parachain 标识符。

HrmpNewChannelOpenRequest

从 Parachain 向中继链发送请求,以打开一个新的通道,用于与另一个 Parachain 进行通信。 使用 HRMP 传输协议传递的消息始终通过中继链路由。 此消息应直接源于中继链,并旨在由中继链发送到 Parachain。

参数说明
sender指定要在其中打开通道的发送方。也是通道打开的启动方。
max_message_size指定发送方建议的消息的最大大小。
max_capacity指定可以在通道中排队的最大消息数。

InitiateReserveWithdraw

将持有注册表的值减少到资产,并将以 WithdrawAsset 开头的 XCM 指令发送到储备位置。

参数说明
assets指定要从持有注册表中删除的资产。
reserve指定充当所有指定资产储备的有效位置。储备位置上的此共识系统的主权帐户将提取相应的资产,并对其执行效果。在任何给定的资产/链组合上,通常只有一个有效位置。
xcm指定在储备位置提取资产后对资产执行的其他指令。

InitiateTeleport

从持有注册表中删除资产,并将以 ReceiveTeleportedAsset 指令开头的消息发送到指定的目标位置。

注意:目标位置必须将指令的来源视为所有资产的有效传送来源。 如果不是,则资产可能会丢失。

参数说明
assets指定要从持有注册表中删除的资产。
destination指定尊重来自此位置的传送的有效位置。
xcm指定在 ReceiveTeleportedAsset 指令后在 destination 位置执行的其他指令。

QueryHolding

发送一条 QueryResponse 消息,其资产值等于持有内容或其一部分。

参数说明
query_id指定用于 QueryResponse 消息的 query_id 字段的标识符。
destination指定应将 QueryResponse 消息发送到的位置。
assets指定应报告回的资产的过滤器。
max_response_weight指定要用于 QueryResponse 消息的 max_weight 字段的值。

以下示例说明一个 QueryHolding 指令,该指令返回一个标识符为 query_id_set 的 QueryResponse:

ParaA::execute_with(|| {
	let message = Xcm(vec![
			QueryHolding {
				query_id: query_id_set,
				dest: Parachain(1).into(),
				assets: All.into(),
				max_response_weight: 1_000_000_000,
			},
	]);
});

QueryResponse

提供来自来源的预期信息。

参数说明
query_id指定导致发送此消息的查询的标识符。

| response: 表示导致查询指令的消息内容。 | max_weight | 指定处理此响应应花费的最大权重。如果正确的执行需要比您指定的权重更多,则会返回错误。如果执行所需的权重少于您指定的权重,则差异可能会在运行时添加到剩余权重注册表中。

Response 类型用于在 QueryResponse XCM 指令中表达信息内容。 根据查询,它可以表示以下不同的数据类型:

  • Null
  • Assets { assets: MultiAssets }
  • ExecutionResult { result: Result<(), (u32, Error)> }
  • Version { version: Compact }

以下示例说明了检查是否已收到 QueryResponse 消息以及响应中的信息是否为新存入的资产:

ParaA::execute_with(|| {
	assert_eq!(
			parachain::MsgQueue::received_dmp(),
			vec![Xcm(vec![QueryResponse {
					query_id: query_id_set,
					response: Response::Assets(MultiAssets::new()),
					max_weight: 1_000_000_000,
			}])],
	);
});

ReceiveTeleportedAsset

将等效于从当前来源删除的资产的资产累积到持有注册表中。 来源必须被信任为已删除资产,这是发送此消息的结果。

参数说明
assets指定已从来源删除的资产。

RefundSurplus

将已退款权重注册表增加到剩余权重注册表的值。 此指令使先前使用 BuyExecution 指令支付的费用可以移动到持有注册表中,以匹配添加到已退款权重注册表中的金额。

ReportError

使用 XCM 将错误注册表的内容报告给指定的 destination。 将类型为 ExecutionOutcome 的 QueryResponse 消息发送到 destination,其中包含给定的 query_id 和 XCM 的结果。

参数说明
query_id指定要用于 QueryResponse 消息的 query_id 字段的值。
destination指定应将 QueryResponse 消息发送到的位置。
max_response_weight指定要用于 QueryResponse 消息的 max_weight 字段的值。

ReserveAssetDeposited

向持有注册表添加派生资产,以表示从来源注册表中的值接收到的资产。 来源必须被信任为资产的储备。

参数说明
assets指定已从来源接收到的本地共识系统主权帐户中的资产。

SetAppendix

设置附加注册表。 附加注册表提供在当前程序完成执行后应运行的任何代码。 在当前程序成功结束或在错误处理程序为空的错误之后,附加注册表将被清除,其内容将用于替换程序注册表。 此指令的估计权重必须包含 appendix 代码的估计权重。 在运行时,应在更改之前将剩余权重注册表增加到附加程序的估计权重。

参数说明
appendix: Xcm:要设置为附加注册表的值。

SetErrorHandler

设置错误处理程序注册表。 错误处理程序注册表提供程序遇到错误时应运行的任何代码。 程序遇到错误后,此注册表将被清除,其内容将用于替换程序注册表。 此指令的估计权重必须包含 error_handler 代码的估计权重。 在运行时,应在更改之前将剩余权重注册表增加到错误处理程序的估计权重。

参数说明
error_handler指定要在错误处理程序注册表中设置的值。

SubscribeVersion

向 Origin 发送 QueryResponse 消息,在响应字段中指定 XCM 版本。 对本地共识的任何升级(导致支持更高版本的 XCM)都应产生类似的响应。

参数说明
query_id指定要用于 QueryResponse 消息的 query_id 字段的值。
max_response_weight指定要用于 QueryResponse 消息的 max_weight 字段的值。

Transact

使用调用程序的调度来源调度编码的调用,该来源由您使用 origin_type 参数指定的上下文表示。

参数说明
origin_type指定一个上下文,用于将消息来源表示为调度来源。
max_weight指定在调度编码的调用时要消耗的最大权重。如果调度需要的权重超过您指定的权重,则执行将停止并返回错误。如果调度需要的权重少于您指定的权重,则差异可能会在运行时添加到剩余权重注册表中。
call指定要在接收系统上执行的编码交易。

TransferAsset

从 Origin 的所有权中提取资产,并在受益人的所有权下存入等效资产。

参数说明
assets指定要转移的资产。
beneficiary指定资产的新所有者。

TransferReserveAsset

从当前来源的所有权中提取资产,并在目标的主权帐户下存入等效资产。 此指令还会向指定的目标发送一条包含 ReserveAssetDeposited 和 xcm 参数中指定的任何指令的附加消息。

参数说明
assets指定要转移的资产。
destination指定其主权帐户将拥有资产并因此成为资产的有效受益者以及储备资产存款消息的通知目标的位置。
xcm指定应在 ReserveAssetDeposited 指令后执行的指令。

以下示例说明了包含两条附加指令的消息中使用的 TransferReserveAsset 指令:

let mut message = Xcm(vec![TransferReserveAsset {
    assets,
    dest,
    xcm: Xcm(vec![
        BuyExecution { fees, weight_limit: Unlimited },
        DepositAsset { assets: Wild(All), max_assets, beneficiary },
    ]),
}]);

Trap

抛出类型为 Trap 的错误。

参数说明
id指定要用于抛出错误的参数的值。

UnsubscribeVersion

取消来自 Origin 的先前 SubscribeVersion 指令的效果。

WithdrawAsset

从本地共识系统上的发送帐户中删除指定的资产,并将它们添加到持有注册表的值中。

参数说明
assets指定要从发送者处删除的资产。该资产必须由来源注册表中的帐户拥有。

注册表

大多数 XCVM 注册表无法直接修改。 它们被设置为特定的起始值,并且仅在某些情况下或根据某些规则由特定指令操作。 XCVM 包含以下注册表:

注册表说明
Origin存储当前程序在其下运行的权限的位置。
Holding存储在 XCVM 控制下但没有链上表示的资产数量。
Surplus weight存储先前计算的权重的高估值。
Refunded weight存储已退款的剩余权重部分。
Programme存储当前正在执行的 XCM 指令集。此注册表在跨共识虚拟机中保存完整的邮件(程序)。
Programme counter存储当前正在执行的指令的指令索引。在每条成功执行的指令结束时,该值会递增 1。当程序注册表更改时,该注册表将重置为零。
Error存储程序执行期间最后一个已知错误的信息。
Error handler存储如果程序遇到错误则应运行的代码。
Appendix存储当前程序结束后应运行的代码。

来源

在某些情况下,您可能希望操作来源注册表中存储的来源,以便为执行特定操作或执行特定 XCM 指令授予更多或更少的权限。 您可以使用以下来源类型来操作如何解释 XCM 指令的来源。

来源类型说明
Native使用本地运行时框架中发送者的本机调度来源表示。对于大多数链来说,如果来自链,则为 ParachainRelay 来源。
SovereignAccount使用发送者的主权帐户。对于大多数链来说,这是 Signed 来源。
Superuser使用超级用户帐户。普通帐户无法使用此来源,并且在许多情况下,任何帐户都无法使用它。对于大多数链来说,这是 Root 来源。
Xcm使用 XCM 本机来源和直接在调度来源中编码的 MultiLocation 不变。对于大多数链来说,这是 pallet_xcm::Origin::Xcm 类型。

使用不同来源的影响取决于您调用的代码。 根据您的链逻辑和权限,您可能无法生成要使用的来源。 例如,大多数用户无法生成超级用户来源,但链逻辑可以这样做。

以下示例说明了在 Transact 指令中指定来源类型:

Transact {
	origin_type: OriginKind::SovereignAccount,
	require_weight_at_most: weight,
	call: call.encode().into(),
},

有关转换来源的其他示例,请参阅 origin_conversion 模块。

错误

如果执行 XCM 指令的程序遇到问题,它将停止执行,并使用以下错误之一来标识遇到的问题类型:

错误类型说明
Overflow = 0指令导致算术溢出。
Unimplemented = 1该指令故意不受支持。
UntrustedReserveLocation = 2来源注册表不包含储备转移通知的有效值。
UntrustedTeleportLocation = 3来源注册表不包含传送通知的有效值。
MultiLocationFull = 4MultiLocation 值太大,无法进一步下降。
MultiLocationNotInvertible = 5MultiLocation 值上升的父级数量超过本地位置的已知祖先数量。
BadOrigin = 6来源注册表不包含执行指令的有效值。
InvalidLocation = 7位置参数不是指令的有效值。
AssetNotFound = 8未找到指定的资产,或者在为指令指定的位置中无效。
FailedToTransactAsset = 9资产交易(例如,提取或存入资产的指令)失败。在大多数情况下,此类错误是由类型转换问题引起的。
NotWithdrawable = 10无法提取指定的资产,这可能是由于缺乏所有权、资产可用性或权限造成的。
LocationCannotHold = 11无法在特定位置的所有权下存入指定的资产。
ExceedsMaxMessageSize = 12尝试发送的消息超过了传输协议支持的最大消息大小。
DestinationUnsupported = 13尝试发送的消息无法转换为目标支持的格式。
Transport = 14目标是可路由的,但传输机制存在问题。
Unroutable = 15已知目标不可路由。
UnknownClaim = 16未识别 ClaimAsset 指令指定的声明,或者找不到该声明。
FailedToDecode = 17无法解码 Transact 指令指定的函数。
TooMuchWeightRequired = 18Transact 指令指定的函数可能会超过允许的权重限制。
NotHoldingFees = 19持有注册表不包含 BuyExecution 指令要使用的任何可支付费用。
TooExpensive = 20BuyExecution 指令中声明的购买权重的费用不足。
Trap(u64) = 21Trap 指令用于故意强制出错。包含其代码。
ExpectationFalse = 22如果期望不为真,则由 ExpectAsset、ExpectError 和 ExpectOrigin 使用。

具体标识符通过其在共识系统中的位置(相对于执行指令的上下文)来唯一标识单个资产。