的前两篇文章中(介绍了XCM的设计和版本结构的基础知识。 本文对其基础设计和运行模式进行深入研究。 由于XCM基于一组非常高级的虚拟机(XCVM )指令集,希望这篇文章能帮助您熟悉该机器体系结构。
XCVM是一个高级、非Turing的完整虚拟机。 它不是基于堆栈而是基于寄存器,有几个专用寄存器,其中大部分具有高度结构化的数据。 与通用处理器不同,XCVM的寄存器不能自由设定为任意值,但有严密的机制来控制其变化。 除了与本地链的状态进行交互的方法(如With draw Asset和Deposit Asset命令)之外,没有其他“内存”。 没有循环的可能性,也没有明确的分支指令。
介绍了其中两个登记册。 可以暂时持有一个以上的资产,可以通过从本地链中提取资产进行填充,也可以从另一个链等可靠的外部来源接收资产。 以及来源登记册在执行开始时,该登记册具有共识系统的位置,可能从该系统当前的XCM执行起源,突变或完全消除到一个内部位置。
在其他寄存器中,三个与异常/错误管理有关,两个与跟踪执行权重有关。 这些将在这篇文章中进行说明。
像Ethereum这样的图灵允许完全语言的系统,实际上无法从程序中直接计算最坏情况下的执行时间。 这起因于图灵的完整性。 他们通过让用户事先决定程序的执行资源来解决这个问题,在程序运行时测量它,如果超过支付的金额就会中断它。 在事务执行之前,事情可能会发生变化,从而导致权重不准确。 幸运的是,像XCVM这样的非Turing - Complete虚拟机可以避免这种测量和权重的需要。
虽然没有权重测量,但是考虑到最终得到XCVM程序的可能性比最坏情况下的权重预测要小,所以有了称为剩余权重寄存器的寄存器。 因为我们能准确预测他们会占多少权重,所以大部分命令都不会碰它。 但是,最坏的情况下的权重预测是被高估的情况,有时也能知道只有在执行时才有多少。 通过跟踪原始权重被高估的数量并从帐户中减去原始权重,链可以优化块执行时间的配额,尽管XCM消息在块执行时间中所占的权重被高估了。
写代码时,应对“异常”状况的能力很重要。 如果远程系统发生意外或实际上无法预测的情况,则只需要将报告发送回源并声明相同的内容,就需要对其进行管理。
虽然XCVM指令集不包含明确的公共分支指令,但其执行模型中确实内置了公共异常处理框架。 XVM还包含两个代码寄存器,每个代码寄存器都包含一个XCVM程序,如程序寄存器。 这两个寄存器称为附录寄存器和错误处理程序寄存器。 如果你熟悉几种流行语言的try/catch/finally异常系统,接下来要做的事情可能会提醒你很多。
如上所述,XCVM程序的执行按照上述各指令,一步一步执行。 如果按照这些命令运行到程序结束,将出现两种情况:程序结束成功或发生错误。 如果第一次执行成功,则会清除错误寄存器,并将该错误寄存器的重量添加到剩余的重量寄存器中。 附录的登记册也将被清除,其内容将被列入方案的登记册。 如果节目登记册空着,我们就停止。 否则,节目计数器将重置为零。 简单地说,放弃当前的程序和错误处理程序,开始执行附录程序(如果有)。
虽然这个功能本身并不有用,但是与发生错误时发生的情况结合起来很有用。 在此,还没有执行的指令的权重被追加到剩余的权重寄存器中。 清除“错误处理程序寄存器”,将其内容放入“程序注册器”,将“程序计数器”复位为零。 简单地说,抛出当前程序,开始执行错误处理程序。 因为没有清除附录寄存器,所以除非用错误处理程序复位,否则会在成功完成后执行。
由于结构原因,允许错误处理程序的任意“嵌套”。 如果需要,错误处理程序也可以有错误处理函数,附录可以有自己的附录。
有两个命令可以操作这些寄存器:设置备用项和设置错误处理程序。 正如您所料,一个设置了附录寄存器,另一个设置了错误处理程序寄存器。 各参数的预测权重比这些参数的权重稍大。 但是,在执行时,将被替换寄存器的XCM消息的权重追加到剩余的权重寄存器中,允许回收未使用的附录和错误处理程序的权重。
验证是否发生了
示例如下所示。
Trap会导致DepositAsset跳过最终的DepositAsset来执行错误处理程序,而1DOT (将减去执行成本后的值置于Parachain 2000的所有权之下)。 我们总是倾向于在错误处理程序的代码开头使用RefundSurplus。 因为,如果它正在运行,则所使用的预测权重(以及由此购买的权重)可能被高估了。
事实证明,只有名为Report Error的命令才能执行此操作。 它使用尚未遇到的寄存器工作。 错误寄存器。 错误寄存器是可选的类型。 可以设定或清除。 如果设定,则包含两种信息:数字索引和XCM错误类型。
其操作原理极其简单。 首先,每当一个指令发生错误,它总是被设置; 错误类型设定为该错误的类型,数值索引设定为程序计数器寄存器的值。 其次,仅在执行Clear Error命令时清除。 这个指令是绝对正确的指令之一——它决不允许自己引起错误这就是一切——设定好的时候,发生错误,清除掉的时候,你会发出相应的指令。
现在,您需要清楚地了解ReportError命令是如何工作的。 使用错误寄存器的内容创建查询响应命令,并将其发送到特定的目的地。 当然,执行前发生的错误会跳过指令。 因为执行首先跳转到Error Handler寄存器的代码,然后跳转到附录寄存器的代码。 但是,这个解决方法很简单。 将ReportError放入附录中,验证主代码是否正在运行,无论是否引起了运行错误。
让我们来看一个简单的例子。 我们将资产(1DOT )从继电器链传输到Statemint(parachain1000 ),在那里购买一些运行时间,将statemint作为储备。 我们把资产保管在Parachain 2000。 的“无错误报告”消息如下:
对于基本错误报告,请使用以下方法:
正如您所看到的,唯一的更改是引入了两个Set Appendix命令,以确保在中继链中报告Statemint和parachain 2000错误或缺失错误。 这假设中继链被设置为可以识别和处理来自Statemint和parachain 2000的查询响应消息,查询ID为42,权重限制为1000万。 令人高兴的是,这确实是电路板支持的,但超出了范围。
如果处理
XCM可以让链条完全避免这个损失。 这个机制分两个阶段工作。 首先,登记册中列出的资产即使得到批准也不会完全忘记。 如果XCVM停止时持有的登记册不为空,则会发行包含持有寄存器值这3个信息的事件。原产地登记册的原始值以及这2个信息的散列。 然后,XCM系统将这个哈希放在存储器上。 这个结构的这一部分称为资产陷阱(AssetTrap )。
这个命令的名称可能会让人想起我们遇到的其他“资金”命令,如With draw Asset和Receive Teleported Asset。 如果是那样的话,那有很好的理由。 那是。 和其他人一样,尝试将资产(由这里的资产参数赋予)放入持有登记簿。 不会像With draw Asset那样减少账户的资产余额。 无论原始登记册的价值如何,Claim Asset都在寻找这些资产的有效索赔。 为了帮助系统找到有效的索赔,可以通过票证参数提供信息。 发现有效债权时,从链条中删除该债权,并将该资产登记在持有登记簿中。
什么构成索赔完全取决于链条本身。 不同的链可能支持不同类型的声明,使用Substrate可以很容易地组合在一起。 不过,正如您所料,我们已经准备了特别声明。 当然,这是以前删除的保持注册器的内容。
因此,让我们来看看这在实践中是如何起作用的。 我们用户paracha in 2000向Statemint发送消息,在该消息中,从其主权账户提取0.01 DOT进行收费,将100个单位的自己本地令牌的储备资产转移到Statemint的主权账户可能是这样的:
假设0.01 DOT就足够了,Statemint支持Parachain 2000本地资产的链式存款,那么这个应该可以正常工作。 但是,Statemint可能还没有建立起来承认parachain 2000的原生资产。 在这种情况下,Deposit Asset不知道如何处理资产,并引发错误。 在执行了通知parachain 2000的失败附录后,我们将保留100个parachain 2000的本地资产和可能的库存帐簿中的DOT。 假设费用只剩下0.005点,剩下的0.005点。
然后,Statemint的Pallet将记录新可索赔资产的事件,包括:
将向Paracha in 2000发送以下消息:
Parachain 2000在稍后阶段,如果确定Statemint可以接受本机资产的存款,则可以通过相当简单的方法收回这100台设备。
在这种情况下,不提供使用ticket参数搜索索赔的特殊信息。 对于资产捕获索赔,这通常是件好事,但对于其他类型的索赔,可能需要。