一文教你如何使用圖靈完備的EVM虛擬機器

買賣虛擬貨幣
近年來,智慧合約成為了區塊鏈安全的重災區,從The DAO到BEC,SocialChain,Hexagon,再到EOS漏洞,智慧合約安全漏洞頻現令不少開發者和企業對區塊鏈望而卻步。12月8日,在迅雷鏈技術沙龍第六站現場,迅雷鏈底層研發工程師胡登啟系統剖析了智慧合約安全問題,分析了智慧合約中存在的典型漏洞和預防措施,並總結了在合約程式設計過程中需要注意的幾大安全原則,在現場聽眾間引起了熱烈反響。區塊鏈虛擬機器工作原理 關於虛擬機器的執行原理,胡登啟以EVM為例,講解了虛擬機器底層是如何實現的,讓開發者對虛擬機器有了更全面的認識。首先,區塊鏈的虛擬機器應該包含以下6個特性:1.安全:這也是最重要的,即程式碼在沙盒中執行,一旦發生錯誤,可以回滾掉所有更新;
2.結果明確:結果確定且沒有歧義,在區塊鏈的所有節點執行該邏輯,得到的結果一定是保持一致的;3.簡單:操作碼低階,結構簡單;4.具備特定的能力:虛擬機器能處理加密運算,比如支援橢圓曲線演算法,能訪問交易與鏈狀態,獲取blockhash,tx相關內容等等;5.易於最佳化:支援即時編譯(JIT)等;

6.節省空間:虛擬機器元件緊湊,便於整合到區塊鏈服務中。

透過分析EVM虛擬機器,胡登啟總結了通用區塊鏈虛擬機器應該是如何運作的:

1.首先開發者會使用 c、c++、或者 solidity等高階語言編寫一個合約,一般情況下這裡包含了很多的複雜的業務邏輯;
2.透過編譯器llvm,或者solidity編譯器,將包含服務業務邏輯的原始碼編譯成與機器無關的中間程式碼,也就是我們所說的位元組碼;
3.虛擬機器在執行時,首先要透過程式碼載入器,將位元組碼讀入記憶體,初始化基礎的記憶體變數;
4.然後由虛擬機器的執行引擎將一條一條的位元組碼指令翻譯成對應機器平臺的底層指令執行;
5.執行引擎在執行指令的過程中會使用到臨時變數、堆疊區儲存空間,或者讀寫外部檔案等,這裡統稱為執行時資料區。

區塊鏈虛擬機器的執行流程

一個通用的虛擬機器執行流程可以抽象成下面這個過程:

1.首先將位元組碼載入到記憶體的程式碼段,初始化執行環境,這時程式計數器初始化為0。如上圖所示,這裡有個迴圈體,迴圈判斷的結束條件是:是否要終止執行?如果判斷標記為false,則獲取pc執行的操作碼,否則退出執行,返回結果;
2.獲取到pc操作碼後,會校驗引數,比如引數是否足夠,有沒有超過堆疊的最大可用空間等;
3.接下來會執行具體的指令;
4.指令結束後,計數器加一,繼續迴圈,直到程式設定了終止標記位。

迅雷鏈支援圖靈完備的EVM虛擬機器,胡登啟以一個簡單的solidity合約為例,為現場開發者分析了EVM虛擬機器是如何執行的。

EVM虛擬機器的執行主流程是在Run函式里面的,在迴圈裡面首先會獲取對應的操作碼,將操作碼關聯到對應的指令,這個指令在執行之前會進行一些資料的校驗。執行指令完之後,可以判斷繼續執行指令還是返回退出。

如上圖所示,這個合約只有一個Add函式,計算2個uint8變數的和。
透過solidity編譯器,將合約編譯成bytecode. 虛擬機器會將bytecode轉換成對應的opcode。opcode被表示為預定義的識別符號。比如 0x60 對應的opcode是  PUSh2, 0x52 對應的opcode是 MSTORE.

而上面提到的被預定義的識別符號,其實就是操作碼。EVM中將操作碼大致分為四類:

第一類是算術運算,包括最基礎的加減乘除運算指令;
第二類是邏輯運算,包括與、或、非、等於、不等於、大於、小於等;
第三類是與區塊鏈狀態相關指令,具體是指區塊資訊如coinbase、區塊時間戳、區塊序號等,還有交易相關的,如交易的傳送者,交易轉賬金額等指令;
第四類是跟儲存相關的指令,比如讀取虛擬機器執行時記憶體資料,或者儲存資料到區塊鏈狀態中。

每一個操作碼都對應一個操作指令。操作指令定義了操作碼具體要執行怎樣的操作,操作消耗的gas值,操作需要的引數與返回值的個數,還有操作需要額外空間。同時操作指令中還定義了一些標記位,比如終止運算、跳轉、是否出錯、是否應該返回等。

胡登啟透過展示最簡單的加法操作指令為例,為大家分析了指令結構。EVM虛擬機器每個操作指令都會消耗一定的gas值,這麼做的目的一方面是為了避免開發者編寫無限迴圈的程式碼,另一方面是為了給打包交易的節點一點獎勵。

智慧合約開發的安全準則

不過胡登啟指出,EVM只是區塊鏈虛擬機器的一種實現方式,而且現行的智慧合約還是一個在不斷髮展的技術,要想運用好這個技術並不容易。

事實上,在實踐過程中,合約被爆出了各種安全漏洞,這些漏洞可能給專案發行方造成巨大的損失。因為區塊鏈是去中心化的自治系統,往往發現漏洞後,發行方很難去修復這個漏洞,只能任由駭客肆意的攻擊。因此要求開發者在編寫智慧合約時,做更加全面的安全測試,儘量避免包含漏洞的程式碼釋出到區塊鏈系統中。

胡登啟透過分析智慧合約中存在的典型漏洞,向現場聽眾展示了智慧合約安全問題的重要性,併為開發者編寫智慧合約提供了一些參考。

比如,他以今年年初轟動一時的美鏈BEC合約漏洞為例,講述了智慧合約安全的重要性。BEC是美鏈公司釋出的token,於今年2月上線交易, 4月22日該合約被爆出重大漏洞,導致其token市值幾乎歸零。

其智慧合約中有個批次轉賬的介面,引數是地址陣列和轉賬token值。如上圖的第218行程式碼,這裡有個乘法運算,用以計算一次交易中轉移token的總值,計算結果使用uint256型別儲存。有過c或者c++開發經驗的同學可能會看出,這裡存在整數溢位的問題。

駭客正是利用了這個漏洞,進行BEC token的鉅額增發,最終導致其價值接近歸零。

胡登啟以此作為反面教材,告誡開發者,在合約開發中進行任何數學運算時,都推薦使用SafeMath庫,這樣可以避免溢位的漏洞。比較諷刺的一點是,BEC合約的其他程式碼都使用了SafeMath庫,唯獨漏了這一處。可見程式碼測試一定要充分,漏了一個點,可能造成巨大損失。

透過對另外數起知名安全漏洞案例的分析,胡登啟總結了智慧合約開發的3條安全準則:

1.開發者應深入的理解系統的執行原理。
2.希望開發者熟練掌握一門合約語言的特性。
3.要做全面的程式碼測試,不能有僥倖心理。

胡登啟最後表示,區塊鏈智慧合約還是一門比較年輕的技術,需要在開發者的不斷實踐中去完善與提升。因此在目前階段,開發者進行智慧合約程式設計時,尤其需要注意規避漏洞,以保證合約具備足夠的安全性。

更多區塊鏈資訊:www.qukuaiwang.com.cn/news

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;