Libra的Move編程語言究竟是個啥? 美女程序員通讀26頁的白皮書後, 找出了這些精華… | 技術頭條...

640?wx_fmt=jpeg

做者 | Lee Ting Ting程序員

編譯 | Guoxi
web

責編 | Aholiab
編程

出品 | 區塊鏈大本營(blockchain_camp)安全



自去年礦難以來,業界充滿了對區塊鏈唱衰的聲音,鏈圈有不少人都開始對區塊鏈的價值產生懷疑。而 Facebook 不斷爆出的區塊鏈項目的消息可謂是給鏈圈打了一劑強心針,盼望着,盼望着,今年 6 月,Facebook 發佈了加密貨幣 Libra 的白皮書並上線了官網。能夠預見, Libra 離落地不遠了。數據結構

 

Libra 以非營利組織的形式管理,其創始成員包括大名鼎鼎的銀行卡巨頭 Visa ,萬事達,以及傳統在線支付巨頭 PayPal ,很有挑戰當下全球金融貨幣體系的趨勢。併發

 

Libra最近愈來愈火。很多開發人員已經開始跟進 Libra 項目,但願在這個全球性的區塊鏈項目中搶佔先機。而 Libra 的編程語言 Move 則是開發人員眼中的重中之重app


爲了幫助開發人員作好入門工做,加州大學伯克利分校區塊鏈實驗室研究學者,Turing Chain 聯合創始人兼首席技術官 Lee Ting Ting 從開發人員的角度分析了 Move 語言的典型特徵以及它與以太坊 Solidity 的異同,爲咱們帶來了這篇 Move 語言的入門指南。less

Move語言的白皮書長達26頁,本篇文章是對該白皮書的精華介紹,文中也會直接放出一些白皮書上的原文。Move 是 Facebook 公司爲其加密貨幣產品 Libra 開發的全新編程語言。編程語言


做爲開發人員和區塊鏈社區愛好者,但願經過這篇文章幫助你快速入門 Move 語言。模塊化


 


關於Move

Move 是一種用於實現 Libra 自定義交易和智能合約的可執行的字節碼語言。

 

它與以太坊 Solidity 語言有如下兩個區別

 

  1. Move 是一種字節碼語言,它能夠直接在 Move 虛擬機中運行,而以太坊的 Solidity 語言是一種更高級別的語言,它須要先編譯成字節碼再加入到以太坊虛擬機中運行。

  2. Move 語言不只能夠用來實現智能合約,還能夠用來實現自定義交易(彆着急,接下來咱們會詳細介紹自定義交易),而 Solidity 語言只能用來實現以太坊中的智能合約。

Move 語言的一個關鍵特性是它可以定義受線性邏輯啓發的帶語義的自定義資源類型。在這種狀況下資源永遠不會被複制或被隱式丟棄,它只能在程序的存儲位置之間轉移。

 

這是一個與 Rust 語言相似的特性。Rust 語言中的數值一次只能分配給一個命名。若是你將某個數值分配給其餘命名則將沒法再使用以前的命名訪問到該數值。

 

就好比說,下面這段代碼將會輸出一個錯誤:使用轉移了的值「 x 」(Use of moved value ‘x’)。


這是由於 Rust 語言沒有垃圾回收機制。當變量超出範圍時,變量引用的內存也會被釋放。


這樣解釋有點麻煩,爲了簡單起見,咱們能夠這樣來理解,每一個數據在同一時間內只能有一個「全部者」。在這個例子中,x 是數據初始的全部者,後來 y 也成了數據的全部者,因此程序會報錯,以下面代碼所示。

640?wx_fmt=png



在開放系統中編碼數字資產

 

將現實世界中的物理資產編碼成區塊鏈上的數字資產,主要存在兩大難題:


  • 稀缺性:區塊鏈系統中資產的供應應該受到嚴格管控。應該禁止複製現有的資產,同時也應該禁止普通用戶隨意建立新資產。

  • 訪問控制:區塊鏈系統中的參與者應該可以使用訪問控制策略保護本身的資產。

 

這也是全部數字資產都須要實現的兩個關鍵特性,這些特性被認爲是現實世界中物理資產的天然表徵。就好比說,現實世界中稀有金屬就是很稀缺的,在現實世界中你只能花屬於本身的錢,換句話說就是本身有訪問權限的錢。

 

爲了更好地闡述這兩個關鍵特性是如何實現的,讓咱們先從如下三個示例提及:

 

示例1:不考慮稀缺性和訪問控制的最簡單的規則


640?wx_fmt=png

左邊爲交易腳本的格式,右邊爲區塊鏈狀態的評估規則

 

  • G [K]:= n 表示使用加密貨幣數額 n 來更新帳戶 K 在區塊鏈全局狀態中存儲的加密貨幣餘額。

  • transaction⟨Alice,100⟩ 表示將 Alice 的帳戶餘額設置爲 100 。

 

上述的實現方式存在兩個很嚴重的問題:

 

  • Alice 能夠經過不斷髮起交易 transaction⟨Alice,100⟩ 讓本身擁有無限多的加密貨幣。

  • Alice 與 Bob 之間的加密貨幣轉帳也變得毫無心義,由於 Bob 也可使用相同的手段向本身發送無限多的加密貨幣。

 

示例2:在數字資產中加入稀缺性


640?wx_fmt=png

左邊爲交易腳本的格式,右邊爲區塊鏈狀態的評估規則

 

如今咱們強制要求在交易發起時發起方 Ka 的帳戶餘額至少爲交易的金額 n 。

 

雖然這種實現方式能夠解決稀缺性的問題,可是如今還存在一個問題,就是你能夠將任何人的加密貨幣餘額轉給本身,這是由於咱們尚未加入對誰能發起交易的檢查,也就是對加密貨幣全部權的檢查。

 

示例3:在數字資產中同時加入稀缺性和訪問控制


640?wx_fmt=png

左邊爲交易腳本的格式,右邊爲區塊鏈狀態的評估規則

 

爲了實現加密貨幣的訪問控制,咱們能夠在稀缺性檢查以前使用數字簽名機制 verify_sig 來檢查所交易加密貨幣的全部者,這意味着 Alice 可使用她的私鑰來簽署交易並證實她是所交易加密貨幣的全部者。

 


現有的區塊鏈編程語言


現有的區塊鏈編程語言每每都會被如下問題所困擾,使人欣慰的是,Move 語言完美地解決了全部這些問題。主要體如今如下兩方面。

 

  1. 間接地表示資產有些區塊鏈編程語言使用整數對數字資產進行編碼。這種編碼方式十分牽強,由於這些整數值與數字資產根本就不是一回事。事實上,這些區塊鏈中並無任何類型或數值來表示比特幣/以太幣/山寨幣!這使得編寫與數字資產交互的智能合約變得十分笨拙且容易出錯。在這些區塊鏈中實現諸如資產轉入/轉出以及將資產存儲在數據結構中這樣的操做都須要特殊的語言支持。

  2. 稀缺性是不可擴展的這些語言每每只能表示一種稀缺資產。除此以外,稀缺性保護直接在語言語義中進行硬編碼。開發人員若是想要建立一個自定義的資產,遺憾的是他得不到該語言的一絲幫助,他將不得不重複造輪子,從新實現資產的稀缺性。

 

相信你可能已經看出來了,這些正是以太坊智能合約中存在的問題。ERC-20 通證等自定義資產使用整數來表示資產和總供應量。每當生成新的通證時,智能合約代碼必須手動檢查交易是否知足稀缺性(在這種狀況下爲是否超過總供應量)。

 

此外,資產的間接表示會給區塊鏈帶來不少的問題,就好比說資產複製、資產重複使用、資產意外丟失等漏洞。


固然,除了上面兩點之外,還包括:訪問控制不夠靈活


這些區塊鏈強制執行的訪問控制策略只有基於公鑰的數字簽名方案。與稀缺性保護同樣,訪問控制策略也被深深嵌入到語言語義中。


若是開發人員想要設置自定義的訪問控制策略,那麼他仍是會陷入重複造輪子的困境。

以太坊也存在這樣的問題。以太坊智能合約缺少對使用公鑰私鑰密碼學實現訪問控制的本地語言支持。面對這種需求。開發人員不得不手動編寫訪問控制,就好比說使用 OnlyOwner函數。

 

儘管我是以太坊的忠實粉絲,但我堅持認爲以太坊在這些資產屬性方面存在欠缺。從安全方面考慮,這些資產屬性本應獲得原生的語言支持。

 

特別是,將以太坊轉移到智能合約中須要用到動態分派( dynamic dispatch ,處理編程語言的語言方法調用的一種計算機制),這又會帶來一類新的漏洞:可重入性漏洞( re-entrancy vulnerabilities )。

 

這裏的動態分派意味着代碼的執行邏輯將在代碼運行時(動態)肯定,而不是在代碼編譯時(靜態)肯定。


所以,在 Solidity 語言中,當智能合約 A 調用智能合約 B 的函數時,智能合約 B 可能會運行智能合約 A 的設計者從未預料到的代碼,這可能會致使可重入性的漏洞(智能合約 A 意外執行智能合約 B 的函數,從而在實際更新帳戶餘額以前提取到資金)。

 


Move 語言的設計目標


一流的資源

從較高的層次上來講,Move 語言中模塊/資源/程序之間的關係相似於面嚮對象語言中的類/對象/方法之間的關係。

Move 語言中的模塊相似於其餘區塊鏈語言中的智能合約。模塊聲明資源類型和程序,而這些資源類型和程序編碼用於建立,銷燬和更新所聲明資源的規則。

 

模塊/資源/程序只是 Move 語言中的一些術語。下文中咱們將會用一個例子來介紹它們。

 

靈活性

Move 經過交易腳本爲 Libra 增長了不少靈活性。每筆 Libra 交易都包含一個交易腳本,該腳本其實是交易的核心。

交易腳本能夠用來執行一次性的行爲(例如給一組特定的收款人付款),也能夠用來執行可重用的行爲(經過調用一個封裝了可重用邏輯的程序)。

 

從上面咱們能夠看出,Move 的交易腳本經過同時支持一次性的行爲和可重用的行爲爲 Libra 引入了更多的靈活性,而以太坊只能執行可重用的行爲(即調用單個智能合約方法)。


以太坊被稱爲「可重用」的緣由是智能合約中的函數能夠被屢次執行。

 

安全性

Move 的可執行格式是一種類型化的字節碼,它比彙編語言更高級但比源語言更低級。在區塊鏈上字節碼驗證器會檢查字節碼的資源,類型以及內存安全性,而後字節碼解釋器會直接執行字節碼。這種設定使得 Move 在提供與源語言相關聯的安全保證的同時,省去了將源編譯器添加到可信計算基礎( Trusted Computing Base,TCB )以及編譯到交易執行的關鍵路徑的成本。

 

將 Move 構建成一種字節碼語言確實是一種很是簡潔的設計。因爲它不須要像 Solidity 同樣從源代碼編譯成字節碼,所以沒必要擔憂編譯器中可能出現的故障或漏洞。

 

可驗證性

咱們的方法是儘量多地在區塊鏈上執行核心安全屬性的輕量級驗證,但同時咱們也在 Move 語言中加入了對鏈下高級靜態驗證工具的支持。

 

從這裏咱們能夠看出 Move 更傾向於執行靜態驗證而不是在區塊鏈上執行驗證工做。儘管如此,正如白皮書末尾所述,Libra 團隊將來將會開發完善驗證工具。

 

模塊化

Move 模塊強制執行數據抽象並本地化執行資源的關鍵性操做。模塊啓用的封裝與 Move 類型系統強制執行的保護相結合,強強聯手能夠確保模塊外部的代碼不能違反模塊類型規定的屬性。

 

這是一個很是好的數據抽象設計!這意味着智能合約中的數據只能在智能合約範圍內修改,而不能在外部修改。

 

640?wx_fmt=png


 

Move語言實操


這個交易腳本的示例說明了模塊外部的惡意開發人員或粗心的開發人員不可能違反模塊資源的關鍵安全不變性。

 

這一部分中咱們將討論在進行 Move 語言開發時,實際使用到的模塊、資源和程序分別是什麼東西。

 

點對點支付交易腳本


Move語言的點對點支付交易腳本,以下面代碼所示:


640?wx_fmt=png


amount(金額)表示所交易加密貨幣的金額,這些加密貨幣將從交易的發起方轉移給接收方 payee。

 

代碼中有幾個新的符號,其中紅色的小字是我記的筆記:

 

  • 0x0:存儲模塊的賬戶地址

  • currency:模塊的名稱

  • coin:資源類型

  • 程序返回的 coin 值是一個類型爲 0x0.Currency.Coin 的資源值

  • move():該值不能再次使用

  • copy():該值能夠再次使用

 

代碼功能解讀:


在第一步中,發送方從存儲在 0x0.Currency 的模塊中調用了名爲 withdraw_from_sender 的程序。

在第二步中,發送方經過將加密貨幣的資源值轉移到 0x0.Currency 模塊的存款程序中從而將資金轉移給收款人。

 

如下是三種會報錯的代碼示例:


1. 經過將轉移加密貨幣 move(coin) 替換爲複製加密貨幣 copy(coin) 來複制加密貨幣。

 

資源值只能被轉移。嘗試複製資源值(就好比說示例中使用的複製加密貨幣 copy(coin) )將在字節碼驗證時引發錯誤。

 

由於 coin 是一個資源值,因此它只能被轉移。


2. 經過兩次轉移加密貨幣 move(coin) 來重複使用加密貨幣(雙重支付)。

在上述的示例代碼中加入一行:

0x0.Currency.deposit(copy(some_other_payee),move(coin))

就可讓發送方兩次花費同一筆加密貨幣,第一次交易的收款人是 payee ,第二次交易的收款人是 some_other_payee 。現實生活中的物理資產能夠徹底杜絕雙重支付,幸運的是,Move 也能夠作到。


3. 忘記執行轉移加密貨幣 move(coin) 致使加密貨幣丟失。

 

忘記轉移資源(就好比說刪除上述代碼示例中轉移加密貨幣 move(coin) 所在的行)將觸發字節碼驗證錯誤。這種機制能夠保護 Move 開發人員不會有意或無心地丟失資源。

 

貨幣 Currency 模塊

模塊入門:Move 語言的執行模型

640?wx_fmt=png


三個帳戶的區塊鏈全局狀態示例

 

每一個賬戶能夠擁有零個或多個模塊(上圖中的矩形)和一個或多個資源值(上圖中的圓柱體)。就好比說,地址 0x0 處的賬戶擁有一個名爲 0x0.Currency 的模塊和一個 0x0.Currency.Coin 類型的資源值。地址 0x1 處的賬戶擁有兩個資源值和一個模塊;地址 0x2 處的賬戶擁有兩個模塊和一個資源值。

 

須要注意的是:

 

  • 交易腳本的執行只有兩種結果:成功或是失敗,不會存在中間的狀態。

  • 模塊是在區塊鏈全局狀態中發佈的長期存在的代碼。

  • 區塊鏈全局狀態的結構爲從賬戶地址到賬戶的映射。

  • 賬戶最多隻能包含一個給定類型的資源值,而且最多隻能包含一個具備給定名稱的模塊(就好比說,上圖中地址 0x0 處的賬戶不能再擁有一個額外的 0x0.Currency.Coin 資源或另外一個名爲 Currency 的模塊)。

  • 所聲明模塊的地址是類型的一部分(就好比說,0x0.Currency.Coin 和 0x1.Currency.Coin 是不能互換使用的不一樣類型)。

  • 開發人員仍然能夠經過自定義的包裝器( wrapper )資源來實現一個賬戶擁有多個給定資源類型的實例。(resource TwoCoins { c1: 0x0.Currency.Coin, c2: 0x0.Currency.Coin })

  • 開發人員仍然能夠經過名稱引用資源而不會產生任何衝突,就好比說,你可使用 TwoCoins.c1 和 TwoCoins.c2 這兩個名稱引用這兩個資源。

 

聲明加密貨幣資源:


640?wx_fmt=png


在名爲 Currency(貨幣)的模塊中定義一個由模塊管理的名爲 Coin(加密貨幣)的資源類型。

 

須要注意的是:

  • Coin(加密貨幣)是一種結構類型,其字段允許的值類型爲 u64 (64位無符號整數)。

  • 只有 Currency (貨幣)模塊的程序可以建立或銷燬 coin(加密貨幣)類型的值。

  • 其餘模塊和交易腳本只能經過模塊提供的公共可訪問的程序來寫入或引用值字段。

 

實現存款操做


640?wx_fmt=png

 

這段程序將 Coin(加密貨幣)資源做爲輸入,並將其與存儲在收款人 payee 賬戶中的 Coin 資源組合,具體的步驟以下:

  1. 銷燬輸入的加密貨幣並記錄其數值。

  2. 獲取對存儲在收款人賬戶下的 Coin 資源的惟一引用。

  3. 將程序傳遞過來的加密貨幣的數值加到收款人帳戶餘額中,並更新收款人帳戶餘額。

 

須要注意的是:

  • Unpack,BorrowGlobal 是內置程序。

  • Unpack <T> 是惟一一種刪除類型爲 T 的資源的方法。它將類型爲 T 的資源做爲輸入,刪除它,並返回綁定到資源字段的數值。

  • BorrowGlobal <T> 將地址做爲輸入,並返回對該地址下惟一的 T 實例的引用。

  • &mut Coin 是對 Coin 資源的可變引用,而不是對 Coin 。

 

實現撤銷存款 withdraw_from_sender:


640?wx_fmt=png


這個程序分爲三步:

 

  1. 獲取對發送方賬戶下惟一的 Coin 類型資源的引用。

  2. 用輸入的數額減小引用的 Coin 的數值。

  3. 建立並返回值爲更新後金額的新加密貨幣。

 

須要注意的是:


  • 任何人均可以調用存款函數 deposit ,但撤銷存款函數 withdraw_from_sender 具備訪問控制策略,於是只能被加密貨幣的全部者調用。

  • 獲取交易發起人帳戶函數 GetTxnSenderAddress 相似於 Solidity 語言中的 msg.sender 。

  • 除非知足什麼條件不然就拒絕函數 RejectUnless 相似於 Solidity 語言中的 require 。若是此項檢查失敗,則當前交易腳本會中止執行,而且它執行的任何操做都不會更新區塊鏈全局狀態。

  • Pack <T> 也是一個內置程序,它主要用來建立一個 T 類型的新資源。

  • 與 Unpack <T> 同樣, Pack <T> 只能在資源 T 的聲明模塊中調用。

 


寫在最後


如今你已經瞭解了 Move 語言的主要特徵,基本語法以及它與以太坊的差別。

 

最後,若是你想從事 Move 語言開發,我強烈建議你閱讀 Move 語言原始的白皮書。白皮書中包含許多 Move 語言的設計原則以及許多很好的參考資料。


640?wx_fmt=gif

推薦閱讀:


猛戳"閱讀原文"有驚喜喲smiley_12.png


老鐵在看了嗎?👇