Facebook推出Libra專案產生了刷屏級的影響,一時間資訊爆炸,觀點紛至。關於Libra具體操作模式、落地場景、影響面、如何與監管互動等討論已經很多。這次,我們想為關注國際區塊鏈發展的開發者、愛好者們帶來點不一樣的!百度超級鏈XUPER致力於國產自研的區塊鏈技術研發,並積極推動區塊鏈的商業化落地。在底層區塊鏈技術上擁有120餘篇專利保護,在超級節點、鏈內並行、立體網路、可插拔共識機制等技術上實現國產自主創新。保持一直以來對區塊鏈技術關注,百度的研發工程師們發現,Libra採用了一種全新的move語言,其核心是從設計上防止數字資產被複制,降低了出現意外漏洞或安全事件的風險。Libra白皮書中關於move語言的描述Libra 區塊鏈的三項決策:1. 設計和使用 Move 程式語言。2. 使用拜占庭容錯 (BFT) 共識機制。3. 採用和迭代改善已廣泛採用的區塊鏈資料結構。 “Move”是一種新的程式語言,用於在 Libra 區塊鏈中實現自定義交易邏輯和“智慧合約”。由於 Libra 的目標是每天 為數十億人服務,因此 Move 的設計首先考慮到安全性和可靠性。Move 是從迄今為止發生的與智慧合約相關的安 全事件中吸取經驗而創造的一種程式語言,能從本質上令人更加輕鬆地編寫符合作者意圖的程式碼,從而降低了出現 意外漏洞或安全事件的風險。具體而言,Move 從設計上可防止數字資產被複制。它使得將數字資產限制為與真實資 產具有相同屬性的“資源型別”成為現實:每個資源只有唯一的所有者,資源只能花費一次,並限制建立新資源。Move 語言還便於自動驗證交易是否滿足特定屬性,例如,僅更改付款人和收款人帳戶餘額的付款交易。透過優先實現這 些特性,Move 可幫助保持 Libra 區塊鏈的安全性。透過減輕關鍵交易程式碼的開發難度,Move 可以可靠地執行 Libra 生態系統的管理政策,例如對 Libra 貨幣和驗證者節點網路的管理。Move 將加快 Libra 區塊鏈協議以及在此基礎上 構建的任何金融創新的演變。我們預計將在一段時間後向開發者開放建立合約的許可權,以支援 Move 的演變和驗證。下面進入百度研發工程師帶來的move語言介紹Move是一門強型別的位元組碼語言,基於棧式虛擬機器設計,受Linear Logic型別系統的啟發,將資源(數字資產)作為第一等公民,藉助所有權轉移和最多一次可變引用等規則保證資產安全。名字Move的來歷也就自然而然可以理解了。三個大特點1. first-class resouces. 用資源表示數字資產是一等公民,然後透過語法藉助borrow check等思路在合約編譯期間保證資產的不可雙花,不可消失,必有歸屬性;2. flexibility 透過交易指令碼來定義單個交易裡面的一次性(不可重用)合約邏輯,交易指令碼定義了合約的main函式,可以插入多個module實現複雜邏輯和可重用邏輯。合約的結構原語modules/resources/procedure,類比與物件導向的class/object/method,同時透過module做合約資源的宣告週期管理,極大的提升了合約可複用性和安全性。3. 強型別的位元組碼,在位元組碼層面的靜態程式碼檢查保證執行時的大多數錯誤都在編譯期間被發現。Move沒有動態指派(dynamic dispath),函式呼叫完全是在編譯期間確定,沒有什麼類似c++的RTTI的機制,這樣驗證工具可以快速構建呼叫圖驗證,borrow check保證資源任何時候只有一個muttable引用,這樣寫操作就可以被嚴格檢驗。保證足夠安全。Move例項介紹先舉個Move寫的合約例子:public main(payee: address, amount: u64) { let coin: 0x0.Currency.Coin = 0x0.Currency.withdraw_from_sender(copy(amount)); 0x0.Currency.deposit(copy(payee), move(coin));}合約接受2個引數轉賬接收人payee和轉賬金額amount。0x0表示賬戶地址,Currency表示module, 0x0.Currency.Coin表示資源型別,0x0.Currency.withdraw_from_sender這個procedure(過程)返回一個0x0.Currency.Coin型別的值coin,然後透過deposit這個過程,將coin轉移到payee的地址下面去。 藉助於linear logic的轉移原則, 限制資源(數字資產的)的不可重用(只能轉移一次),不可複製(不能copy資源)以及不可丟失(轉移之後必有地址接受)。Move透過一個地址到賬戶的map來表示global state。如下:
包含3個賬戶的global state的示意圖
在一個賬戶裡面,可以包含多個module或者resouces,但是不能同名,雖然不能同名,但是可以在一個賬戶裡面,同時持有2個地址下面相同型別名的例項。例如:
resource TwoCoins { c1: 0x0.Currency.Coin, c2: 0x0.Currency.Coin })
例如宣告一個名叫Coin資源如下:
module Currency {
resource Coin { value: u64 }
// ...
}
預設情況下,Coin是private的,外部需要透過module暴露的其他介面(實際操作的語義最終也只能是move)才能被訪問,並且許可權完全由module的建立者控制。
deposit的實現如下:
public deposit(payee: address, to_deposit: Coin) {
let to_deposit_value: u64 = Unpack<Coin>(move(to_deposit));
let coin_ref: &mut Coin = BorrowGlobal<Coin>(move(payee));
let coin_value_ref: &mut u64 = &mut move(coin_ref).value;
let coin_value: u64 = *move(coin_value_ref);
*move(coin_value_ref) = move(coin_value) + move(to_deposit_value);
}
詳細解釋為:
1. move(to_deposit)將銷燬sender的to_deposit這個資源,並且將其儲存在一個區域性變數to_deposit_value上;
2. 在接受人的空間下面建立一個引用coin_ref,然後建立一個儲存coin_ref的value的可變引用coin_value_ref,
3. 取出coin_value_ref的value,將其跟to_deposit_value相加,將結果存回到coin_value_ref。
其中注意的是,Unpack<T>是Move內嵌的使用者銷燬型別為T的變數,然後返回T的具體欄位的值的procedure。BorrowGlobal返回一個Coin的資源的引用。
然後在看下withdraw_from_sender的實現:
public withdraw_from_sender(amount: u64): Coin {
let transaction_sender_address: address = GetTxnSenderAddress();
let coin_ref: &mut Coin = BorrowGlobal<Coin>(move(transaction_sender_address));
let coin_value_ref: &mut u64 = &mut move(coin_ref).value;
let coin_value: u64 = *move(coin_value_ref);
RejectUnless(copy(coin_value) >= copy(amount));
*move(coin_value_ref) = move(coin_value) - copy(amount);
let new_coin: Coin = Pack<Coin>(move(amount));
return move(new_coin);
}
幾乎是deposit的逆過程,流程如下:
1. 獲得轉賬發起方的地址,然後獲得其Coin資源的實際的value, code_value;
2. 從coin_value減去amount個幣;
3. 然後條用Pack建立一個新的Coin資源並且傳回去。
綜上可以看到,BorrowGlobal可以驗證account是否有許可權獲得一個資源的引用(意味著馬上要進行修改),然後透過Unpack實際的資源的value然後銷燬資源,或者Pack來新建新的資源。然後上面各種語法&mut之類的,建議大家看看rust就好懂了。