在只有比特幣的年代,區塊鏈能夠實現簡單的價值產生和轉移,但卻未出現更多的商業模式。以太坊給區塊鏈帶來了維度的提升,基於區塊鏈的應用漸趨豐富,區塊鏈的各種商業模式加速湧現。這其中很重要的原因,是以太坊給區塊鏈帶來了一套圖靈完備的程式語言。
區塊鏈的主要功能,是實現了多方的共識。在比特幣中,需要共識的操作是固定的,是非圖靈完備的。其共識的僅僅是價值所有者的改變。但以太坊上,開發者可以自己編寫需要共識的邏輯,以太坊透過智慧合約語言Solidity,實現了共識邏輯的自定義。
Solidity 介紹
Solidity語言和Java存在著些許相似之處。在眾多程式語言中,Java是發展較為成熟的。Java程式碼在Java虛擬機器(JVM)執行。JVM遮蔽掉了作業系統的差異,使得Java成為一個跨平臺的語言。一套Java程式碼可在Windows、Linux、Mac上通用,而不需要關心作業系統的差異。
Solidity與Java類似。程式碼寫好後,都需要透過編譯器將程式碼轉換成二進位制,在Java中,編譯器是Javac,而對於Solidity,是solc。生成後的二進位制程式碼,會放到虛擬機器裡執行。Java程式碼在Java虛擬機器(JVM)中執行,在Solidity中,是一個區塊鏈上的虛擬機器EVM。
Solidity與Java的不同之處在於,Solidity是服務於區塊鏈的語言,程式碼在區塊鏈上執行。EVM是區塊鏈上的一個執行器。每個區塊鏈節點都有一個EVM。Solidity在EVM中被執行後,EVM對區塊鏈的資料進行了改變。這些資料的改變交由共識演算法去共識。同時,Solidity的操作僅限於EVM內部,不能訪問外部不確定系統或資料,如系統時鐘,網路檔案系統等。
Solidity的設計目的,是給區塊鏈提供一套統一的邏輯,讓相同的程式碼跑在區塊鏈的每個節點上,藉助共識演算法,讓區塊鏈的資料以統一的方式進行改變,達到全域性一致的結果。
Solidity 實現細節
以此處的Demo合約為例,合約中有一個全域性變數m,並有一個函式add(),實現給全域性變數m增加x數值的功能。
透過合約編譯器solc,可將此合約編譯成二進位制。二進位制的每個字(8 bit),表示一個EVM的操作碼(OPCODE)。Demo合約編譯出的二進位制及其相應的OPCODE如下,實現了完整的Demo合約的功能,包括對合約的裝載、合約介面的呼叫和異常處理的邏輯。其中,標紅部分是add()方法的實現。
將add()函式的OPCODE的標紅部分摘取出來,可看到其具體的實現思想與彙編程式碼相同,是一種基於堆疊式的操作。其中的SLOAD將區塊鏈上指定位置的資料讀入堆疊頂部,ADD實現將堆疊頂端的兩個資料相加,SSTORE再將相加後放在堆疊頂部的結果寫入區塊鏈下一個區塊的資料中,為下個區塊的共識做準備。
在合約二進位制被部署到區塊鏈上後,透過傳送交易呼叫合約裡的方法。節點根據交易將合約程式碼裝載入EVM中,並根據交易的傳參執行合約上相應的函式add()。
EVM執行合約程式碼,從區塊鏈上讀入當前區塊的資料,進行相加操作,並將結果寫入下一個區塊(等待共識的區塊)對應的狀態資料中。
此後,共識演算法將待執行的區塊共識落盤,區塊高度增加,區塊鏈上的資料完成更新。
上述步驟可見,Solidity的實現與當今已有的做法有著很多相似之處。編譯,用的是傳統的套路,將程式碼轉換成虛擬機器可執行的二進位制;執行,也是與傳統方式相同,藉助堆疊作為緩衝區執行二進位制程式碼。
Solidity 侷限與改進
Solidity由於是第一個大規模應用的智慧合約語言,存在著一些有待改進的地方。
Solidity不夠靈活。Solidity語言受到自身堆疊深度的限制,函式傳參和區域性引數的個數總和不能超過16個。要實現一些比較複雜的函式難免有些雞肋。Solidity是一種強型別的語言,但其型別轉換較為麻煩。將整型轉換成字串時需要轉換成二進位制再拼接。在字串的操作上,缺少一些方便的函式。
Solidity的效能較差。在執行上,OPCODE的執行是一種用程式模擬的彙編執行器,而不是直接使用CPU的資源。在儲存上,Solidity的底層儲存單位是32位元組(256 bits),對硬碟的讀寫要求較高,浪費了大量的儲存資源。
針對上述兩點,FISCO BCOS提供了一種用C++寫合約方式:預編譯合約。開發者可以用C++編寫智慧合約邏輯,並將其內建在節點中。
預編譯合約的呼叫方法與Solidity合約相同,透過合約地址即可直接呼叫。FISCO BCOS提供了引數解析,將呼叫的引數解析成C++可識別的格式。
預編譯合約突破了Solidity語言的限制,藉助強大的C++語言,可以靈活的實現各種邏輯,靈活性大大提高。同時,C++的效能優勢也得到了很好的利用,透過預編譯合約編寫的邏輯,相比於Solidity語言來說,效能得到提升。