XCM基础部分
指引:
ParachainDevelopment·PolkadotWiki「1」
XCM:TheCross-ConsensusMessageFormat「2」
XCM消息格式
OverviewofXCM:AFormat,NotaProtocol
xcm-format参考资料「3」
XCMisrelatedtocross-chaininthesamewaythatRESTisrelatedRESTful.
XCM是一种消息格式,而不是消息传递协议,因为它无法在系统之间发送任何消息,仅仅是一种应如何执行消息传输的格式,也就是表达接收者应该做什么。XCM还可用于通过UMP、DMP、XCMP通信通道中的任意一个来表发消息的含义。
xcm消息里带有执行消息和位置信息
例如:链和链之间,合约与合约之间的xcm消息传递都可以用这套规范来实现,这些东西不能依托于链来实现,因为这套规范,如果依托于链本身,那每次链的升级都相当于做了一次xcm版本的升级。这很影响兼容性。
XCM不仅仅是跨链,而是"跨共识"消息格式!-技术圈「4」
XCM的核心—XCVM
XCMformat?的核心是XCVM,它是一种超高级非图灵完备计算机,它的指令设计和交易大致处于同一水平。
XCM中的“消息”实际上只是XCVM上运行的程序。它是一个或多个XCM指令。程序一直执行,直到它运行到最后或遇到错误,此时它完成并停止。
XCVM包括许多寄存器,以及对托管它的共识系统的整体状态的访问。指令可能会更改寄存器,它们可能会更改共识系统的状态或两者兼而有之。
MultiLocations
可以理解为共识系統语义下的“位置”
需要注意的是,所有位置都是从消息解释器的相对角度来看的。就如下面的例如...
从ParachainA的?度来看:
RelayChain:X1(Parent)
ParachainA:Self
ParachainB:X2(Parent,ParachainB)
ContractA:X1(ContractA)
ContractB:X3(Parent,ParachainB,ContractB)
Alice:X2(ContractA,AcountId32{Alice})
Bob:X1(AcountId32{Bob})
Charlie:X3(Parent,ParachainB,AcountId32{Charlie})
Dave:X4(Parent,ParachainB,ContractB,AcountId32{Dave})
消息路由
Cross-ConsensusProtocols
随着XCMFormat的正式建立,这些messages需要协议的通用模式,Polkadot实现了两个,用于在其组成的parachain之间处理XCMmessages。
注:下文中的“消息”意指上面提到的messages。
VMP
实际上,有两种垂直消息传递传输协议。
UMP:允许平行链向他的中继链发送消息
DMP:允许中继链将消息向下传递到他们的平行链之一。
注意,
DMP?的消息也可能来自平行链,例如:平行链A转给平行链B的情况,这个过程是这样子的。
首先平行链A将使用
UMP,将消息传递给中继链,其次中继链再根据
DMP将消息向下传递给平行链B
XCMP
XCMP允许平行链与其中继链上其他的平行链交换消息。
跨链交易使用基于Merkle树的简单排队机制来解决,以确保fidelity。中继链验证人的任务是将一个平行链的输出队列上的交易移动到目标平行链的输入队列中。但是,只有关联的metadata作为hash存储在中继链的存储中。
输入和输出队列有时在Polkadot代码库和相关文档中分别称为ingress和egress消息。
XCMP-精简版
水平中继路由消息传递协议(HRMP)?协议是未完全完成的功能的临时替代品。虽然XCMP本身仍在开发中,但HRMP是一个有效的替代品。
HRMP具有与XCMP相同的接口和功能,但对资源的要求更高,因为它将所有消息存储在中继链存储中。当XCMP实施后,HRMP计划被弃用并逐步淘汰以支持它。
XCMP
(思想:中继链只保存相关元数据的hash值,只做关于xcm的相关验证。)
由于现在XCMP还没有被完全开发出来,现在主要使用的是HRMP,上文也提到了,HRMP需要用到许多的资源,现在吞吐量可能会是42条平行链上下。不过现在parity的开发者已经在把其他模块交易移到其他平行链比如国库财政部分来提高吞吐能力和承载链数量。
小问题:
xcm消息执行失败了,怎么办呢题外话:波卡网络上平行链只负责出块,所以没有grandpa共识,最后敲定区块上交给中继链决定的。
消息分发
Polkadot'sMessagingScheme「5」
Polkadot的跨链消息传递方案「6」
平?链阶段中,收集?打包区块的同时,也会将跨链交易放到平?链的出队列中。跨链交易通过
XCMP协议进?传输,根据收集?和验证?的?络连接情况,
具体的传输?法有三种:
发起链收集?直接发送给?标链收集?;
发起链验证?发送给?标链收集?;发起链收集?发送给发起链验证?,发起链验证?传递给?标链验证?,?标链验证?再传递给?标链收集?。
跨链交易传递到?标链后,会把跨链交易放到平?链?队列中。通过以上步骤,就完成了跨链交易在链间的传递。
如果A和B不共享全节点,则需要依靠中继链上的验证?来传递消息。
队列
中继链验证者应负责将某?平?链上输出队列中的交易移??标平?链上的输?队列中。
收集?节点负责把平?链之间的信息传递。
收集?产?"出?"列表信息并会在"??"接收到其它平?链信息。
当收集?产?了区块并提交给验证?,它会收集最新??队列信息并且处理它。
验证?将会对收集?提交的平?链区块进?验证,包括处理到该平?链预期??的信息。
cumulus的pallets中两种队列:
MQC
消息队列链是由验证人创建的一个通用哈希链,用于跟踪从发送方发送到单个接收方的每条消息以及顺序。
MQC本身不保存在任何地方,而是只提供所有接受到的消息的最终证明。当验证器接收到候选消息时,它从放置在upward_messages中的消息中按升序生成MQC
FeatureXCMP
Cross-ConsensusMessageFormat(XCM)·PolkadotWiki「7」
平行链之间直接通信,在中继链上只更新proofs和读取confirmations,只包含验证消息处理的必要信息。
假设平行链A上部署的一个合约要发一条跨链调用的消息给平行链B,从而调用位于链B上的合约完成资产转移,其整体流程如下:
调用者在链A上调用部署在链A上的智能合约,从而初始化一条以链B为目的地的跨链消息M;
链A的收集人节点会将这条消息M连同其目的地、时间戳放到A的出口队列中;
链B的收集人在正常情况下会轮询其他所有的平行链的收集者节点以查看是否有自己的消息。如果在新一轮询问中发现有以自己为目的地的消息,那么其会将这条消息放到自己的入口队列中,以待在产生下一个区块的时候处理该消息;
另外,链A的验证人也会通过读取链A的出口队列从而知道这条消息;链B的验证人也是。验证人也需要知道这些消息,因为之后它们都会对这条消息进行验证;
当链B的收集人节点开始构建一个新区块的时候,它会处理当前入口队列中所有的消息;在处理过程中,消息M会执行链B中相应的智能合约以此完成预期的资产转移;
然后收集人将这个区块提交给验证人,验证人会验证消息M是否真的被处理了;如果这条消息被验证确实处理了,并且这个区块没有其他不合法的地方,验证者就会把该块确认进中继链中。
跨链资产转账详解:从基础到实践
上方都是关于XCM的基础部分,有了上面的知识,我们就进一步扩展讲讲其中的一些应用实现,例如跨链资产转账。
关于平行链之间进行资产转账会有一些细节。
跨链资产转账方式
XCM其实定义了两种转账的方式,一种是AssetTeleportation一种是ReserveAssetTransfer。
参考:HowcanItransferassetsusingXCM?「8」
AssetTeleportation
这个转账模型只有两个参与者,源和目的地。
例子:
Rust?//?链A的Alice向链B的Bob转账100个链A的native?token_aTransfer_teleport_asset(source_alice,?dest_bob,?token_a,?100);
过程:
首先先会在链Aburn掉Alice的100个token_a,并记下burn掉的资产总量,
然后链A会创建一个名为"ReceiveTeleportedAssets"的XCM指令,并将burn掉的资产数量和链B的相对位置作为这条XCM指令的参数,然后它会将这条指令发送到目的地,在那里它被处理并根据参数里的信息mint新的资产。
最后链B会将新锻造的资产存入Bob账户中。
缺点:
它要求来源和目的地都具有高度的相互信任。目的地必须相信来源已经烧毁了发送过来的资产,并且来源还必须相信目的地铸造在来源处被烧毁的资产。
不支持这两个条件中的任何一个都将导致资产的总发行量发生变化或NFT的完全丢失/重复。
ReserveAssetTransfer
过程:chainA上的account1想转移某个资产到chainB上的account2账??,那?先将account1的资产转移?chainA上的chainB代表账?,再发送?条通知消息给chainB,chainB将对应的资产分配给account2。
ps:其实业界里更推崇后者(reserve),相较于前者会更有保障。像orml-xtokens其实就是基于reserve方式实现的平行链多资产转账模块。
为平行链添加跨链资产转移的功能
我们接下来的目的就是创建两条平行链,让这两条平行链支持多资产并且实现跨链资产转账。
实验环境
我们会准备4个中继链的验证人节点以支持两条平行链。因为我们要模拟链A到链B的跨链资产转移以及平行链到中继链的跨链资产转移。
-4个验证人的中继链
-平行链A
-平行链B
平行链的跨链转账一共有两种场景:
平行链转中继链平行链转中继链都是转的中继链代币,如果想让自己的平行链能支持向中继链跨链转账的功能其实只需要配置XcmConfig就行。
平行链A转平行链B平行链之间的转账会稍微复杂些,因为会涉及多资产转账的问题,这里只需要配置XcmConfig以及添加orml模块就行。
接下来我们直接分析整个完整的runtime配置来介绍一下配置跨链资产转账时需要注意的配置项以及其含义。
平行链转中继链
为两条平行链添加支持向中继链进行跨链转账的功能。
进行runtime配置
其实是关于XcmExecutor的配置,其中一项XcmConfig就是指定XcmSender.这是你需要包含实现XCMP协议的pallet的地方。根据您要将XCM发送给谁,如果是要发送到中继链,则需要包含parachain-system-pallet「9」,或者如果你要发送到同级平行链,则需要包含xcmp-queue-pallet「10」。
Rust///?queues
平行链A转平行链B
为平行链A和平行链B配置ORML相关库以实现平行链之间的跨链资产转移将会用到
ORML的一些依赖库:
orml-xtokens为平行链提供跨链资产转移的方式。
orml-tokens用于查询多资产额度的模块
orml-currencies可以使用currencies模块实现链内的多资产转账,可以理解为currencyplus?。
orml-traits共享一些trait,包括BasicCurrency、MultiCurrency、Auction等trait。
orml-xcm-support?提供types、traits和implementations以支持XCM集成
最后实现的效果:
链A的Alice通过xtokens模块进行跨链资产转移将token_a转移给链B的Bob,转账成功后,链B上的Bob通过tokens模块查看token_a的余额,然后通过currencies模块将一部分的token_a转账给链B上的Alice。
进行runtime配置
为了平行链能够支持多资产转移,我们除了需要添加上面的ORML依赖库,还需要做一些定制化的配置。
链A和链B上需要实现CurrencyId和CurrencyIdConvert,一个是代币的tokenSymbol的list一个是将tokenSymbol转换成multilocation的转换器。
引入orml标准库
还需要进一步配置XcmExcuter,其中包括跨链转账时手续费的收费规则、XCM过滤器以及如何存取资产的配置
两条链都需要配置这些内容,下面我主要以链A为例。链B同理。
1.配置CurrencyId和CurrencyIdConvert
假设条件:
平行链A->TokenSymbol:AA->ParachainId:1000
平行链B->TokenSymbol:BB->ParachainId:2000
Rust##pub?enum?CurrencyId?{??//?/?Relay?chain?token.??ROC,??//?Native?TokenSymbol??AA,??//?===============================??//?1.?添加支持的代币tokenSymbol??//?===============================??BB}pub?type?Amount?=?i128;//?===============================//?2.?设置?CurrencyIdConvert,//?===============================pub?struct?CurrencyIdConvert;impl?Convert>?for?CurrencyIdConvert?{??fn?convert(id:?CurrencyId)?->?Option?{????match?id?{??????CurrencyId::ROC?=>?Some(Parent
impl?orml_currencies::Config?for?Runtime?{??type?Event?=?Event;??type?MultiCurrency?=?Tokens;??type?NativeCurrency?=?BasicCurrencyAdapter;??type?GetNativeCurrencyId?=?GetNativeCurrencyId;??type?WeightInfo?=?();}pub?struct?AccountIdToMultiLocation;impl?Convert?for?AccountIdToMultiLocation?{??fn?convert(account:?AccountId)?->?MultiLocation?{????X1(AccountId32?{?network:?NetworkId::Any,?id:?account
parameter_type_with_key!?{??pub?ParachainMinFee:?|location:?MultiLocation|?->?u128?{????#?//?false?positive????match?(location
impl?orml_xtokens::Config?for?Runtime?{??type?Event?=?Event;??type?Balance?=?Balance;??type?CurrencyId?=?CurrencyId;??type?CurrencyIdConvert?=?CurrencyIdConvert;??type?AccountIdToMultiLocation?=?AccountIdToMultiLocation;??type?SelfLocation?=?SelfLocation;??type?MinXcmFee?=?ParachainMinFee;??type?XcmExecutor?=?XcmExecutor;??type?Weigher?=?FixedWeightBounds;??type?BaseXcmWeight?=?BaseXcmWeight;??type?LocationInverter?=?LocationInverter;??type?MaxAssetsForTransfer?=?MaxAssetsForTransfer;}parameter_type_with_key!?{??pub?ExistentialDeposits:?|currency_id:?CurrencyId|?->?Balance?{????//?every?currency?has?a?zero?existential?deposit????match?currency_id?{??????_?=>?0,????}??};}parameter_types!?{??pub?ORMLMaxLocks:?u32?=?2;??pub?NativeTreasuryAccount:?AccountId?=?TreasuryPalletId::get()
impl?orml_tokens::Config?for?Runtime?{??type?Event?=?Event;??type?Balance?=?Balance;??type?Amount?=?Amount;??type?CurrencyId?=?CurrencyId;??type?WeightInfo?=?();??type?ExistentialDeposits?=?ExistentialDeposits;??//?type?OnDust?=?orml_tokens::TransferDust;??type?OnDust?=?();??type?MaxLocks?=?ORMLMaxLocks;??type?DustRemovalWhitelist?=?Nothing;}//?orml?unknown?tokensimpl?orml_unknown_tokens::Config?for?Runtime?{??type?Event?=?Event;}impl?orml_xcm::Config?for?Runtime?{??type?Event?=?Event;??type?SovereignOrigin?=?EnsureRoot;}//?=====================================//?=====================================//?=====================================//?runtime/src/lib
pub?type?Barrier?=?(??TakeWeightCredit,??AllowTopLevelPaidExecutionFrom,??AllowUnpaidExecutionFrom,??//?^^^?Parent?and?its?exec?plurality?get?free?execution??AllowUnpaidExecutionFrom,);//?==================================//?AssetTransactor?设置支持的资产类型//?==================================pub?type?LocalAssetTransactor?=?MultiCurrencyAdapter<??Currencies,??UnknownTokens,??IsNativeConcrete,??AccountId,??LocationToAccountId,??CurrencyId,??CurrencyIdConvert,??DepositToAlternative,>;//?==================================//Trader配置跨链转账手续费的收费规则,这个手续费是其他链给我们链进行跨链转账的时候,我们平行链会收取一定的手续费。//?==================================use?frame_support::{ExtrinsicBaseWeight,?WEIGHT_PER_SECOND};pub?const?MICROUNIT:?Balance?=?1_000_000;pub?const?MILLICENTS:?Balance?=?1_000?*?MICROUNIT;pub?const?CENTS:?Balance?=?1_000?*?MILLICENTS;?//?assume?this?is?worth?about?a?cent
//?======================================//?XcmConfig//?======================================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?=?MultiNativeAsset;??type?IsTeleporter?=?();?//?Teleporting?is?disabled.??type?LocationInverter?=?LocationInverter;??type?Barrier?=?Barrier;??type?Weigher?=?FixedWeightBounds;??type?Trader?=?Trader;??type?ResponseHandler?=?PolkadotXcm;??type?AssetTrap?=?PolkadotXcm;??type?AssetClaims?=?PolkadotXcm;??type?SubscriptionService?=?PolkadotXcm;}
ps:关于Trader机制的解释。
转账的手续费,一般是把转账的手续费充到国库。
需要开发者自己设置weight的比例,这个weight的意思就是一秒钟的时间消耗大概多少的手续费,这个weight其实就是时间复杂度。这里需要注意一下:如果不调整的话,大伙转账消耗的都是一个代币,但是一个ksm得几百u,一个平行链代币却是几u,这个相差就有点大,就有可能被攻击。
如果是非平行链的话,这个手续费会给验证人,但是平行链没有验证人,只能给国库。
如果Trader不指定任何账户,
类似这样子的写法,gas就相当于burn掉了。
如果是给国库,那生态的人可以通过治理模块支配国库内的额度。
如果是直接burn掉,就类似通缩模型。转的越多,代币越少。
打开Hrmp
在这里之前,请确保你链A和链B都进行了上面的配置。
我们本地需要启动4个验证人的一条中继链,然后把两条平行链注册上去
打开Hrmp通道有两种方法,一种是在中继链上直接通过sudo打开,另外一种则是在平行链上利用orml-xcm打开hrmp。
注意的是,hrmp是一个单向的通道,我们需要实现双向打通,就必须打通两次
这里以中继链上通过sudo为例,后者可以根据acala的wiki为参考:OpenHRMPChannel「11」.
在Developer/Sudo下通过parasSudoWrapper.sudoEstablishHrmpChannel来打开1000->2000和2000->1000的hrmp通道。
1.打开1000->2000
2.打开2000->1000
进行跨链资产转账
到这所有的准备工作都准备好了,我们可以进行xcm消息传递了也就是说可以进行跨链资产转移了。
1.链A向中继链转中继链代币
这里需要注意的是只能往中继链转中继链代币,因为我用的是rococo-local,所以中继链代币tokenSymbol为ROC。
2.链A向链B转中继链代币
需要注意的是这里的AccountId32需要我们将ss58的地址hex一下
转换工具:SubstrateUtilities「12」
同理也可以把CurrencyId切换成平行链代币,比如链A的nativetoken。
执行成功之后,我们可以去链B通过Developer/ChainState下的tokens模块查看余额。
总结
在实践之前需要先吃一些基础的知识,可以囫囵吞枣但是不能不去了解。
配置的时候确实牵扯到需要的配置项,不过细心的理解每个选项的含义,也能把问题修复好。
参考链接
「1」ParachainDevelopment·PolkadotWiki:
https://wiki.polkadot.network/docs/build-pdk#how-to-make-cross-chain-transfers
「2」XCM:TheCross-ConsensusMessageFormat:
https://medium.com/polkadot-network/xcm-the-cross-consensus-message-format-3b77b1373392
「3」xcm-format参考资料:
https://wiki.polkadot.network/docs/learn-crosschain#overview-of-xcm-a-format-not-a-protocol
「4」XCM不仅仅是跨链,而是"跨共识"消息格式!:
https://jishuin.proginn.com/p/763bfbd6d91c#:~:text=XCM是一种消息,表发消息的含义。
「5」Polkadot'sMessagingScheme:
https://medium.com/web3foundation/polkadots-messaging-scheme-b1ec560908b7
「6」Polkadot的跨链消息传递方案:
https://mp.weixin.qq.com/s?__biz=MzI3MzYxNzQ0Ng==&mid=2247485114&idx=1&sn=b85ed58daaa075c7c332c204b3749e20&chksm=eb21c1f3dc5648e588a01f860ae3cadd44c654270cc76a14b8b728e25a3b99ed03ccb97dc21f&scene=21
「7」Cross-ConsensusMessageFormat(XCM)·PolkadotWiki:
https://wiki.polkadot.network/docs/learn-crosschain
「8」HowcanItransferassetsusingXCM?:
https://substrate.stackexchange.com/questions/37/how-can-i-transfer-assets-using-xcm/38#38
「9」parachain-system-pallet:
https://github.com/paritytech/cumulus/tree/master/pallets/parachain-system
「10」xcmp-queue-pallet:
https://github.com/paritytech/cumulus/tree/master/pallets/xcmp-queue
「11」OpenHRMPChannel:
https://wiki.acala.network/build/development-guide/composable-chains/open-hrmp-channel
「12」SubstrateUtilities:
https://www.shawntabrizi.com/substrate-js-utilities/
XCMPartII:?
VersioningandCompatibilityhttps://medium.com/polkadot-network/xcm-part-ii-versioning-and-compatibility-b313fc257b83
XCMPartIII:
ExecutionandErrorManagement:
https://medium.com/polkadot-network/xcm-part-iii-execution-and-error-management-ceb8155dd166
PolkadotMessagingGuide-HackMD:
https://hackmd.io/S4TZc1uTQH-vxEWv-QFapg
Sub0Online:?
GettingStartedwithXCM-YourFirstCrossChainMessages:https://www.youtube.com/watch?v=5cgq5jOZx9g
PolkadotLaunchPhases:
https://wiki.polkadot.network/docs/learn-launch
Acala&KaruraWiki:
https://wiki.acala.network/
Collator·PolkadotWiki:
https://wiki.polkadot.network/docs/learn-collator
来源:金色财经
郑重声明: 本文版权归原作者所有, 转载文章仅为传播更多信息之目的, 如作者信息标记有误, 请第一时间联系我们修改或删除, 多谢。