深層解讀白皮書 - Move:Facebook Libra Blockchain的新編程語言

MOVE 語言的特點以及從開發人員的角度來看與以太坊的差異

附註:部份英文專有名詞無對應中文翻譯,原文作者以及Blockore團隊為其保留翻譯之準確空間

 

概述和動機

這篇文章帶領大家初步了解Facebook Libra新編程語言Move的26頁技術白皮書。 作為以太坊開發人員和區塊鏈社區愛好者,我希望為每個對這種新語言感到好奇的人,快速的介紹這篇文章,讓大家了解他的亮點:)

希望大家會喜歡!

1. 抽象

Move是一種可執行的位元組碼的語言,用於執行自定義事項和智能合約。

相較於Solidity,有兩件事需要注意:

  • Move是一種位元組碼語言,可以在Move的VM中直接執行,然而Solidity(以太坊的智能合約語言)是一種更高級別的語言,需要在EVM(以太坊的虛擬機)執行之前編譯成位元組碼。
  • Move不僅可用於執行智能合約,還可用於自定義事項(本文稍後將對此進行說明),而Solidity僅適用於以太坊上的智能合約。

The key feature of Move is the ability to define custom resource types with semantics inspired by linear logic: a resource can never be copied or implicitly discarded, only moved between program storage locations.

這是一個類似於Rust的功能。 Rust中的值一次只能分配給一個名稱。如果將值分配給一個不同的名稱,那將會導致無法再使用以前的名稱訪問該值。

例如,以下代碼段將輸出錯誤: Use of moved value 'x' 。 這是因為Rust沒有垃圾回收。當變量超出範圍時,它們引用的內存也會被釋放。 簡單來說,我們可以理解為 數據 一次只能有一個「所有者」。在以下的示例中,x是原始所有者,然後y成為所有者。

參考: http://squidarth.com/rc/rust/2018/05/31/rust-borrowing-and-ownership.html

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

物理資產有兩個屬性難以在數字資產中編碼: 

  • 稀缺性:應控制系統中的資產供應。 複制現有資產應當被禁止,且創建新資產應該為一種特權。 
  • 資產擁有權的權限管理:系統中的參與者資產應該能受到資產控管條例的保護。

它指出了數字資產需要實現的兩個對物理資產理所當然的主要特徵。 例如,稀有金屬自然具有稀缺性 ,而傳統物理資產不需做資產擁有權的權限管理,因為花出去的錢會實體交給商家,不易有電子現金的雙重支付問題(同一張鈔票能支付多次)。

為了說明我們如何提出這兩個屬性,讓我們從以下提案開始說明:

提案#1:最簡單的規則,沒有稀缺性和權限管理

最簡單的狀態評估規則,沒有稀缺性和權限管理。

  • G[K]:=n表示將儲存在全區域區塊鏈,密鑰K中的值更新為K
  • transaction ⟨Alice, 100⟩表示將Alice的賬戶餘額設置為100。

上述表示存在嚴重問題:

  • Alice可以通過發送transaction ⟨Alice, 100⟩,讓自己擁有無限的硬幣。
  • Alice發送給Bob的硬幣毫無價值,因為Bob可以使用相同的技術向自己發送無限量的代幣。

提案#2:考慮到稀缺性

第二個提案只考慮稀缺性

 

現在我們強制將在轉移之前存儲在𝐾𝑎下的硬幣數量設定至少為𝑛。

然而,雖然這解決了稀缺問題,但是對於可以發送給Alice的貨幣的人沒有做所有權的檢查。 (任何人都可以根據此評估規則這樣做)

提案#3:同時考慮稀缺性和權限管理

第三個提案同時考慮稀缺性和權限管理

我們透過在檢查稀缺性之前使用數字簽章機制verify_sig來處理這個問題。這意味著Alice使用她的私鑰來簽署交易,並證明她是代幣的所有者。

2.1 現有的區塊鏈語言

現有的區塊鏈語言面臨以下問題(所有這些問題都已在Move中解決):

  • 間接代表資產:資產使用整數進行編碼,但整數值與資產本質上並不相同。 事實上,目前沒有任何類型或數值代表Bitcoin/Ether/StrawCoin! 這使得編寫使用資產的程序變得不便且容易出錯。 諸如將資產傳入或傳出的過程,或是將資產存儲在數據結構中等的模式會需要編程語言的一些特殊支持。
  • 稀缺性是不可擴展的 :這種語言只代表一種稀缺資產。 此外,稀缺性的保護是直接在編程語言的語義中進行硬編碼而成的。 程序員在希望創建自定義資產時,必須在沒有語言支持的情況下,謹慎地實現稀缺性這一特性。

這些正是以太坊智能合約中的問題。 ERC-20代幣等自定義資產使用整數來表示其值和其總供應量。每當新的代幣被生成時,智能合約代碼必須手動檢查是否符合稀缺性(在這種情況下為總供應量)。

此外,由於資產問題的間接表示,更有可能引入重複、重用或資產損失等嚴重錯誤。

  • 權限管理不靈活 :現有的模型架構,強制執行權限管理的唯一策略,是基於公鑰的簽章的模式。 與稀缺性保護一樣,權限管理的策略也深深嵌入編程語言的語義中。關於如何能擴展語言,並允許程序員制定自定義的權限管理策略,這個答案並不明顯。

在以太坊中也是如此,智能合約在使用公鑰-私鑰密碼學來進行權限管理的過程中,並沒有任何原生語言的支持。開發人員必須手動編寫權限管理,例如使用OnlyOwner

儘管我是以太坊的忠實粉絲,但我同意這些資產屬性應該由語言本身支持實現,以達到安全目的。

特別是,將以太轉移到智能合約涉及動態調度,這導致了一類新的錯誤,稱為重新入侵漏洞

動態調度在這裡指代碼執行邏輯將在運行時(動態)而不是編譯時(靜態)確定。 因此,在Solidity中,當合約A調用合約B的功能時,合約B可以運行合約A的設計者未預料到的代碼,這可能導致重新入侵的漏洞 (合約A意外執行合約B的功能,以便在實際扣除帳戶餘額之前提取資金)。

3. Move的設計理念

3.1  一流的資源

在較高的層次上,Move中modules(模組)/resources(資源)/procedure(程序)之間的關係類似於物件導向程式中classes/objects/methods之間的關係。 Move的模組類似於其他區塊鏈語言中的智能合約。 module聲明resource類型和procedure。這些資源類型和程序用於編碼創建,銷毀和更新其聲明的資源時的規則。

modules/resources/procedure只是Move中的一些術語。 我們將在本文後面用一個例子來說明這些;)

3.2 靈活性

Move通過(交易腳本)為Libra增加了靈活性。 每個Libra交易都包含一個transaction script,它實際上是事務的主要過程。

scripts可以執行expressive one-off behaviors(例如支付特定的一組收件人)或 可重用行為(通過調用單個程序,此程序封裝了可重用邏輯)

從上面我們可以看出, Move的transcation script引入了更多的靈活性,因為它能夠實現一次性行為以及可重用行為,而以太坊只能執行可重用行為 (這是一種只調用單一智能合約的方法)。 它被命名為「可重用 」的原因是因為智能合約功能可以多次執行。

3.3 安全

Move的執行格式是一種類型化的(typed)位元組碼,它比彙編語言(assembly language)更高級但比源語言(source language)更低級。 位元組碼通過位元碼驗證器在鏈上檢查資源,類型和記憶體安全性,然後由位元組碼解釋器直接執行。 此選項允許Move提供通常與源語言相關的安全保證,但不將源編譯器添加到可信任的計算庫或編譯的成本到執行交易的關鍵路徑 。

對於Move來說 ,成為位元組碼語言是一種非常簡潔的設計。 由於它不需要像Solidity一樣,從源代碼編譯為位元組碼,因此不必擔心在編譯器中可能出現的故障或攻擊。

3.4 可驗證性

我們的方法是盡可能多地執行關鍵安全屬性的輕量級的鏈上驗證,但同時設計Move可支持進階鏈下的靜態驗證工具。

從這裡我們可以看到Move更喜歡執行靜態驗證而不是進行鏈上驗證。儘管如此,正如他們在論文末尾所述,驗證工具留在未來進行開發。

3.5 模組化

 Move模組強制執行data abstraction(數據抽象)並將在資源上的關鍵操作本地化。 模組利用的封裝,結合Move系統強制執行的保護,可確保模組類型的屬性不會受到模組外部的代碼的影響。

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

來自: https//libra.org/en-US/open-source-developers/#move_carousel

4. Move概述

此示例的交易腳本演示了一個惡意或粗心程序員,在模組外部不能違反模組資源的關鍵安全不變量。

本節將透過一個示例,向您介紹在編寫編程語言時的modules(模組),resources(資源)和procedure(程序)到底是什麼。

4.1 點對點付款交易腳本

貨幣金額將從交易發送方轉移到收款方

這裡有幾個新符號(紅色小文字是我自己的筆記XD):

  • 0x0 :存儲module的帳戶地址
  • Currency :module的名稱
  • Coin :resource類型
  • coin是一個被procedure返回的值。它是一個類型為0x0.Currency.Coin的resource值
  • move() :該值不能再次使用
  • copy() :該值可以在以後使用

代碼細部 :

在第一步中,發送方從存儲在0x0.Currency的module中,調用名為withdraw_from_sender的procedure。

 

在第二步中,發送者通過將貨幣的資源值移動到0x0.Currency module的存款這動作,將資金轉移到收款人。

 

以下是3種將被拒絕的代碼示例:

1.  將move(coin)改為copy(coin)來複製貨幣金額

資源值只能被移動。 嘗試複製資源值(例如,在上面的示例中使用copy(coin) )將導致在位元組碼驗證時出錯。

因為coin是資源值,所以它只能被移動。

2. 透過兩次 move(coin) 來重新使用貨幣

將0x0.Currency.deposit(copy(some_other_payee),move(coin))添加到上面的示例中會讓發件人“花”兩次貨幣 - 第一次與收款人,第二次與some_other_payee。 這種不良行為在物理資產的情況下無法實現。 幸運的是,Move不會允許此類計劃的實施。

3. 透過刪除 move(coin) 丟失貨幣

移動資源失敗時(例如,通過將上面示例中包含move(coin)的那行代碼刪除)將觸發位元組碼驗證錯誤。 這可以防止使用Move的程序員不會意外地或有意地丟失對資源的跟踪。

4.2 Currency(貨幣)模組

4.2.1 入門開始:Move execution model(執行模型)

每個帳戶可以包含零個或多個模組(為上圖矩形)和一個或多個資源值(為上圖圓柱體)。 例如,在地址0x0的帳戶有模組0x0.Currency和類型為0x0.Currency.Coin的資源值。 在地址0x1的帳戶有兩個資源值和一個模組; 在地址0x2的帳戶有兩個模組和一個資源值。

一些值得注意的點:

  • 執行交易腳本是全有或全無的
  • 模組是在全域狀態下發布的長期代碼
  • 全域狀態的結構為從帳戶地址到帳戶的map
  • 帳戶最多只能包含一個給定類型的資源值,和一個具有給定名稱的模組(在地址0x0的帳戶不允許包含其他的類型為0x0.Currency.Coin的資源或另一個名為Currency的模組)
  • declaring module(聲明模組)的地址算是類型的一部分( 0x0.Currency.Coin和0x1.Currency.Coin是不能互換使用的不同類型)
  • 程序員仍然可以通過定義自定義一個包裝好的資源,來保有帳戶中給定資源類型的多個實例( resource TwoCoins { c1: 0x0.Currency.Coin, c2: 0x0.Currency.Coin } )
  • 規則是可以的,只要您仍然可以通過其名稱引用資源而不會發生衝突,例如您可以使用TwoCoins.c1和TwoCoins.c2引用這兩個資源。

4.2.2 聲明貨幣的資源

一個名為Currency的模塊組和一個由模組管理的名為Coin的資源類型

一些值得注意的點:

  • Coin是一種結構類型,其單個字段(field)值類型為u64(64位無符號整數)
  • 只有Currency module(模組)的procedure(程序)才能創建或銷毀Coin類型的值
  • 其他module(模組)和transaction script(交易腳本)只能透過模組公開的procedure(程序)寫入或引用值的字段

4.2.3 實施存款

此過程將 Coin(貨幣)資源作為input(輸入),並透過以下步驟將其與存儲在收款人帳戶中的Coin資源組合: 

  1. 銷毀輸入Coin並記錄其值。 
  2. 獲取對存儲在收款人帳戶下的獨一的Coin資源的引用。 
  3. 通過將Coin的值傳遞給procedure(程序),來增加收款人Coin的值。

一些值得注意的點:

  • Unpack, BorrowGlobal是內置procedure(程序)
  • Unpack<T>是刪除類型為T的資源的唯一方法。它將類型為T的資源作為輸入,銷毀它,並返回綁定到資源的字段的值
  • BorrowGlobal<T>將地址作為輸入,並返回對在此地址下發布的唯一類型T實例的引用&mut Coin是對Coin 資源的可變引用,而不是對Coin

4.2.4 實現withdraw_from_sender

這個程序(procedure):

  1. 獲取對在發件人帳戶下發布的Coin類型的唯一資源的引用。 
  2. 透過輸入量來減少引用的Coin的值。 
  3. 創建並返回值為金額的新Coin。

一些值得注意的點:

  • 任何人都可以調用Deposit ,但withdraw_from_sender有限制,它只能被硬幣所有者調用的權限管理
  • GetTxnSenderAddress類似於Solidity裡的msg.sender
  • RejectUnless類似於Solidity裡的require 。 如果此檢查失敗,則當前交易腳本的執行將停止,並且它執行的任何操作都不會應用於全域狀態
  • Pack<T> ,也是一個內置procedure(過程) ,它用於創建一個T類型的新資源\與Unpack<T>相似 , Pack<T>只能在資源T的聲明模組內調用

總結

現在您已經初步了解了Move的主要特徵,它與以太坊的相較的區別,以及其基本語法。

最後,我強烈建議您閱讀白皮書的原文 。 它包含了許多關於編程語言設計原則的細節以及許多很好的參考資料。

非常感謝您的閱讀時間。 歡迎任何建議!

 

《Ting Ting Lee 李婷婷》授權 Blockore 轉譯

Turing chain 共同創辦人兼 CTO/ Blockchain Researcher / Ethereaum ERC Author/ UC Berkeley Blockchain Lab

Add a new comment