Gavin Wood:詳解跨共識消息格式 XCM 設計原理與運轉機制

原文標題:《Gavin Wood: 跨共識消息格式 XCM》

撰文:Gavin Wood,以太坊的聯合創始人、波卡和 Parity 科技創始人

翻譯:PolkaWorld

隨著最終的 Polkadot 1.0 版本和平行鏈的臨近,跨共識消息格式(簡稱 XCM)即將發布其第一個生產就緒版本。這是對格式、其目標、工作原理的介紹,可用于實現典型的跨鏈任務。

我們從一個有趣的事實講起,XCM 是“跨共識”消息格式,而不僅僅是“跨鏈”,這種差異是該格式在最終實現的目標上的標志,該格式不僅在鏈之間交流,而且在智能合約和模塊之間,以及通過橋和分片(如 Polkadot 的 Spree)中發送各種想法,

🤟 一種格式,而不是一個協議

為了更好地理解 XCM,重要的是要了解它的邊界以及它在 Polkadot 技術堆棧中的位置。XCM 是一種消息格式,它不是消息傳遞協議。它不能用于在系統之間實際“發送”任何消息,它的作用僅在于表達接收者應該做什么,

不包括橋和合約模塊,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 鏈中,可能需要將遠程調用分派到其模塊之一以訪問專門的功能,

最重要的是,有許多我們希望支持的代幣轉移模型:我們可能只想簡單地控制遠程鏈上的帳戶,允許本地鏈在遠程鏈上擁有一個地址以接收資金并最終將其控制的資金轉移到該遠程鏈上的其他賬戶中。

我們可能有兩個共識系統,它們都是特定代幣的“本地家園”。想象一下像 USDT 或 USDC 這樣的代幣,它在幾個不同的鏈上都有實例,并且完全可以互換,應該可以在一條鏈上銷毀這樣的代幣,并在另一條支持的鏈上鑄造相應的代幣。在 XCM 的說法中,我們之所以稱之為傳送(teleport),是因為資產的轉移實際上是通過在一側銷毀它,并在另一側創建一個克隆來實現的。

最后,可能有兩條鏈想要提名第三條鏈,其中一條鏈上的資產可能被視為本地資產,用作該資產的儲備。每個鏈上資產的衍生形式將得到完全支持,允許衍生資產交換為支持它的儲備鏈上的基礎資產,這可能是兩條鏈不一定相互信任的情況,但(至少就相關資產而言)愿意信任資產的本地鏈。這里的一個例子是我們有幾個社區平行鏈想要在彼此之間發送 DOT。它們每個都有一個本地形式的 DOT,由 Statemint 鏈(DOT 的本地中心)上的平行鏈控制的 DOT 完全支持,當在鏈之間發送本地形式的 DOT 時,在后臺,“真正的”DOT 在 Statemint 上的平行鏈帳戶之間移動,

即使這種看似適度的功能水平也有相對大量的配置,它們的使用可能是可取的,并且需要一些有趣的設計來避免過度擬合。

XCM 剖析

XCM 格式的核心在于 XCVM,與某些人的看法相反,這不是(有效的)羅馬數字(盡管如果是,它可能意味著 905),事實上,這代表跨共識虛擬機。這是一臺超高級別的非圖靈完備計算機,其指令設計為與交易大致處于同一級別,

XCM 中的“消息”實際上只是一個運行在 XCVM 上的程式。它是一個或多個 XCM 指令,程式會一直執行,直到它運行到最后或遇到錯誤為止,此時它會結束(我現在有意不解釋這一點)并停止。

XCVM 包括許多 Register,以及訪問托管它的共識系統的整體狀態。指令可能會改變一個 Register,它們可能會改變共識系統的狀態,或者兩者兼而有之。

這種指令的一個例子是 TransferAsset,它用于將資產轉移到遠程系統上的某個其他地址,需要告知要轉讓哪些資產以及資產要轉讓給誰/在哪里。在 Rust 中,它是這樣聲明的:

enum Instruction {

TransferAsset {

assets: MultiAssets,

beneficiary: MultiLocation,

}

/* snip */

}

正如你可能猜到的那樣,資產是表示要轉讓哪些資產的參數,而受益人則說明這些資產要交給誰/在哪里,當然,我們還缺少另一條資訊,即從誰/何處獲取資產,這是從原 Register自動推斷出來的,程式開始時,這個 Register 一般是根據傳輸系統(網、XCMP 或者其他什么)來設置的,以反映消息實際來自哪里,和受益人是同一類型的資訊,Origin Register 作為一個受保護的 Register 運行 —— 程式不能任意設置它,盡管有兩條指令可以用來以某種方式改變它。

使用的類型是 XCM 中非常基本的思想:資產,由 MultiAsset 表示,共識內的位置,由 MultiLocation 表示,Origin Register 是一個可選的 MultiLocation(可選,因為如果需要它可以完全清除),

📍 在 XCM 的位置

MultiLocation 類型標識存在于共識世界中的任何單個位置,這是一個相當抽象的想法,可以代表共識中存在的所有事物,從可擴展的多分片區塊鏈(如 Polkadot)一直到平行鏈上的低級 ERC-20 資產賬戶,在計算機科學術語中,它實際上只是一個全局單例數據結構,無論其大小或復雜性如何。

MultiLocation 始終表示相對于當前位置的位置。你可以把它想象成一個文件系統路徑,但是沒有辦法直接表達文件系統樹的“根”,這有一個簡單的原因:在 Polkadot 的世界中,區塊鏈可以合并到其他區塊鏈中,也可以從其他區塊鏈中分離出來。區塊鏈可以非常獨立地開始生命,并最終被提升為更大共識中的平行鏈,如果這樣做,那么 “root” 的含義將在一夜之間改變,這可能會給 XCM 消息和其他任何使用 MultiLocation 的消息帶來混亂。為了簡單起見,我們完全排除了這種可能性。

XCM 中的位置是分層的,共識中的一些地方完全封裝在共識中的其他地方。Polkadot 的平行鏈完全存在于整個 Polkadot 共識中,我們稱之為內部位置。更嚴格地說,我們可以說,只要有一個共識系統的任何變化都意味著另一個共識系統的變化,那么前一個系統是后者的內部系統。例如,Canvas 智能合約位于托管它的合約模塊的內部,比特幣中的 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),

有許多不同類型的連接點,用于以各種方式識別你可能在鏈上找到的位置,例如鍵、索引、二進制 blob 和復數描述。

💰 XCM 中的資產

在 XCM 中工作時,通常需要引用某種資產,這是因為幾乎所有現有的公共區塊鏈都依賴于一些原生數字資產來為其內部經濟和安全機制提供支柱。對于比特幣等工作量證明區塊鏈,原生資產(BTC)用于獎勵開發區塊鏈的礦工并防止雙重支出,對于 Polkadot 等權益證明區塊鏈,原生資產 (DOT) 用作一種抵押形式,網路管理員(稱為權益人)必須承擔風險才能生成有效區塊并獲得實物獎勵。

一些區塊鏈管理多種資產,例如以太坊的 ERC-20 框架允許在鏈上管理許多不同的資產。一些管理不可替代的資產,例如以太坊的 ETH,而是不可替代的 —— 獨一無二的實例;Crypto-kitties 是此類不可替代代幣或 NFT 的早期示例,

XCM 旨在能夠毫不費力地處理所有此類資產。為此,有數據類型 MultiAsset 及其關聯類型 MultiAssets、WildMultiAsset 和 MultiAssetFilter。讓我們看看 Rust 中的 MultiAsset:

struct MultiAsset {

id: AssetId,

fun: Fungibility,

}

所以有兩個字段定義了我們的資產:id 和 fun,這很好地表明了 XCM 如何處理資產。首先,必須提供整體資產身份。對于可替代資產,這只是標識資產。對于 NFT,這標識了整個資產“類別” —— 不同的資產實例可能在這個類別中。

plain

enum AssetId {

Concrete(MultiLocation),

Abstract(BinaryBlob),

}

資產身份以兩種方式之一表示;無論是具體的還是抽象的。Abstract 并沒有真正使用,但它允許通過名稱指定資產 ID,這很方便,但依賴于接收者以發送者期望的方式解釋名稱,這可能并不總是那么容易,Concrete 在一般用途中使用并使用位置來明確地識別資產。對于原生資產(例如 DOT),資產往往被識別為鑄造資產的鏈(在這種情況下是 Polkadot 中繼鏈,這將是其平行鏈的位置 .. )。主要在鏈模塊內管理的資產可以通過包括其在該模塊內的索引的位置來識別,例如,Karura 平行鏈可能指的是 Statemine 平行鏈上的資產,位置為 ../Parachain(1000)/PalletInstance(50)/GeneralIndex(42) ,

enum Fungibility {

Fungible(NonZeroAmount),

NonFungible(AssetInstance),

}

其次,它們必須是可替代的或不可替代的,如果它們是可替代的,那么應該有一些相關的非零數量,如果它們不可替代,那么應該有一些指示它們是哪個實例而不是數量,(這通常用索引表示,但 XCM 還允許使用各種其他數據類型,例如數組和二進制 blob。) 這涵蓋了 MultiAsset,但我們有時會使用其他三種相關類型,MultiAssets 就是其中之一,實際上只是意味著一組 MultiAsset 項目。然后我們有 WildMultiAsset;這是一個通配符,可用于匹配一個或多個 MultiAsset 項目,它實際上只支持兩種通配符:All(匹配所有資產)和 AllOf 匹配特定身份 (AssetId) 和可替代性的所有資產。值得注意的是,對于后者,不需要指定數量(在可替代的情況下)或實例(對于非可替代的),并且全部匹配,

最后,還有 MultiAssetFilter,這是最常用的,實際上只是 MultiAssets 和 WildMultiAsset 的組合,允許指定通配符或明確(即非通配符)資產列表。

在 Rust XCM API 中,我們提供了很多轉換,以盡可能輕松地處理這些數據類型,例如,當我們在 Polkadot 中繼鏈上時,要指定等于 100 個不可分割的 DOT 資產單位的可替代 MultiAsset(普朗克,對于那些知道的人),那么我們將使用 (Here, 100).into()。

👉 Holding Register

我們再來看看另一個 XCM 指令:WithdrawAsset,從表面上看,這有點像 TransferAsset 的前半部分:它從起源的賬戶中提取了一些資產,但這與他們有什么關系?如果他們沒有在任何地方存入,那么這肯定是一個非常無用的操作。如果我們查看它的 Rust 聲明,我們會發現更多有關其用法的線索:

WithdrawAsset(MultiAssets),

所以,這次只有一個參數(MultiAssets 類型,它規定哪些資產必須從 Origin Register 的所有權中撤出)。但是沒有指定放置資產的位置。

這些暫時持有的未動用資產稱為持有 Register。(“Holding”是因為它們處于不能無限期持續的臨時位置,“Register”是因為它有點像 CPU Register,是一個存放工作數據的地方。)有許多指令對持有寄存器進行操作。一種非常簡單的指令是 DepositAsset 指令,讓我們來看看它:

enum Instruction {

DepositAsset {

assets: MultiAssetFilter,

max_assets: u32,

beneficiary: MultiLocation,

},

/* snip */

}

啊哈!精明的讀者會發現這看起來很像 TransferAsset 指令中缺失的一半。我們有 assets 參數,該參數指定應從持有寄存器中刪除哪些資產以存放在鏈上,max_assets 讓 XCM 作者通知接收者打算存入多少獨特的資產,(這在知道 Holding Register 的內容之前計算費用時很有幫助,因為存入資產可能是一項代價高昂的操作。)最后是受益人,這與我們之前在 TransferAsset 操作中遇到的參數相同,有許多指令表示要在 Holding Register 上執行的操作,而 DepositAsset 是最簡單的指令之一。其他一些則更復雜。

🤑 XCM 中的費用支付

XCM 中的費用支付是一個相當重要的用例,Polkadot 社區中的大多數平行鏈都會要求其對話者為他們希望進行的任何操作付費,以免為 “交易垃圾” 和拒絕服務攻擊敞開大門,當鏈有充分的理由相信它們的對話者會表現良好時,也存在例外情況 —— 當 Polkadot 中繼鏈與 Polkadot Statemint 公共利益鏈通信時就是這種情況。但是,對于一般情況而言,費用是確保 XCM 消息及其傳輸協議不會被過度使用的好方法。我們來看看 XCM 消息到達 Polkadot 時如何支付費用。

正如前文提到的一樣,XCM 不包括作為一等公民的費用和費用支付:與以太坊交易模型不同,對于費用支付不是協議中不需要的東西,就必須進行規避,就像 Rust 的零成本抽象一樣,費用支付在 XCM 中沒有很大的設計開銷。

對于確實需要支付一定費用的系統,XCM 提供了使用資產購買執行資源的能力。概括來講,這包括了三個部分:

  • 首先,需要提供一些資產。
  • 其次,必須就計算時間(用 Substrate 中的說法就是 weight)交換資產,
  • 最后,XCM 操作將按照指示執行,

第一部分由提供資產的多個 XCM 指令之一管理。我們已經知道其中的一個指令了( WithdrawAsset ),但還有其他幾個我們稍后會看到,Holding Register中的所得資產當然將用于支付與執行 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 程式的總 weight,

在我們的示例中,我們假設所有 XCM 指令的 weight 為 100 萬,因此到目前為止,我們的兩個項目(WithdrawAsset 和 BuyExecution)為 200 萬,接下來還有一個,我們將只使用我們必須支付這些費用的所有 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 在鏈之間移動資產

將資產發送到另一條鏈可能是鏈間消息傳遞的最常見用例,允許一條鏈管理另一條鏈的本地資產,將允許各種衍生用例(無雙關語),最簡單的是去中心化交易所,但通常歸為去中心化金融或 De-Fi,

一般來說,資產在鏈之間移動有兩種方式,這取決于鏈之間是否信任彼此的安全性和邏輯,

✨ 傳送(Teleporting)

對于相互信任的鏈(例如在相同的整體共識和安全保護傘下的同質分片),我們可以使用 Polkadot 稱為傳送的框架,這基本上就意味著在發送方銷毀資產并在接收方鑄造它。這種國防法既簡單又高效——它只需要兩條鏈的協調,并且每一側只涉及一個動作,遺憾的是,如果接收鏈不能 100% 信任發送鏈實際銷毀它正在鑄造的資產(并且確實不鑄造超出資產約定規則的資產),那么發送鏈確實沒有根據消息鑄造資產的理由。

我們來看看 XCM 將(大部分的)1 個 DOT 從 Polkadot 中繼鏈傳送到它在 Statemint 上的主權帳戶時是什么樣的,我們假設 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 中繼鏈)在執行InitiateTeleport指令時正在創建一條全新的消息;它獲取 xcm 字段并將其放入新的 XCMReceiveTeleportedAsset中,然后將此 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 的資產標識符(Here,指的是中繼鏈本身是 DOT 的原生環境)已自動變異為它在 Statemint 上的表示: Parent.into(),即 Statemint 上下文中中繼鏈的位置。

beneficiary 也被指定為 Polkadot 中繼鏈,因此其(在 Statemint 上的)主權賬戶被記入新鑄造的 1 DOT 減去費用,XCM 可能只是輕松地為beneficiary 指定了一個帳戶或其他地方。實際上,可以使用從中繼鏈發送的后續 TransferAsset 來移動這 1 個 DOT。

🏦 準備金(Reserves)

跨鏈轉移資產的另一個方式稍微復雜一些。用到了稱為準備金(reserve)的第三方,這個名字來自銀行的準備金制度,也就是資產被 “儲備” 起來,來讓某些已發布的價值承諾具有可信度。例如,如果我們有理由相信在一條獨立的平行鏈上發行的每個 “衍生” DOT 恰好可以兌換 1 個 “真” DOT(例如 Statemint 或中繼鏈上的 DOT),那么我們就可以將平行鏈的 DOT 視為在經濟上等同于真實的 DOT ,(大多數銀行都做部分準備金銀行業務,這意味著他們保留的準備金少于面值。這種做法平時沒什么問題,但是當太多人都希望贖回,就會很快出問題。)所以,準備金是存儲 “真實” 資產的地方,出于傳輸目的,其邏輯和安全性受到發送方和接收方的信任。發送方和接收方的任何相應資產都將是衍生品,但它們將得到 100% 的 “真實” 儲備資產支持,假設平行鏈表現良好(即它沒有漏洞,并且其治理沒有決定偷走準備金跑路),這將使衍生品 DOT 與基礎儲備 DOT 的價值基本相同。儲備資產保存在儲備鏈上的發送者/接收者的主權賬戶(即由發送者或接收者鏈控制的賬戶)中,所以除非平行鏈出現問題,否則有充分的理由相信這些資產會受到很好的保護。

說回到轉賬機制,發送方將指示準備金把發送方擁有的資產(并將其用作其自己版本的相同資產的準備金)轉移到接收方的主權賬戶中,而準備金(而不是發送方!)通知接收方他們的新資產。這意味著發送方和接收方不需要信任彼此的邏輯或安全性,而只需信任用作準備金的鏈的邏輯或安全性。然而,這確實意味著三方需要協調,這增加了整體成本、時間和復雜性,

讓我們看看所需的 XCM,這次我們將從平行鏈 2000 發送 1 個 DOT 到平行鏈 2001,它在平行鏈 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(),

},

]),

},

]),

},

就像我之前說的,這會有點復雜,讓我們來看看這個過程,外部部分負責在發送方(平行鏈 2000)上提取 1 個 DOT 并撤回 Statemint(平行鏈 1000)上相應的 1 個 DOT —— 為此它使用了 InitiateReserveWithdraw ,其作用就是字面意思(開啟準備金提取),

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

InitiateReserveWithdraw {

assets: All.into(),

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

xcm: /* snip */

}

現在我們在 Statemint 的 Holding Register 中持有 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())存入平行鏈 2001 的主權賬戶,但這樣做是作為儲備資產,這意味著我們也要求 Statemint 向該接收鏈發送通知 XCM,通知它傳輸以及要對生成的衍生資產執行的一些指令,DepositReserveAsset 指令并不總是奏效;為了讓它奏效, dest 必須是一個可以在準備金鏈上合理持有資金的位置,而且也是儲備鏈可以向其發送 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*/

最后一部分定義了到達平行鏈 2001 的消息的一部分,就像啟動傳送操作一樣, 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 Reserve 中,然后我們將它們存入接收鏈上的發送者主權賬戶中,🎉

🏁 結論

以上就是本文的內容,希望它有助于解釋 XCM 是什么,以及它是如何設計以運轉的基礎知識,在下一篇文章中,我們將深入研究 XCVM 的架構、其執行模型及其錯誤處理、XCM 的版本控制系統;如何在連接良好的、相互依賴的生態系統中管理格式升級;其查詢-響應系統;以及 XCM 在 Substrate 中的工作原理,我們還將討論 XCM 的一些未來發展方向、計劃的功能以及發展它的過程。

原文鏈接:medium.com

0 条回复 A文章作者 M管理員
    暫無討論,說說你的看法吧