Sui 與 Aptos 都屬於 Move 語系,而他們兩者技術方面有什麼不同?本文源自 Shark Team 團隊的研究文章《Sui 與 Aptos 技術實現對比》,由 DeFi之道 整理。
(前情提要: Sui推出「永久」測試網,將持續運作、不再重置,預告Q2上線主網)
(背景補充: Move系公鏈|Sui預告Q2上線主網,如何埋伏空投、技術創新?)
近期,隨著 Sui 主網即將上線,圍繞 Aptos 和 Sui 的討論也逐漸增加,社群也非常活躍,大家都在討論 Aptos 和 Sui 的異同。其實公鏈技術並沒有絕對的優勢和劣勢,主要還是看與業務的適用程度以及基礎效能、安全性等。
SharkTeam 之前對 Aptos、Sui、StarCoin 等 Move 語言公鏈進行了深入研究,我們將進行一些對比和分享,這是第一期,希望對 Move 開發者選擇適合自己業務的公鏈有幫助。
1. 共識機制
Aptos 和 Sui 都是 PoS 共識模型,但是兩者細節實現有些不同。
Aptos 採用基於 BFT 的 HotStuff,在此基礎上,Aptos 開發了 Block-STM 執行引擎。Block-STM 執行引擎提高了吞吐量降低了延遲。
Sui 採用了 Narwhal 和 Tusk。Narwhal 是基於 DAG 的記憶體池模組(mempool),主要負責交易資料的可用性。Tusk 是共識模組,主要是對負責交易進行排序。
2. 帳戶模型
在以太坊中有兩個帳戶:EOA 和 合約帳戶。帳戶的本質是地址,在 Aptos 和 Sui 中,地址有所不同。
在 Aptos 中,每個帳戶是由資源和模組組成,每個帳戶可以擁有多個資源和模組。資源是儲存資料,模組是儲存程式碼。
在 Sui 中,沒有帳戶這一說法。Sui 的最小單位是物件(Object),所有建立的物件都會在 0x0 地址上。該 0x0 地址,一般是建立的包。比如,我用 sui move new learn 建立的一個專案,在 Move.toml 中
3. 能力
Core Move 提供了四種能力: Copy、Drop、Store、Key。
Copy :允許此型別的值被複制
Drop :允許此型別的值被彈出 / 丟棄
Store :允許此型別的值存在於全域性儲存的某個結構體中
Key :允許此型別作為全域性儲存中的鍵 (具有 key 能力的型別才能儲存到全域性儲存中)
在 struct 中,Copy 和 Drop 可以用於建立類似 Solidity 中 event,來獲取日誌資訊。擁有 Store 和 Key,可以被認為資源物件。
Aptos 和 Core Move 能力特性一樣。
Aptos 使用 Core Move 中的全域性儲存操作符(move_to,move_from 等)。使用全域性儲存操作符必須具有相應的 acquires 關鍵字去註釋全域性資源。
Sui 有 Sui 物件,沒有 Aptos 的 acquires 關鍵字。Sui 物件要儲存在鏈上必須要有 Key 並且 struct 中要有一個特殊的成員欄位 id,它的型別是 sui::object::UID。物件 UID 具有唯一性,它通過 object::new (&mut TxContext) 建立,並通過 object::delete (UID) 銷燬。
Sui 和 Aptos(Core Move)不同,擁有 Key 能力,並不意味著能夠全域性儲存。
在 Aptos(Core Move)中,任意 struct 被 Key 修飾後都可以作為資源儲存在帳戶中。合約在執行的時候,無論是不是被訪問帳戶,都可以通過 borrow_global 等一些全域性資源操作符去訪問。
在 Sui 中,物件是 sui -> move 中直接傳遞,不能借助全域性操作符。比如,在 Sui 中儲存物件必須通過函式 transfer::transfer (object, address) 進行儲存。但是,該函式智慧在 entry 函式中使用。因為 entry 函式是用來物件資源交易入口函式。
4. 所有權
4.1 Owned 所有權
4.2 Shared 所有權
在 Aptos(Core Move)中 Shared 的所有權主要通過建立資源帳戶,並且繫結資源帳戶,合約之間間接共享。
在 Sui 中的某些物件不能被任何人修改,這些物件可以被讀取。比如 Sui 中所有已釋出的包和模組都是不可變物件。
transfer::freeze_object(obj)
在 Sui 中還有一種共享物件可以被任何人讀取或修改,並且該共享物件交易需要通過共識協議進行全域性排序。
transfer::share_object(obj)
5.Signer 和 TxContext
在 Aptos 中,一個交易的簽名者(signer)被直接作為一個引數傳遞到從 Move 外部呼叫的函式中。
簽名者(signer)是 Move 內建的資源型別。簽名者(signer)是一種允許持有者代表特定地址(address)行使權力的能力(capability)。你可以將原生實現(native implementation)視為:
struct signer has drop { a: address }
std::signer 標準庫模組為 signer 提供了兩個實用函式:
signer 有點像 Unix UID ,因為它表示一個通過 Move 之外的程式碼(例如,通過檢查加密簽名或密碼)進行身份驗證的使用者。
在 Sui 中,TxContext 型別可以像對待 signer 一樣被宣告為一個函式的引數,並且可以使用一個庫函式從 TxContext 中獲得簽名者(signer)。此外,TxContext 還用於在 Sui Move 中建立 UID 。
6. 初始化
6.1 Aptos 初始化函式
Aptos 在 module 部署時,採用 signer 傳入 init_module。
init_module(account: &signer)
6.2 Sui 初始化函式
Aptos 支援在具有類似簽名的 module 部署時呼叫的初始化函式。 Sui 將在 module 部署時呼叫使用類似簽名宣告的 init 函式。
init(&mut TxContext)
7. 安全性
7.1 Overflow
整數溢位問題,出現在 Solidity 0.8 之前版本中。Solidity 0.8 之前採用的是 SafeMath 安全庫去處理溢位問題,Solidity 0.8 之後溢位問題在語言層面不在出現,Solidity 自帶溢位處理。如果發生溢位,將會 revert。
那麼,在 Move 中是否純在溢位問題。我們簡單寫了一個測試例子。
從測試結果中可以得知,Move 在語言層面處理了溢位問題。如果發生溢位,Move 會出現 arithmetic error。
在 Solidity 0.8 之後,位運算不精確使用也會發生數值問題。
Move 中的位運算也同樣存在相同問題。
適當的使用位運算可以節省 gas,但是同時要保證精確計算,否則會發生數值問題。
7.2 訪問控制
在 Solidity 中,對於基本的訪問控制,Openzepplin 提供了一個合約安全模板 Ownable。在該合約中,帳戶的所有者可以被賦予特定的獨佔訪問許可權。
在 Move 中提供了一些 ability(key/store),通過 ability 對資源物件進行授權操作。同時,Move 中也有常用的設計模式,它允許以資源物件為中心來進行適當的訪問控制。這種設計模式類似於有一個相應許可權的 “帽子”(Cap),我將一個 struct 賦予 key 能力但是不賦予 store。如下所示:
struct AdminCap has key{}
在 Aptos(Core Move)中,Cap 的設計如下:
在 Sui 中,Cap 的設計如下:
在 AdminCap struct 中,Sui 和 Aptos 相比,Sui 多了 UID 型別的 id。Sui 是沒有帳戶地址的概念,只能使用 id 進行索引物件。
在 init 函式中,我們建立了一個 AdminCap 的一個副本,將其傳送到釋出者的地址,讓釋出者擁有 Cap。
在 create_and_send 函式中,傳入 AdminCap 並且立即採用_未使用變數符號對它使用。由於是引用物件,所以原來物件未變化。這時候,只有 AdminCap 擁有者才能進行呼叫執行該函式。