
本文作者:jolestar.eth(Twitter:@jolestar)
原文標(biāo)題及鏈接:為什么是 Move 之編程語言的生態(tài)構(gòu)建
作為一個(gè) Move 的鼓吹者,每次給開發(fā)者推廣 Move 的時(shí)候都會遇到這樣的問題。Move 有什么優(yōu)勢嗎?為什么是 Move?就像你給好友介紹自己的新戀人,總會遇到類似的問題。但這種問題其實(shí)不易回答,如果一條一條列舉優(yōu)缺點(diǎn),總是會有人質(zhì)疑,畢竟新語言的生態(tài)都不成熟,選擇只能基于它的潛力來判斷。我先說一個(gè)論斷:Move 是最有潛力構(gòu)建出 Solidity 這樣的生態(tài)系統(tǒng),甚至超越的智能合約編程語言。
目標(biāo)讀者:開發(fā)者以及對區(qū)塊鏈領(lǐng)域的技術(shù)感興趣的朋友。本文希望盡量以通俗的方式說明智能合約當(dāng)前遇到的難題以及 Move 的一些嘗試,盡量少用代碼,期望不懂編程語言的朋友也能大致理解,但這個(gè)很難,希望讀者給一點(diǎn)反饋。
如果把時(shí)間拖回到幾年前,新公鏈上支持圖靈完備智能合約的編程語言主要有兩種方式:
1. 一種是基于現(xiàn)有的編程語言進(jìn)行裁剪,然后運(yùn)行在 WASM 等通用的虛擬機(jī)里。這種方案的優(yōu)勢是可以沿用當(dāng)前編程語言以及 WASM 虛擬機(jī)的生態(tài)。
2. 一種是新造一個(gè)專門的智能合約編程語言,以及虛擬機(jī),從頭構(gòu)造語言以及虛擬機(jī)生態(tài)。Solidity 就是這條路線,Move 也是這條路線。
那時(shí)候大家普遍其實(shí)不太看好 Solidity&Evm 生態(tài),覺得 Solidity 除了用來發(fā) Token,貌似也沒有什么用,性能也不好,工具也孱弱,像是個(gè)玩具。很多鏈的目標(biāo)是讓開發(fā)者用已有的語言來進(jìn)行智能合約編程,覺得前一條路更被看好,很少有新公鏈直接復(fù)制 Solidity&Evm。
但經(jīng)過幾年的發(fā)展,尤其 DeFi 崛起之后,大家突然發(fā)現(xiàn) Solidity 的生態(tài)不一樣了。而走前一條路的智能合約生態(tài)反倒沒有成長起來,為什么呢?我總結(jié)有幾個(gè)原因。
1. 區(qū)塊鏈的程序運(yùn)行環(huán)境和面向操作系統(tǒng)的程序運(yùn)行環(huán)境區(qū)別很大,如果拋棄掉操作系統(tǒng)的系統(tǒng)調(diào)用,文件IO,硬件,網(wǎng)絡(luò),并發(fā)等相關(guān)的庫,再考慮鏈上的執(zhí)行成本,已有編程語言能和智能合約共享的代碼庫非常少。
2. 第一種方案理論上能支持的語言很多,但實(shí)際上帶有 Runtime 的編程語言編譯到 WASM 等虛擬機(jī)后文件會非常大,不適合區(qū)塊鏈場景使用,能用的也主要是 C, C++, Rust 等。而這幾種語言的學(xué)習(xí)門檻實(shí)際上并不比 Solidity 這種專門的智能合約編程語言的成本更低,并且同時(shí)支持多個(gè)語言可能會導(dǎo)致早期生態(tài)的割裂。
3. 各鏈的狀態(tài)處理機(jī)制不一樣,即便都用都是 WASM 虛擬機(jī),各鏈的智能合約應(yīng)用也不能直接遷移,無法共享一個(gè)共同的編程語言以及開發(fā)者生態(tài)。
對應(yīng)用開發(fā)者來說,直接面對的就是智能合約編程語言,編程語言的基礎(chǔ)庫,有沒有可復(fù)用的開源庫。DeFi 的安全性要求智能合約代碼要經(jīng)過審計(jì),而經(jīng)過審計(jì)的代碼每一行都代表著錢,大家基于已有的代碼略做修改進(jìn)行復(fù)制,就能降低審計(jì)成本。
現(xiàn)在看來 Solidity 雖然走了一個(gè)看起來慢的路,但實(shí)際上更快的構(gòu)建出了生態(tài)。現(xiàn)在很多人已經(jīng)認(rèn)為 Solidity&EVM 就是智能合約的終點(diǎn)了,很多鏈都開始兼容或者移植 Solidity&Evm。這時(shí)候,新的智能合約編程語言需要證明自己有更強(qiáng)的生態(tài)構(gòu)建能力,才能說服大家關(guān)注與投入。
那新的問題就是,一個(gè)編程語言語言,如何衡量它的生態(tài)構(gòu)建能力?
編程語言的生態(tài)構(gòu)建能力,簡單的來說就是它的代碼的復(fù)用能力,主要體現(xiàn)在兩個(gè)方面:
1. 編程語言模塊之間的依賴方式。
2. 編程語言模塊之間的組合方式。“可組合性”是智能合約標(biāo)榜的一個(gè)特性,但實(shí)際上編程語言都有組合性,我們發(fā)明的 Interface, Trait 等都是為了更方便的組合。
先說說依賴方式,編程語言實(shí)現(xiàn)實(shí)現(xiàn)依賴主要通過三個(gè)方式:
1. 通過靜態(tài)庫(Static-Libraries)的方式,在編譯期靜態(tài)鏈接,將依賴打包在同一個(gè)二進(jìn)制中。
2. 通過動態(tài)庫(Dynamic-Libraries)的方式,運(yùn)行時(shí)動態(tài)鏈接,依賴并不在二進(jìn)制中,但要預(yù)先在目標(biāo)平臺上部署。
3. 通過遠(yuǎn)程調(diào)用(RPC)在運(yùn)行期依賴。這里泛指各種可以遠(yuǎn)程調(diào)用的 API。
1,2 一般都用在基礎(chǔ)庫依賴的場景下。基礎(chǔ)庫一般是無狀態(tài)的,因?yàn)閼?yīng)用如何處理狀態(tài),比如寫哪個(gè)文件里,還是存哪個(gè)數(shù)據(jù)庫表里,基礎(chǔ)庫是很難假設(shè)。這種調(diào)用是在同一個(gè)進(jìn)程同一個(gè)方法調(diào)用的上下文里,共享調(diào)用棧,共享內(nèi)存空間,沒有安全隔離(或者說隔離很弱),需要可信環(huán)境。
3 實(shí)際上調(diào)用的是另外的進(jìn)程或者另外的機(jī)器上的進(jìn)程,互相通過消息通信,各進(jìn)程負(fù)責(zé)自己的狀態(tài),所以可以提供狀態(tài)的依賴,調(diào)用也有安全隔離。
這三種方法各有優(yōu)劣。1 在最終二進(jìn)制中包含依賴的庫,優(yōu)點(diǎn)是對目標(biāo)平臺的環(huán)境無依賴,但缺點(diǎn)是二進(jìn)制比較大,2 的優(yōu)勢是二進(jìn)制比較小,但對運(yùn)行環(huán)境有前置要求,3 可以構(gòu)建跨語言的依賴關(guān)系,一般用在跨服務(wù),跨機(jī)構(gòu)合作的場景中,為了方便開發(fā)者調(diào)用,一般通過 SDK 或者代碼生成模擬成方法調(diào)用。
技術(shù)歷史上,很多編程語言,操作系統(tǒng)平臺都花費(fèi)了很大的精力想彌合遠(yuǎn)程調(diào)用和本地調(diào)用之間的差異,想實(shí)現(xiàn)無縫的遠(yuǎn)程調(diào)用和組合。隨便舉一些著名的技術(shù)詞匯,COM(Component Object Model)/CORBA/SOAP/REST 等等,都是為了解決這些問題。雖然實(shí)現(xiàn)無縫調(diào)用組合的夢想破滅了,大家最后還是靠工程師人力拼接口,把整個(gè) Web2 的服務(wù)給拼接在一起,但夢想的火種還在。
而智能合約,給應(yīng)用間的依賴方式帶來了新變化。
傳統(tǒng)的企業(yè)應(yīng)用之間的依賴方式可以用下圖表示
1. 系統(tǒng)之間通過各種 RPC 協(xié)議把運(yùn)行在不同的機(jī)器上的服務(wù)連接在一起。
2. 機(jī)器之間有各種技術(shù)的,人工的“墻”進(jìn)行隔離,保證安全。
而智能合約的運(yùn)行環(huán)境是鏈的節(jié)點(diǎn)給構(gòu)造出的沙箱環(huán)境,多個(gè)合約程序是運(yùn)行在同一個(gè)進(jìn)程內(nèi)的不同的虛擬機(jī)沙箱中,如下圖所示:
合約之間的調(diào)用是同一個(gè)進(jìn)程內(nèi)不同的智能合約虛擬機(jī)之間的調(diào)用。
安全依賴于智能合約虛擬機(jī)之間的隔離。
我們以 Solidity 為例子,Solidity 的合約(表明為?contract?的模塊)將自己的函數(shù)聲明為?public,然后其他合約就可以直接通過這個(gè)?public?方法調(diào)用該合約。以下圖的一個(gè) RPC 調(diào)用過程為例:
圖片來源 https://docs.microsoft.com/en-us/windows/win32/rpc/how-rpc-works
鏈實(shí)際上接管了上圖中,Client 和 Server 之間通信的所有過程,自動生成 stub,實(shí)現(xiàn)序列化和反序列化,真正讓開發(fā)者感覺到遠(yuǎn)程調(diào)用就像本地方法調(diào)用一樣。
當(dāng)然,技術(shù)并沒有銀彈,沒有一勞永逸的方案,新的方案總帶來新的難題需要解決。
通過前面的分析,我們理解了智能合約之間的調(diào)用實(shí)際上是一種類似于遠(yuǎn)程調(diào)用的方法。那如果像要通過庫的方式進(jìn)行依賴調(diào)用呢?
在 Solidity 中,表明為?library?的模塊,就相當(dāng)于靜態(tài)庫,它必須是無狀態(tài)的。對?library?的依賴會在編譯期打包到最終的合約二進(jìn)制中。
這樣帶來的問題就是如果合約復(fù)雜,依賴過多,導(dǎo)致編譯后的合約過大,無法部署。但如果拆成多個(gè)合約,則又無法直接共享狀態(tài),內(nèi)部依賴變成遠(yuǎn)程服務(wù)間的依賴,增加了調(diào)用成本。
那是不是可以走第二條動態(tài)庫加載的路呢?比如 Ethereum 上的大部分合約都依賴了 SafeMath.sol 這個(gè)庫,每個(gè)合約都包含了它的二進(jìn)制,既然代碼都在鏈上了,為什么不能直接共享呢?
于是 Solidity 中提供了?delegatecall?的方法,類似于動態(tài)鏈接庫的解決方案,把另外一個(gè)合約的代碼,嵌入到當(dāng)前合約調(diào)用的上下文中執(zhí)行,讓另外一個(gè)合約直接讀寫當(dāng)前合約的狀態(tài)。但這就有兩個(gè)要求:
1. 調(diào)用和被調(diào)用方要是完全信任的關(guān)系。
2. 兩個(gè)合約的狀態(tài)要對齊。
非智能合約開發(fā)者可能不太理解這個(gè)問題,如果是 Java 開發(fā)者可以這樣理解:Solidity 的每個(gè)合約都相當(dāng)于一個(gè) Class,它部署后運(yùn)行起來是一個(gè)單例的 Object,如果想在運(yùn)行時(shí),加載另外一個(gè) Class 的方法來修改當(dāng)前 Object 里的屬性,那這兩個(gè) Class 里定義的字段必須相同,并且新加載的方法相當(dāng)于一個(gè)內(nèi)部方法,Object 的內(nèi)部屬性完全對它可見。
這樣就限制了動態(tài)鏈接的使用場景和復(fù)用程度,現(xiàn)在主要用來做內(nèi)部的合約升級。
因?yàn)樯厦娴脑颍?strong>Solidity 很難像其他編程語言一樣提供一個(gè)豐富的標(biāo)準(zhǔn)庫(stdlib),提前部署到鏈上由其他合約依賴,只能提供有限的幾個(gè)預(yù)編譯方法。
這也導(dǎo)致了 EVM 字節(jié)碼的膨脹。很多本來可以通過 Solidity 代碼從狀態(tài)中獲取的數(shù)據(jù),被迫實(shí)現(xiàn)成了通過虛擬機(jī)指令從運(yùn)行時(shí)上下文中獲取。比如區(qū)塊相關(guān)的信息本可以通過標(biāo)準(zhǔn)庫里的系統(tǒng)合約從狀態(tài)中獲取,編程語言本身不需要知道區(qū)塊相關(guān)的信息。
這個(gè)問題是所有的鏈和智能合約編程語言都會遇到的問題。傳統(tǒng)編程語言并沒有考慮同一個(gè)方法調(diào)用棧內(nèi)的安全問題(或者說考慮的比較少),搬到鏈上之后,也只能通過靜態(tài)依賴,和遠(yuǎn)程依賴的方式解決依賴關(guān)系,一般連類似于 Solidity 中的 delegatecall 方案都很難提供。
那我們?nèi)绾尾拍茏龅皆谥悄芎霞s之間實(shí)現(xiàn)類似動態(tài)庫鏈接的方式調(diào)用?合約之間的調(diào)用可以共享同一個(gè)方法調(diào)用棧,并且可以直接傳遞變量?
這樣做帶來兩個(gè)安全性方面的挑戰(zhàn):
合約的狀態(tài)的安全性要通過編程語言內(nèi)部的安全性進(jìn)行隔離,而不能依賴虛擬機(jī)進(jìn)行隔離。
跨合約的變量傳遞需要保證安全,保證不能隨意丟棄,尤其是表達(dá)資產(chǎn)類型的變量。
前面說到,智能合約實(shí)際上是把不同組織機(jī)構(gòu)的代碼放在同一個(gè)進(jìn)程中執(zhí)行,那合約的狀態(tài)(簡單理解就是合約執(zhí)行時(shí)生成的結(jié)果,需要保存起來供下次執(zhí)行的時(shí)候使用)的隔離就是必要的了,如果直接允許一個(gè)合約讀寫另外一個(gè)合約的狀態(tài),肯定帶來安全問題。
隔離方案理解起來其實(shí)也很簡單,就是給每個(gè)合約一個(gè)獨(dú)立的狀態(tài)空間。執(zhí)行智能合約的時(shí)候,將當(dāng)前智能合約的狀態(tài)空間和虛擬機(jī)綁定,這樣智能合約就只能讀取自己的狀態(tài)了。如果要讀取另外的合約,則需要前面提到的合約間的調(diào)用,實(shí)際上是在另外一個(gè)虛擬機(jī)里執(zhí)行。
但如果想要通過動態(tài)庫的方式進(jìn)行依賴的時(shí)候,這樣的隔離就不夠了。因?yàn)閷?shí)際上,另外一個(gè)合約是在當(dāng)前合約的執(zhí)行棧中運(yùn)行的,我們需要基于語言層面的隔離,而不是虛擬機(jī)的隔離。
另外,基于合約的狀態(tài)空間的隔離同時(shí)帶來的一個(gè)問題是狀態(tài)所有權(quán)的問題。這種情況下,所有的狀態(tài)都屬于合約,并沒有區(qū)分合約的公共狀態(tài)和個(gè)人的狀態(tài),給狀態(tài)計(jì)費(fèi)帶來難題,長遠(yuǎn)來看會有狀態(tài)爆炸的問題。
那如何在智能合約語言層面做狀態(tài)隔離呢?思路其實(shí)也很簡單,基于類型。
1. 利用編程語言對類型提供的可見性的約束,這個(gè)特性大多數(shù)編程語言都支持。
2. 利用編程語言對變量提供的可變性約束,許多編程語言區(qū)分引用的可變與不可變,比如 Rust。
3. 提供基于類型為 Key 的外部存儲,限制當(dāng)前模塊只能用自己定義的類型作為 Key 來讀取外部存儲。
4. 在編程語言層面對類型提供聲明?copy,?drop?的能力, 保證資產(chǎn)類的變量不可以被隨意復(fù)制和丟棄。
Move 語言就是用了以上解決方案,其中第3,4點(diǎn)是 Move 特有的。這個(gè)解決方案其實(shí)也比較容易理解,如果不能在虛擬機(jī)層面給每個(gè)智能合約程序一個(gè)單獨(dú)的狀態(tài)空間,在合約內(nèi)部做狀態(tài)隔離,基于類型是比較容易理解的方式,因?yàn)轭愋陀忻鞔_的歸屬和可見性。
這樣在 Move 中,智能合約之間的調(diào)用變成如下圖所示:
不同組織和機(jī)構(gòu)的程序,通過動態(tài)庫的方式,組合成同一個(gè)應(yīng)用運(yùn)行,共享同一個(gè)編程語言的內(nèi)存世界。組織之間不僅可以傳遞 消息,同時(shí)可以傳遞 引用 ,和 資源 。組織之間的交互規(guī)則和協(xié)議,只受編程語言的規(guī)則約束。(關(guān)于 資源 的定義后文中有描述)。
這個(gè)改變同時(shí)帶來幾個(gè)方面的變化:
1. 編程語言以及鏈可以提供一個(gè)功能豐富的基礎(chǔ)庫,提前部署到鏈上。應(yīng)用直接依賴復(fù)用并不需要在自己的二進(jìn)制中包含基礎(chǔ)庫部分。
2. 由于不同組織之間的代碼在同一個(gè)編程語言的內(nèi)存世界狀態(tài)里,可以提供更豐富和復(fù)雜的組合方式。這個(gè)話題在后面會詳述。
Move 的這種依賴方式雖然和動態(tài)庫的模式類似,但它同時(shí)利用了鏈的狀態(tài)托管的特性,給編程語言帶來了一種新的依賴模式。
這種模式下,鏈既是智能合約的運(yùn)行環(huán)境,同時(shí)也是智能合約程序的二進(jìn)制倉庫。開發(fā)者通過依賴將鏈上的智能合約自由組合起來提供一個(gè)新的智能合約程序,并且這種依賴關(guān)系是鏈上可追蹤的。
當(dāng)然 Move 現(xiàn)在還很早期,這種依賴方式提供的能力尚未充分發(fā)揮出來,不過雛形以及出現(xiàn)。可以設(shè)想,未來肯定可以出現(xiàn)基于依賴關(guān)系的激勵(lì)機(jī)制,以及基于這種激勵(lì)模式構(gòu)建出的新的開源生態(tài)。后面我們繼續(xù)談一談可“組合性”的問題。
編程語言模塊之間的可組合性是構(gòu)建編程語言生態(tài)的另外一個(gè)重要特性。可以說,正因?yàn)槟K之間有可組合性,才產(chǎn)生依賴關(guān)系,而不同的依賴方式也提供了不同的組合能力。
根據(jù)前面對依賴方式的分析,在 Solidity 生態(tài)談?wù)撝悄芎霞s的可組合性的時(shí)候,實(shí)際上主要說的是?contract?之間的組合,而不是?library?之間的組合。而我們前面也說了,?contract?之間的依賴是一種類似與遠(yuǎn)程調(diào)用的依賴,互相傳遞的實(shí)際上是消息,而不能是?引用?或者?資源。
這里用?資源(resource)?這個(gè)詞,主要是強(qiáng)調(diào)這種類型的變量在程序內(nèi)不能隨意的復(fù)制(copy)或者丟棄(drop),這是線性類型帶來的特性,這個(gè)概念在編程語言中還不普及。
線性類型來自于線性邏輯,而線性邏輯本身是為了表達(dá)經(jīng)典邏輯無法表達(dá)的資源消耗類的邏輯。比如有“牛奶”,邏輯上可以推導(dǎo)出“奶酪”,但這里沒辦法表達(dá)資源消耗,沒辦法表達(dá) X 單位的“牛奶”可以得出 Y 單位的“奶酪” 這樣的邏輯,所以才有了線性邏輯,編程語言里也有了線性類型。
編程語言中首先要處理資源就是內(nèi)存,所以線性類型的一個(gè)應(yīng)用場景就是追蹤內(nèi)存的使用,保證內(nèi)存資源被正確的回收,比如 Rust。但如果將這個(gè)特性普遍推廣,我們就可以在程序中模擬和表達(dá)任意類型的資源。
那為什么組合時(shí)能進(jìn)行資源?傳遞非常重要呢?我們先來理解一下當(dāng)前的基于 Interface 的組合方式,大多數(shù)編程語言,包括 Solidity 都是這樣的組合方式。
我們要將多個(gè)模塊組合起來,最關(guān)鍵的是約定好調(diào)用的函數(shù)以及函數(shù)的參數(shù)和返回值類型,一般叫做函數(shù)的“簽名”。我們一般用 Interface 來定義這種約束,但具體的實(shí)現(xiàn)由各方自己實(shí)現(xiàn)。
比如大家常說的 ERC20 Token,它就是一個(gè) Interface,提供以下方法:
function balanceOf(address _owner) public view returns (uint256 balance)function transfer(address _to, uint256 _value) public returns (bool success)
這個(gè)接口的定義中,有給某個(gè)地址轉(zhuǎn)帳的方法,也有查詢余額的方法,但沒有直接提款(withdraw)的方法。因?yàn)樵?Solidity 中,Token 是一個(gè)服務(wù),而不是一種類型。下面是 Move 中定義的類似的方法:
可以看出,Token 是一種類型,可以從賬號 withdraw 出來一個(gè) Token 對象。有人要問,這樣做有什么意義呢?
我們可以通過一種比較通俗的類比來比較二者的組合方式的區(qū)別。Token 對象類似于生活中的現(xiàn)金,你想去一個(gè)商場購買東西,有兩種支付方式:
1. 商場和銀行對接好接口,接入電子支付系統(tǒng),你支付的時(shí)候直接發(fā)起請求讓銀行劃賬給商場。
2. 你從銀行取出現(xiàn)金,直接在商場支付。這種情況,商場并不需要提前和銀行對接接口,只要接受這種現(xiàn)金類型就行。至于接收現(xiàn)金后,商場是將現(xiàn)金鎖在保險(xiǎn)柜里,還是繼續(xù)存到銀行中,這個(gè)由商場自己解決。
而后一種組合類型,可以稱做基于資源類型的組合方式,我們可以把這種在不同組織的合約之間流動的資源叫做“自由狀態(tài)”。
基于自由狀態(tài)的組合方式,更像是物理世界中的組合方式。比如光碟和播放機(jī),各種機(jī)器的配件。這種組合方式和基于接口的組合方式也并不沖突。比如多個(gè)交易所(swap)想對外提供統(tǒng)一的接口,方便第三方集成,則使用接口的組合方式更合適。
基于自由狀態(tài)的組合的關(guān)鍵優(yōu)勢有兩個(gè):
可以有效的降低基于接口組合的嵌套深度,對這個(gè)感興趣的朋友可以參看以前我一次分享中關(guān)于閃電貸的例子。考慮到有的讀者對閃電貸背景不清楚,這里就不詳述里。
可以明確的將資源的定義和基于資源的行為拆分開來,這里有一個(gè)典型的例子是靈魂綁定的 NFT。
靈魂綁定的 NFT 這個(gè)概念是 Vitalik 提出的,想用 NFT 來表達(dá)一種身份關(guān)系,而這種關(guān)系不應(yīng)該是可以轉(zhuǎn)讓的,比如畢業(yè)證,榮譽(yù)證書等。
而 ETH 上的 NFT 標(biāo)準(zhǔn),都是一個(gè)接口,比如 ERC721 的幾個(gè)方法:
function ownerOf(uint256 _tokenId) external view returns (address);function safeTransferFrom(address _from, address _to, uint256 _tokenId) external payable;
如果想擴(kuò)展新的行為,比如綁定,就需要定義新的接口。還會影響舊的方法,比如轉(zhuǎn)讓 NFT 的時(shí)候,如果 NFT 已經(jīng)靈魂綁定了,就無法轉(zhuǎn)讓,勢必帶來兼容性問題。更難的是開始允許轉(zhuǎn)讓流通,但綁定后就無法流通的場景,比如部分游戲道具。
但如果我們把 NFT 設(shè)想成一個(gè)物品,這個(gè)物品本身只決定了它如何展示,有哪些屬性,至于能否轉(zhuǎn)讓,這個(gè)應(yīng)該是上層的封裝。
比如下面是用 Move 定義的 NFT,它是一種類型。
然后我們可以把上層封裝設(shè)想成不同容器,不同的容器有不同的行為。比如 NFT 放在個(gè)人展覽館里的時(shí)候,是可以拿出來的,但一旦放一些特殊容器中,想要拿出來則需要有其他規(guī)則限制,這就實(shí)現(xiàn)了“綁定”。
比如 Starcoin 的 NFT 標(biāo)準(zhǔn)實(shí)現(xiàn)了一種靈魂綁定 NFT 的容器叫做?IdentifierNFT?:
/// IdentifierNFT 中包含了一個(gè) Option 的 NFT,默認(rèn)是空的,相當(dāng)于一個(gè)可以容納 NFT 的箱子struct IdentifierNFT has key {
nft: Option>,}/// 用戶通過 Accept 方法初始化一個(gè)空的 IdentifierNFT 在自己的賬號下public fun accept(sender: &signer);/// 開發(fā)者通過 MintCapability 給 receiver 授予該 nft,將 nft 嵌入到 IdentifierNFT 中public fun grant_to(_cap: &mut MintCapability, receiver: address, nft: NFT);/// 開發(fā)者也可以通過 BurnCapability 將 `owner` IdentifierNFT 中的 NFT 取出來public fun revoke(_cap: &mut BurnCapability, owner: address): NFT;
這個(gè)箱子里的 NFT,只有 NFT 的發(fā)行方可以授予或者收回,用戶自己只能決定是否接受,比如畢業(yè)證書,學(xué)校可以頒發(fā)和收回。當(dāng)然開發(fā)者也可以實(shí)現(xiàn)其他規(guī)則的容器,但 NFT 標(biāo)準(zhǔn)是統(tǒng)一的。對這個(gè)具體實(shí)現(xiàn)感興趣的朋友,可以參看文末鏈接。
這段闡述了 Move 基于線性類型帶來的一種新的組合方式。當(dāng)然,只有語言的特性優(yōu)勢并不能自然帶來編程語言的生態(tài),還必須有應(yīng)用場景。我們繼續(xù)來討論 Move 語言的應(yīng)用場景擴(kuò)展。
Move 最初作為 Libra 鏈的智能合約編程語言,設(shè)計(jì)之處就考慮到了不同的應(yīng)用場景。當(dāng)時(shí) Starcoin 正好在設(shè)計(jì)中,考慮到它的特性正好符合 Starcoin 追求的目標(biāo),就將其應(yīng)用在公鏈場景里。再后來 Libra 項(xiàng)目擱淺,又孵化出幾個(gè)公鏈項(xiàng)目,在幾個(gè)不同的方向上探索:
- MystenLabs 的 Sui 引入了不可變狀態(tài),試圖在 Move 中實(shí)現(xiàn)類似 UTXO 的編程模型。
- Aptos 在探索 Layer1 上的交易的并行執(zhí)行,以及高性能。
- Pontem 試圖將 Move 帶入 Polkadot 生態(tài)。
- Starcoin 在探索 Layer2 乃至 Layer3 的分層擴(kuò)展模式。
同時(shí) Meta(Facebook)的原 Move 團(tuán)隊(duì)在嘗試將 Move 運(yùn)行在 Evm 之上,雖然會損失合約之間的傳遞資源的特性,但有助于 Move 生態(tài)的擴(kuò)展以及 Move 生態(tài)和 Solidity 生態(tài)的融合。
當(dāng)前 Move 項(xiàng)目已經(jīng)獨(dú)立出來,作為一個(gè)完全社區(qū)化的編程語言。現(xiàn)在面臨幾個(gè)挑戰(zhàn):
1. 如何在不同的鏈的需求之間尋找最大公約數(shù)?保證語言的通用性。
2. 如何讓不同的鏈實(shí)現(xiàn)自己的特殊語言擴(kuò)展?
3. 如何在多個(gè)鏈之間共享基礎(chǔ)庫和應(yīng)用生態(tài)?
這幾個(gè)挑戰(zhàn)同時(shí)也是機(jī)遇,它們之間是沖突的,需要有取舍,需要在發(fā)展中尋找一種平衡,還沒有一種語言做過這種嘗試。這種平衡可以保證 Move 有可能探索更多的應(yīng)用場景,而不僅僅是和區(qū)塊鏈綁定。
這點(diǎn)上,Solidity 通過指令和鏈交互帶來的一個(gè)問題是 Solidity&EVM 生態(tài)完全和鏈的綁定了,運(yùn)行就需要模擬一個(gè)鏈的環(huán)境。這限制了 Solidity 拓展到其他場景。
關(guān)于智能合約編程語言的未來,有許多不同的看法,大體上有四種:
1. 不需要圖靈完備的智能合約語言,Bitcoin 的那種 script 就夠用了。沒有圖靈完備的智能合約,就很難實(shí)現(xiàn)通用的仲裁能力,會局限住鏈的應(yīng)用場景。這點(diǎn)可以看我以前的一篇文章《開啟比特幣智能合約的「三把鎖」》。
2. 不需要專門的智能合約語言,用已有的編程語言就夠了,這個(gè)觀點(diǎn)我們上面已經(jīng)分析了。
3. 需要一種圖靈完備的智能合約語言,但應(yīng)用場景也僅僅在鏈上,類似于數(shù)據(jù)庫中的存儲過程腳本。這是大多數(shù)當(dāng)前智能合約開發(fā)者的觀點(diǎn)。
4. 智能合約編程語言會推廣到其他場景,最終變?yōu)橐环N通用的編程語言。
最后一種可以稱做智能合約語言最大化主義者,我個(gè)人持這種觀點(diǎn)。理由也很簡單,在 Web3 世界里,無論是游戲還是其他應(yīng)用,如果遇到爭議,需要有一種數(shù)字化的爭議仲裁方案。而區(qū)塊鏈和智能合約關(guān)鍵的技術(shù)點(diǎn)就是關(guān)于狀態(tài)和計(jì)算的證明,當(dāng)前這個(gè)領(lǐng)域摸索出來的仲裁機(jī)制,完全可以使用到更通用的場景中去。當(dāng)用戶安裝一個(gè)應(yīng)用,擔(dān)心應(yīng)用不安全,希望應(yīng)用能提供狀態(tài)和計(jì)算證明的時(shí)候,也就是應(yīng)用開發(fā)必須要選擇用智能合約實(shí)現(xiàn)應(yīng)用核心邏輯的時(shí)候。
這篇從鏈上智能合約的實(shí)現(xiàn)途徑上,以及當(dāng)前智能合約在依賴和組合性上遇到的難題,用盡可能通俗的語言闡述了 Move 在這個(gè)方向上做的嘗試,以及基于這些嘗試帶來的生態(tài)構(gòu)建的可能性。
考慮到文章也比較長了,很多方面還沒表述到,我會基于這個(gè)題目寫一個(gè)系列,這里做個(gè)預(yù)告:
為什么是 Move 之生態(tài)構(gòu)建能力
這是本文。
為什么是 Move 之智能合約的安全
智能合約的安全是一個(gè)廣泛關(guān)注的問題,布道 Move 的文章也喜歡提“安全”這個(gè)特性。但如何比較不同的編程語言之間的安全性?有句俗話說,你不能阻止一個(gè)人向自己的腳開槍,編程語言是一個(gè)工具,開發(fā)者用這個(gè)工具向自己的腳開槍的時(shí)候,編程語言本身能做些什么事情?智能合約讓不通組織的程序運(yùn)行在同一個(gè)進(jìn)程中,最大化了編程語言的作用,但也帶來了新的安全挑戰(zhàn)。這篇文章將從一個(gè)整體的視角去討論這個(gè)問題。
為什么是 Move 之狀態(tài)爆炸與分層
Move 在編程語言內(nèi)部實(shí)現(xiàn)了狀態(tài)隔離,同時(shí)也給這個(gè)領(lǐng)域的解決方案提供了更多的可能性。合約可以更自由的處理狀態(tài)的存儲位置,比如將狀態(tài)存儲在用戶自己的狀態(tài)空間,這樣更利于實(shí)現(xiàn)狀態(tài)計(jì)費(fèi),激勵(lì)用戶釋放空間。比如是否可以真正實(shí)現(xiàn)狀態(tài)在不同的層之間的遷移,從而將 Layer1 的狀態(tài)遷移到 Layer2 ,從而在根本上解決狀態(tài)爆炸問題?這篇文章將探討一些這個(gè)方向的可能性。
相關(guān)鏈接
1. https://github.com/move-language/move?Move 項(xiàng)目的新倉庫
2. awesome-move: Code and content from the Move community?一個(gè) Move 相關(guān)項(xiàng)目的資源集合,包括公鏈以及 Move 實(shí)現(xiàn)的庫
3. Soulbound (vitalik.ca)?Vitalik 關(guān)于 NFT 靈魂綁定的文章
4. SIP22 NFT?Starcoin 的 NFT 標(biāo)準(zhǔn),包括 IdentifierNFT 的說明
5. 開啟比特幣智能合約的「三把鎖」 (jolestar.com)