硬核分享|Crust Network 如何玩轉 Substrate 的“黑魔法”?

在這裏插入圖片描述

Crust 實現了去中心化存儲的激勵層協議,適配包括 IPFS 在內的多種存儲層協議,並對應用層提供支持。同時 Crust
的架構也有能力對去中心化計算層提供支持,構建分佈式雲生態。

6月 18 日,Crust Show 第 3 期活動中,我們邀請了 Parity 工程師 kai chao老師,與 Crust Network CTO 子琨一起,就 Crust 核心技術相關進行了硬核的技術探討。

本期分享,從 Crust 協議組的設計與技術實現、對於無縫升級的設計與思考以及 Crust 如何利用 Runtime Interface 擴展鏈上密碼庫、對於鏈上定時器(Scheduler)的運用、Crust 鏈上身份綁定的設計與實現等 5 個方面,子琨和大家進行了詳細的講解。

在這裏插入圖片描述

由於分享內容過長,分爲上下兩篇。上一篇內容爲《Crust 核心協議棧的設計與實現》,本篇主要介紹 Crust 如何運用 Substrate。

以下爲 Crust Show 003(下篇)分享整理。

01. Substrate 是一個開源、模塊化、可擴展的區塊鏈開發框架,能簡單介紹一下爲什麼會選擇 Substrate 進行開發嗎?

子琨:首先,Substrate 是特別好的開發工具,得力於 Rust 語言的 Generic 和 Substrate 良好的設計模式,讓 Substrate 形成了別具一格的搭積木的開發模式,這使得開發者能夠很輕易的開箱即用。這也是我剛接觸 Substrate 的第一感受。

隨着對 Substrate 的深入瞭解,其很多“黑魔法”讓人眼前一亮,包括大家熟知的 Forkless Upgrade、Offchain Worker、鏈上治理,或是 Crust 運用到的 Runtime interface 和鏈上定時器等等,都讓不同種類和不同功能的協議開發變得純粹簡單。

Crust 是協議棧相對比較複雜的去中心化存儲公鏈,其鏈上鍊下複雜的交互機制,SGX 特殊的驗證機制,精巧的經濟模型設計等等都讓實現 Crust 協議難度增加。

在這之前,Crust 嘗試過 1 個多月的以太坊 +Tendermint 的開發。但從去年年底開始使用 Substrate 以來,Substrate 的種種“黑魔法”大大加速了 Crust 協議的實現,Crust 已經完成了 70% 的協議開發,今天也會跟大家分享 Crust 是如何使用這些“黑魔法”的。

02. Substrate 提供的一些組件包括底層的數據庫、點對點網絡、共識算法、交易池,以及模塊化的 Runtime,也就是狀態轉換函數。 Crust 在 Substrate 的基礎上覆用了哪些組件,又有哪些新的功能特性呢?

在當前的 Crust 代碼庫中有 5 大模塊,分別是 Staking,Payment,TEE,Market 和 Balance。其 Staking 和 Balance 模塊是複用的 Substrate 原生的組件,Crust 對原生 Staking 提供的 NPoS 以及 Phragmen Election 算法進行了修改以適配 GPoS 協議,我們對原生 Balance 模塊也進行了修改去配合延緩釋放的功能。

新的功能包括了實現 MPoW 協議的 TEE 模塊,實現去中心化存儲/檢索市場的 Market 模塊以及負責訂單支付的 Payment 模塊。其中在 Market 模塊的 Provider Slashing 機制也參考了 Staking 模塊的 Slashing,對 Slashing Span 的機制也做了部分移植。

最後,Crust 也參考了 Substrate 的很多設計模式,比如爲了解決循環引用引入的 Trait 和 Frame_support, 公共類型定義 Primitives,以及 Mock/Tests。這些都大大提升了 Crust 的代碼質量。

03. 你剛剛提到了無分叉升級,據我所知 Substrate 的一個核心優勢就是它,Crust 是怎麼使用的,以及使用過程遇到了哪些問題呢?

由於 Crust 協議組包含鏈上和鏈下兩個部分,所以無分叉升級其實也分爲鏈上和鏈下兩個部分。

首先是鏈上升級,由於 Crust 是 Base 在 Substrate 之上搭建的公鏈,所以鏈上部分的升級 Crust 直接使用了 Substrate 的 Forkless Upgrade。

在 Substrate中, Runtime 的代碼會以 Wasm 的形式存儲在鏈上,這部分是主要的鏈上邏輯,Runtime 的修改可以通過無分叉升級方式進行,非 Runtime 的代碼修改還是需要升級 Native 程序。

對此,Crust 有兩個方面的考慮,如何進行升級以及升級的限制。

首先是如何進行升級。目前 Crust 採用的方法是在 Sudo 或者議會模塊會發起一個鏈上定時器,約定好在指定塊進行一次鏈上升級,這也是官方推薦的升級方法。

其原理是通過 Scheduler,將 setCode 這個操作分攤到定時 Duration 的每個塊進行,所以不用擔心 Code 過大而超過一個塊的打包容量或者超出了 MaxWeight 的值而導致 Extrinsic 不被接受。

而對於鏈上升級的限制,官方的 Rule 是隻要不涉及到 Native 改動以及保證邏輯和存儲相匹配的條件下就都能進行鏈上升級。但對於一些細節沒有給出特別的說明,Crust 其實對涉及到的業務和可能出現的情況做了比較詳細的實驗。

這些實驗包括了:

  1. Offchain Worker 的升級
  2. 鏈上密碼庫的升級
  3. 鏈上存儲的更改
  4. DB 的升級
  5. Substrate Client 模塊的升級
  6. 鏈上參數的調整

等等都做了測試,並做出了詳細的升級說明,之後也會給出 Upgrade Red Line的報告,可以關注 Crust Github Wiki。

但總的來講,Crust 可以得力於 Substrate 提供的鏈上升級機制做到 99% 以上的升級。也會在 Maxwell 測試網中將 1% 的情況完全確定下來,讓 Hard Fork 的概率做到最低。

其次是鏈下的升級,也就是 SGX 程序的升級。這個升級的意義是在於修補一些量化程序和加解密程序的漏洞或者提升其效率,Crust 設計了一套 AB Upgrade 的機制,去解決兩個 Enclave 無法互相信任的問題。

在這裏插入圖片描述

上圖的意思是,在 Block Number=500 的時候,此時鏈上被認爲合法的是 Enclave A,那麼 Account A 綁定的 Enclave A 所提交的 Id A 以及其工作量報告,會被鏈認爲是合法的輸入。

當 Sudo/Democracy 通過 Set TEE Code 操作更改鏈上存儲狀態,將 Enclave B 認證爲合法代碼後,將會規定所有的 Enclave A 在 1000 塊後失效。

但在 500 到 1500 塊中間,會出現 A、B 同時有效的中間狀態,其是爲了讓(新)B 同步(老) A 的存儲狀態。

直到 Block Number 變爲 1500,Enclave A 提交上來的內容將被鏈認爲是無效的,簡單來講就是,Enclave A 和 Enclave B 會在升級的過程中同時存在並且進行量化存儲資源,鏈上也會允許 A、B 兩個 Enclave Code 上報的工作量。

簡單來講就是,Enclave A 和 Enclave B 會在升級的過程中同時存在並且進行量化存儲資源,鏈上也會允許 A、B 兩個 Enclave Code 上報的工作量。

但在約定期間內,節點需要完成從 A 到 B 的升級,超出約定期間,鏈上將不再接受A上報的所有信息。

這套機制有點類似於 ETH 的難度炸彈升級,利用 AB Upgrade 可以很好的規避掉去解決 A、B 互信這個無解的問題,同時可以做到用戶無感知的升級。

04. 下一個問題,你在開始的時候提到了 Runtime Interface,這其實是 Substrate 裏的一個比較複雜的技術點,請跟我們詳細介紹下吧

首先對於 Runtime Interface 的介紹比較少,原因是因爲 Substrate 本身並沒有期待大家直接使用這個 Crate,而是用構建在此基礎上的 Offchain Worker。

換句話說,Runtime Interface 是爲 Offchain Worker 打造的基礎組件。

其原理是在 Native 和 Wasm 環境中橋接一些固定的接口,通過 Wasm executo r定義的外部函數,接受從 Wasm 傳入的參數,並且在 Native 中執行任何程序,並將結果返回給 Wasm 環境。

聽起來其實和 Offchain Worker 特別像,但使用上面會比 Offchain Worker 輕量,因爲你不需要像 Offchain Worker 一樣制定一套生命週期,僅僅只需要把它當作一個函數調用就可以了。

但和 Offchain Worker一樣,Runtime Interface 的使用也需要注意不要對鏈產生副作用,因爲完全裸露沒有超時機制,Runtime Interface 更容易讓你對鏈產生副作用。

所以按照 Crust 的經驗來看,儘量不要引入很複雜的計算或者 IO 開銷,比如網絡等待等等。

Crust 對 Runtime Interface 的運用僅僅在於擴展密碼庫,這也是 MPoW 協議不能缺失的部分。包含了 CA X509 簽名算法,ECDSA P256 橢圓曲線算法和 EVP Sha256 算法。Runtime Interface 的引入的確大大減輕了 Crust 實現鏈上驗證的工作量。

05. 在 Runtime 升級時,通常可以使用鏈上定時器(Scheduler)來指定升級的區塊,那麼 Crust 也是這麼使用的嗎?

鏈上定時器(Scheduler)是 Substrate 中比較有特色的模塊,可以允許你 Arrange 一個 Task 或者函數在某個 Block Number 去執行,並且支持週期性重複執行的操作。

Substrate 提供的 Scheduler 模塊完美匹配了 Crust 的一個業務場景,就是存儲訂單金額的線性釋放,也就是用戶支付給存儲節點的金額,會在文件有效期內線性的釋放給存儲節點。

舉個例子,用戶 Alice 存取一張照片給節點 A,存儲時常爲 3 個月,一共付給 A 300 CRUs,Market 模塊會將 300 個 CRUs 拆分爲 33024600.0023 個 CRU,每 10 個塊也就是 1 分鐘,會支付給 A 0.0023 個 CRU,在 3 個月內支付完畢。

所以 Crust 在 Market 模塊引入了 Scheduler ,但是由於 Substrate 網絡對全網Scheduler 的數量有所限制(大概可容納 30-40 個左右),所以我們無法對單個訂單分配一個 Scheduler。

基於這個考慮,Crust 設計了一個鏈下結算系統,也就是利用 Substrate 特有的 Offchain Worker,讓 Scheduler 去週期性執行一個鏈下結算的系統,從鏈下提交一個 Quote 到鏈上,然後執行一個 Batch 的清算轉賬工作。

這樣的話,我們可以平均分配 10 個 Scheduler 在 1 個 era (300 個塊)的週期內實現大約 30W 筆訂單釋放。目前這個方案還沒有完全實現,所以沒有 Benchmark 和準確的測試數據,只是做了一個比較粗略的估算。

但總的來講,Scheduler 爲 Crust 的延緩釋放提供了一個簡便的思路,如果沒有鏈上定時器的話,我們可能要基於 on_initialize 或者 on_finalize 做很多事情,並且還需要自己去測算具體的 Cost。

06. 終於到我的最後一個問題了,Crust 的鏈上身份具體是如何設計和實現的呢?

在這裏插入圖片描述
Crust 的身份綁定有三層邏輯:

  1. 取得 Intel 認證和 TEE Enclave Code(環境可靠:爲了保證可信運行環境),環境可靠是爲了保證沒有惡意的人修改 Enclave Code 並保證 Enclave 運行的環境是可信的。

  2. 綁定 TEE Enclave Code 和生成的公鑰(輸出可靠:爲了保證運行環境和TEE身份的匹配)。

由於 Enclave 之外的所有行爲,用戶都可以控制和修改,所以必須在 Enclave 內部生成用戶的公私鑰(私鑰只在 Enclave 內部才能獲取),並且對所有 Enclave 的輸出進行私鑰加密。

這使得用戶無法修改從 Enclave 中輸出的所有內容,保證了輸出的可靠性。

  1. 綁定生成的公鑰和鏈上身份(鏈上身份可靠:爲了保證 TEE 身份和鏈上身份的匹配),避免女巫攻擊,多個鏈上身份綁定一個 TEE。

這樣會導致 TEE 身份的盜用,所以這一步會在 TEE 內部生成鏈上身份的綁定信息,並且在鏈上進行唯一性確認。

通過這三層綁定,能夠保證 Enclave 到 Chain 的全鏈路可信,爲 MPoW 提供了可信基礎。

在這裏插入圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章