Gavin Wood: XCM 第二部分- 版本控制和兼容性

在關(guān)于 XCM 的第一篇文章中,介紹了它的基本架構(gòu)、目標以及如何將其用于一些簡單的用例。在這里,我們將繼續(xù)深入檢查 XCM 的一個有趣方面:。
有一個共同的語言可以解決很多交互的問題。它可以讓我們一起工作,解決沖突,記錄信息以備后用。但是,語言的有用性取決于它所能表達的概念,在一個不斷變化的世界中,一種語言必須改變和適應其概念庫,否則就有被廢棄的危險。
不幸的是,太突然地改變一種,會損害它的主要目的 —— 促進人與人之間的溝通。既然語言必須改變,就必須有辦法管理這些改變,而不讓新的形式令外行人難以理解。在這方面,一個非常有用的發(fā)明是字典,它幫助記錄和歸檔一種語言的概念調(diào)色板,以便后代能夠更好地理解歷史文本。詞典的版本可以被看作是語言的形式化“版本”。
時過境遷,但問題依然似曾相識。正如我在上一篇文章中所解釋的,XCM只不過是一種語言,盡管是非常專業(yè)的語言。這是共識系統(tǒng)相互對話的一種手段,而作為這一需求的XCM在密碼產(chǎn)業(yè),特別是 Polkadot 生態(tài)系統(tǒng)飛速發(fā)展的情況下,必須有一些方法來確保這些變化不會損害XCM的互操作性。我們現(xiàn)在需要解決的不僅僅是共識空間中的互操作性,還包括共識時間。
版本控制
既然我們希望XCM要在大量使用的同時隨時間變化,需要采取的一個非常簡單的預防措施是確保我們確定哪個版本的XCM我們在實際消息內(nèi)容之前進行通信。我們通過使用許多版本包裝器類型來做到這一點,之所以這樣命名是因為它們包裝了XCM消息或其組件的版本。在 Rust 代碼中,這看起來非常簡單:
pubenum VersionedXcm {V0(v0::Xcm),V1(v1::Xcm),V2(v2::Xcm),}
當“over the wire”(或者更確切地說,在共識系統(tǒng)之間),XCM總是放在這個版本化的容器中。這確保了那些太舊而無法解釋消息的系統(tǒng)能夠安全地接收它們,并識別出消息的格式不受它們的支持。它還允許新的系統(tǒng)識別并相應地解釋舊的消息。
不只是XCM消息是版本化的;在XCM代碼庫我們也存在多版本以及它的相關(guān)類型。這是因為當鏈的XCM邏輯升級了。如果不進行版本控制,我們可能會試圖將舊的 MultiLocation 解釋為新的,并發(fā)現(xiàn)它是不可理解的(或者更糟糕的是,可以理解但與原來的含義不同)。
兼容性與翻譯
版本控制是第一步,它確保我們能夠識別正在使用的語言版本。它不能保證我們能解釋它,當然也不能保證它是我們優(yōu)先使用的版本。這就是兼容性的作用所在。我們所說的“兼容性”是指能夠繼續(xù)用一個版本來解釋和表達自己。
如果我們希望能夠升級我們的網(wǎng)絡和XCM時間表,那么這種兼容性變得相當重要。這可以分為向后兼容和向前兼容。從根本上說,向后兼容性是升級后的系統(tǒng)在遺留世界中繼續(xù)運行的能力,向前兼容性則是遺留系統(tǒng)在升級后世界中持續(xù)運轉(zhuǎn)的能力。
在我們的例子中,我們希望兩者都有,但是有實際的限制:XCM提供了以前版本中不存在的功能,因此期望舊系統(tǒng)能夠解釋這些消息是不現(xiàn)實的。這有點像試圖把“社交媒體”這個詞翻譯成拉丁文,然后指望凱撒大帝能從表面上理解它。有些概念根本無法在上下文中表示。
同樣,發(fā)生重大的變化,XCM可能會從其概念模型中移除相關(guān)功能。這種情況較少發(fā)生,但類似于將某些古代術(shù)語翻譯成現(xiàn)代術(shù)語的問題。有趣的是,“點”的古意可能就是一個例子(過去指一種相當特殊的財政捐贈形式)。
因此,新版本的XCM的設計大多兼容舊版本和新版本,但通常XCM的這些信息在另一種語境中根本沒有意義,也不能翻譯。
實際通訊
如前所述,我們確保所有獨立存在的消息都包含版本標識符。這意味著在系統(tǒng)之間發(fā)送的消息或保存在存儲中的消息。它不包括所有的消息、位置和資產(chǎn),雖然存在一部分數(shù)據(jù),但其他數(shù)據(jù)不需要某一特定版本,因為其版本可以從它的上下文推斷。
而版本識別和 compatibility/translation對于從舊的網(wǎng)絡接收消息或向新的網(wǎng)絡發(fā)送消息很有幫助,但是,如果采用另一種方式,單獨使用會沒有效果。這是因為從升級網(wǎng)絡接收消息的遺留網(wǎng)絡本身不具備能夠?qū)⑿碌腦CM它可以解釋為某種形式 —— 確切地說,這種邏輯只存在于發(fā)送方,它的翻譯代碼能夠以遺留術(shù)語重新表示新消息。
因此,必須由發(fā)送網(wǎng)絡負責確保其發(fā)送的消息能夠被接收網(wǎng)絡解釋。具體而言,用于傳遞消息的版本不能超過XCM接收網(wǎng)絡支持的內(nèi)容。
由于這個原因, Polkadot 和 Kusama 中繼鏈、Statemint 、Statemine、Shell 和任何其他基于Substrate/Frame的鏈及其XCM引擎都保存一個遠程鏈支持的版本。每當一個XCM消息由這些鏈發(fā)送,它首先通過查詢其注冊表確定發(fā)送消息的版本。它將信息翻譯給之前的發(fā)送者和接收者,那么大多數(shù)情況下,這些將是相同的,最新發(fā)布的版本,會提供完整的功能集XCM。
這個注冊表通常由治理過程決定和升級,這有點麻煩和繁瑣,特別是隨著潛在目的地數(shù)量的增加。出于這個原因,引入了版本跟蹤。
版本協(xié)商
版本跟蹤是最后一塊XCM拼圖的故事。它的功能是刪除跟蹤XCM潛在目的地鏈的版本。相反,這個過程是自動發(fā)生的,而且是連鎖的。
本質(zhì)上它允許一個網(wǎng)絡使用XCM向另一個人查詢最新版本的XCM,并在此更改時收到通知。來自此查詢的答復允許所述網(wǎng)絡填充和維護其版本注冊表,確保以盡可能最新可理解版本的消息。
具體來說,有三個有價值的指示,在XCM:Subscribe Version ,允許一方要求另一方通知其XCM版本現(xiàn)在和它更改時;取消訂閱版本以取消該請求;以及 Query Response ,將一些信息從響應者網(wǎng)絡返回到發(fā)起網(wǎng)絡的一般方法。以下是它們在 Rust 中的樣子:
enum Instruction {SubscribeVersion {query_id: QueryId,max_response_weight: u64,},UnsubscribeVersion,/* snip */}
所以 Subscribe Version 需要兩個參數(shù)。第一個 query_id 是 Query Id 類型,它只是一個整數(shù),用于識別和區(qū)分返回的響應。全部XCM導致響應被發(fā)送的指令具有類似的手段,以確保其響應能夠被識別并相應地處理。第二個參數(shù)稱為 max _response_weight ,它是一個 Weight 值(也是一個整數(shù)),指示返回時我們應該花費的最大計算時間。與 query_id 類似,它將被放入該指令生成的任何響應消息中,并且需要確保任何權(quán)重不可預測,可變權(quán)重成本至少可以限制在執(zhí)行前的最大值。如果不這樣做,我們將無法獲得解釋應答消息所需時間的上限,因此無法安排執(zhí)行該消息。
Unsubscribe Version 作為一個指令是相當貧瘠的,主要是因為一次只允許一個版本訂閱對給定位置是活動的。這意味著取消只能通過原產(chǎn)地注冊的內(nèi)容來識別。

回答
第三個要注意的指令是 QueryResponse ,它是一個非常通用的指令,允許一個鏈回復另一個,并在這樣做時報告一些信息。這是在 Rust 中:
enum Instruction {QueryResponse {query_id: QueryId,response: Response,max_weight: u64,},/* snip */}
我們已經(jīng)知道三個參數(shù)中的兩個,因為它們是從 SubscribeVersion 中提供的值填充的。第三個稱為 response,包含我們關(guān)心的實際信息。它被放置在一個新的類型 Response 中,它本身是幾種類型的聯(lián)合,其中一種網(wǎng)絡可能希望使用它們來通知另一種網(wǎng)絡。在 Rust 中是這樣的:
pubenum Response {Null,Assets(MultiAssets),ExecutionResult(Result<(), (u32, XcmError)>),Version(XcmVersion),}
就我們目前的目的而言,只需要 Version 項,但正如我們將在以后的文章中看到的,其他項對其他上下文也有用。
執(zhí)行時間
一般來說,我們不需要 QueryResponse 指令來通過 BuyExecution 購買它們自己的執(zhí)行時間,因為(假設它們是有效的),是現(xiàn)解釋網(wǎng)絡要求首先發(fā)送它們。同樣,我們認為 SubscribeVersion 是廣義上符合發(fā)送方和接收方共同利益的東西,所以也不指望有人會付錢。在任何情況下,付款都很難計算,因為付款所產(chǎn)生的反應具有異步性和不可預測性。
自動化
而這些XCM指令允許網(wǎng)絡使用完全的鏈上邏輯來確定對話者支持的最新版本,但仍然存在何時啟動這個版本的問題。此外,一些跨協(xié)商一致的傳輸協(xié)議是不基于規(guī)定的,這將排除版本協(xié)商的可能性。
在諸如 Polkadot 中繼鏈和 Statemint 之類的 Substrate 鏈中,解決方案是當需要包裝發(fā)送消息但目標的最新版本未知時自動啟動此版本發(fā)現(xiàn)過程。這有一個小缺點,即第一個消息將在次優(yōu)級的XCM版本停留,直到收到版本響應為止。如果這是一個實際問題,那么治理可以介入,強制初始版本XCM目的地與默認值不同(通常設置為最早的XCM版本)。
代碼兼容性XCM
關(guān)于版本控制,最后一點是代碼創(chuàng)作。完全不同于 Over-the-wire 格式的XCM,代碼兼容性處理是使用 Rust 實現(xiàn)(基于 substrate )項目代碼庫必須發(fā)生的事情。XCM會隨著時間的推移而堆疊。
顯然,旨在使用不斷發(fā)展的語言來表達變化的代碼庫必須隨著時代的變化而適應。我們已經(jīng)有了 Semantic Versioning ( SemVer )系統(tǒng),它可以幫助確認在特定版本更改時可能發(fā)生的更改。這在處理 API 和 ABI 時非常有用,但在考慮整個數(shù)據(jù)格式或語言時就不那么有用了。幸運的是,XCM被設計成幾乎不需要 Sem Ver 了 。
我們知道,新版本的XCM軟件能夠在新的和舊的XCM消息之間以及它們的內(nèi)部數(shù)據(jù)類型(如位置和資產(chǎn))之間進行轉(zhuǎn)換。它可以通過將XCM語言的多個版本同時保存在XCM代碼基中來做到這一點。如果我們回顧VersionedXcm數(shù)據(jù)類型的Rust聲明(就在本文的開頭),它只不過是底層Xcm數(shù)據(jù)類型的每個特定版本的標記聯(lián)合,每個都可以在它們自己的模塊v0、v1、v2和&c中找到。
由于事務和 API 使用XCM而且它的數(shù)據(jù)類型傾向于只使用版本化的變體,這些變體同樣可以構(gòu)造新的和舊的格式,最終的結(jié)果是代碼庫可以更新為使用最新的XCM軟件(在 Rust 中,這被稱為一個 Crate)很少或根本沒有改變他們的代碼。升級XCM Crate允許網(wǎng)絡更好地與其他類似升級的網(wǎng)絡進行互操作,但升級XCM網(wǎng)絡使用的語言不需要再出現(xiàn)。
我們希望,這會成為一個強有力的激勵,促使團隊保持他們的XCM Crate更新進度,因此保持一切迭代和快速發(fā)展。
結(jié)論
希望XCM的版本系統(tǒng),以及它如何能夠被用來保持一個網(wǎng)絡的主權(quán)鏈通信可以對大家有所啟發(fā)。在下一期中,我們將更深入地探討XCM:它的執(zhí)行模型和異常管理功能。
直播預告:
今晚 7 點(9 月 16 日),PolkaWorld 邀請到了 Bifrost 的創(chuàng)始人 Lurpis 和 Zenlink 的中國區(qū)負責人郭濤加入我們的視頻號直播間「波卡世界」,一起聊聊:
如何通過 Bifrost SALP 協(xié)議釋放鎖定在 crowdloan 中的 KSM 流動性?
如何通過 Zenlink SlotVault DApp 參與 crowdloan,并獲得 ZLK 獎勵?
點擊下方 “預約” 按鈕預約直播↓
歡迎學習 Substrate:
https://substrate.dev/
關(guān)注 Substrate 進展:
https://github.com/paritytech/substrate
關(guān)注 Polkadot 進展:
https://github.com/paritytech/polkadot

更多內(nèi)容:
Polkadot 的最低質(zhì)押金額將增加到 120 DOT!
掃碼關(guān)注公眾號,回復 “1” 加入波卡群
關(guān)注 PolkaWorld
發(fā)現(xiàn) Web 3.0 時代新機遇
點個 “在看” 再走吧!
