Move誕生於2018年Libra項目的早期階段--Mysten的兩位創始人(Evan和我)也是Libra的創始團隊。在我們決定創建一種新的語言之前,早期的Libra團隊密集地研究了現有的智能合約用例和語言,以了解開發人員想要做什麼,以及現有語言在哪些方面沒有提供。我們發現的關鍵問題是,智能合約都是關於資產和訪問控制的,然而早期的智能合約語言缺乏對這兩者的類型/價值表示。我們的假設是,如果我們為這些關鍵概念提供一流的抽象,我們就可以大大改善智能合約的安全性和智能合約程序員的生產力--擁有正確的詞彙來完成手頭的任務,就可以改變一切。多年來,許多人對Move的設計和實施做出了貢獻,因為該語言從一個關鍵的想法演變成一個平台無關的智能合約語言,其大膽目標是成為"web3的JavaScript"。
今天,我們很高興地宣布Move與Sui整合的一個里程碑。 Sui Move的功能是完整的,由先進的工具支持,並有大量的文檔和例子,包括如下幾部分:
- 關於使用Sui Move對象編程的系列教程
- 一本關於Sui Move基礎知識、設計模式和样本的開發文檔
- 由Mysten Move團隊開發的VSCode增強插件,支持代碼解析和錯誤診斷,
- 將Move的構建、測試、包管理、文檔生成以及Move驗證器與sui CLI整合在一起
Move的獨特之處
Move是一種跨平台的嵌入式語言。核心語法本身非常簡單:它有通用的概念,如structs(結構體), integers(整型), and addresses(地址),但它沒有區塊鏈特有的概念,如accounts(賬戶)、transactions(交易)、time、cryptography等。這些功能必須由整合Move的區塊鏈平台提供。重要的是,這些區塊鏈不需要自己的Move分叉--每個平台都使用相同的Move虛擬機、字節碼驗證器、編譯器、驗證器、包管理器和CLI,但通過建立在這些核心組件之上的代碼來增加區塊鏈的特定功能。 Diem是第一個嵌入Move的區塊鏈,隨後基於Move的區塊鏈(包括0L、StarCoin和Aptos)大多采用了Diem風格的方法。儘管Diem風格的Move有一些很好的品質,但Diem的許可性質和Diem區塊鏈的某些實現細節(特別是存儲模型)都使得一些基本的智能合約用例難以實現。特別是,Move和Diem的原始設計早於NFT的流行爆炸,並且有一些怪癖,使NFT相關用例的實施特別棘手。在這篇文章中,我們將通過三個這樣的例子,展示原始Diem風格的Move嵌入的問題,並描述我們如何在Sui Move中解決這個問題。我們假定對Move有一些基本的了解,但希望這些關鍵點對任何有編程背景的人來說都是可以理解的。
大規模創建asset時的絲滑體驗
批量創建和分發資產的能力對於入職和吸引web3用戶都是至關重要的。也許一個Twitch流媒體人想要分發紀念性的NFT,一個創造者想要為一個特別的活動發送門票,或者一個遊戲開發者想要向所有的玩家空投新的物品。這裡是一個(失敗的)嘗試,為Diem-style Move中的資產大規模造幣編寫代碼。這段代碼將一個接收者地址的向量作為輸入,為每個接收者生成一個asset,並嘗試轉移資產。
在Diem-style Move中,全局存儲是由(地址,類型名稱)對鍵入的--也就是說,每個地址最多可以存儲一個特定類型的資產。因此,move_to(receiverient, CoolAsset { ...}試圖通過將CoolAsset存儲在接收者的地址下來轉移它。然而,這段代碼在move_to(receiverient, ...)這一行會編譯失敗。關鍵的問題是,在Diem-style Move中,你不能發送一個CoolAsset類型的值到一個地址A,除非。一個非A的地址發送一個交易,在A創建一個賬戶A的所有者發送了一個事務,明確選擇接收CoolAsset類型的對象。這是兩個交易,只是為了接收一個資產!這樣做的決定對Diem來說是有意義的,它是一個許可系統,需要仔細限制賬戶的創建,並防止賬戶因存儲系統的限制而持有過多的資產。但是,對於一個想要使用資產分配作為入職機制的開放系統,或者只是一般地允許資產在用戶之間自由流動,就像他們在以太坊和類似的區塊鏈上所做的那樣,這是非常有限的。
而在Sui Move中實現相同功能代碼代碼如下:
Sui Move的全局存儲以對象ID為鍵。每個具有鍵值對的的結構都是一個"Sui對象",它必須有一個全局唯一的id字段。 Sui Move引入了一個可以在任何Sui對像上使用的transfer原語,而不是使用限制性的move_to結構。在底層,這個基元將id映射到全局存儲中的CoolAsset,並添加元數據以表明該值為接收方所擁有。 mass_mint的Sui版本的一個有趣的屬性是,它與所有其他交易(包括調用mass_mint的其他交易!)進行交換。 Sui運行時將注意到這一點,並通過不需要共識的拜占庭一致廣播"快速路徑"發送調用該函數的事務。這樣的事務既可以被提交,也可以被並行執行。這不需要程序員做任何努力(他們只需寫下上面的代碼,其餘的由runtime來處理。)也許很微妙的是,這段代碼的Diem變體並非如此--即使上面的代碼有效,exists和guid::create的調用都會與其他生成GUID或觸及賬戶資源的事務產生爭論點。在某些情況下,有可能重寫Diem風格的Move代碼以避免爭論點,但許多寫Diem風格Move的習慣性方法會引入小阻礙,使並行執行時受阻。
本地資產所有權和轉讓
讓我們用一個可以實際編譯和運行的變通方法來擴展Diem風格的Move代碼。做到這一點的習慣方法是"wrapper pattern(包裝器模式)":因為Bob不能直接將CoolAsset移動到Alice的地址,我們要求Alice "選擇"接收CoolAsset,首先發布一個包裝器類型CoolAssetStore,裡面有一個集合類型(表)。愛麗絲可以通過調用opt_in函數來做到這一點。然後,我們添加代碼,允許Bob將CoolAsset從他的CoolAssetStore移到Alice的CoolAssetStore。在這段代碼中,讓我們添加一個其他的問題:我們將只允許CoolAsset的轉移,如果它們被創建後至少有30天。這種政策對於那些(例如)想要阻止投機者購買/炒作活動門票的創作者來說是很重要的,這樣真正的粉絲就更容易以合理的價格獲得這些門票。
這段代碼是有效的。但這是一種相當複雜的方式來完成將資產從Alice轉移到Bob的任務!再看一下Sui Move的另外一種實現方式
這段代碼要短得多。這裡需要注意的關鍵是,cool_transfer是一個入口函數(意味著它可以被Sui運行時通過事務直接調用),然而它有一個CoolAsset類型的參數作為輸入。這又是Sui運行時的神奇之處一個事務包括它想操作的一組對象ID,而Sui Runtime時:
- 將ID解析為對象值(不需要上面Diem風格的代碼中的borrow_global_mut和table_remove部分)。
- 檢查該對像是否為交易的發送者所擁有(消除了對上述signer::address_of部分和相關代碼的需要)。這一部分特別有意思,我們很快就會解釋:在Sui中,安全的對象所有權檢查是運行時的一部分
- 根據被調用函數cool_transfer的參數類型檢查對象值的類型
- 將對象值和其他參數綁定到cool_transfer的參數上,並調用該函數
這使得Sui Move的程序員能夠跳過邏輯中"提款"部分的模板,直接跳到有趣的部分:檢查30天的到期政策。同樣地,"存款"部分也通過上文解釋的Sui Move轉賬結構得到了極大的簡化。最後,沒有必要像CoolAssetStore那樣引入一個具有內部集合的封裝類型--以id為索引的Sui全局存儲允許一個地址存儲任意數量的具有給定類型的值。另一個需要指出的區別是,Diem風格的cool_transfer有5種方式可以中止(即失敗並在沒有完成轉移的情況下向用戶收取汽油費),而Sui Move cool_transfer只有一種方式可以中止:當違反了30天的政策。將對象所有權檢查卸載到運行時是一個很大的成功,不僅在人機工程學方面,而且在安全性方面。在運行時層面上的安全實現可以防止在構造上實現這些檢查(或完全忘記它們!)的錯誤。最後,注意到Sui Move的入口點函數簽名cool_transfer( asset: CoolAsset, ...)給了我們很多關於這個函數要做什麼的信息(與Diem風格的函數簽名相比,它更加不透明)。我們可以認為這個函數是在請求轉移CoolAsset的權限,而另一個函數f(asset: &mut CoolAsset, ...)是在請求寫入(但不是轉移)CoolAsset的權限,而g(asset: &CoolAsset, . ..)只是在請求讀取權限。
因為這些信息可以直接在函數簽名中獲得(不需要執行或靜態分析!),它可以直接被錢包和其他客戶端工具使用。在Sui錢包中,我們正在研究人類可讀的簽名請求,利用這些結構化的函數簽名,向用戶提供iOS/Android風格的權限提示。錢包可以這樣說:"此交易要求允許讀取你的CoolAsset,寫入你的AssetCollection,並轉移你的ConcertTicket。繼續嗎?"。
人類可讀的簽名請求解決了許多現有平台(包括使用Diem-style Move!的平台)上存在的大規模攻擊載體,即錢包用戶必須盲目地簽署交易而不了解其可能產生的影響。我們認為使錢包體驗不那麼危險是促進加密貨幣錢包主流採用的關鍵步驟,並通過啟用人們可讀簽名請求等功能來設計Sui Move以支持這一目標。
捆綁不同的資產
最後,讓我們考慮一個關於捆綁不同類型的資產的例子。這是一個相當常見的用例:程序員可能想把不同類型的NFT打包成一個集合,把物品捆綁在一起在市場上出售,或者給現有的物品添加附件。假設我們有以下情況:
- Alice定義了一個在遊戲中使用的角色對象
- Alice希望支持用後來創建的不同類型的第三方配飾來裝飾她的角色。
- 任何人都應該能夠創建一個配件,但是一個角色的所有者應該決定是否添加一個配飾。
- 轉移一個角色應該自動轉移其所有的配飾。
這一次,讓我們從Sui Move的代碼開始。我們將利用Sui運行時內置的對象所有權功能的另一個方面:一個對象可以被另一個對象所擁有。每個對像都有一個唯一的所有者,但一個父對象可以有任意數量的子對象。父/子對象關係是通過使用transfer_to_object函數創建的,它是上面介紹的transfer函數的關聯對象。
在這段代碼中,角色模塊包括一個accessorize函數,讓角色的擁有者添加一個具有任意類型的附件對像作為子對象。這允許Bob和Clarissa創建他們自己的飾品類型,具有不同的屬性和功能,這是Alice沒有的,但又建立在Alice已經完成的基礎上。例如,Bob的襯衫只有在它是角色最喜歡的顏色時才能裝備,而Clarissa的劍只有在角色足夠強大時才能揮舞。下面是在Diem-style Move 的實戰演示,但都沒有成功,也就是Diem-style的Move是不能實現上述場景的。
由此可見,在Diem-style Move中的問題如下
- 只支持同類型的集合(正如第一次測試所展示的那樣),但配飾從根本上來說不是一類
- 對象之間的關聯只能通過"wrapping(包裝)"(即把一個對象存儲在另一個對像中)來創建;但可以被包裝的對象集合必須預先定義(如第二次嘗試),或者以一種臨時的方式添加,不支持附加對象組成(像第三次測試的那樣)。
總結
Sui是第一個在如何使用Move方面與最初的Diem設計大相徑庭的平台。設計能充分利用Move和平台獨特功能結合既是一門藝術,也是一門科學,需要對Move語言和底層區塊鏈的能力有深刻的理解。我們對Sui Move所取得的進展和它將啟用的新用例感到非常興奮! "。[1] 支持Diem式的Move政策的另一個論點是,"必須選擇加入對應的資產類型後,才能接收特定類型的資產",這是一個很好的防止垃圾郵件的機制。然而,我們認為垃圾郵件的預防屬於應用層。與其要求用戶發送花費真金白銀的交易來選擇接收資產,不如在(例如)錢包層面用豐富的用戶定義的政策和自動垃圾郵件過濾器來輕鬆解決垃圾郵件問題。