我們都知道一個智能合約其實就是一段代碼,最終執行的是相應的編譯器編譯出的二進制代碼。這個執行二進制代碼的環境就叫虛擬機。如果一條區塊鏈系統上集成了相應平臺的虛擬機,就可以說這個區塊鏈系統支持了某個平臺的智能合約。
我們知道第一個實現智能合約的公鏈是以太坊,而以太坊實現智能合約的技術原理來源于比特幣的腳本代碼。比特幣的腳本的運行原理是基于堆棧這種數據結構的。具體可以去看《精通比特幣》的交易章節---比特幣交易腳本和腳本語言。
所以一個虛擬機里最基本也是最核心的數據結構就是要實現一個堆棧(stack);如同CPU結構里的寄存器。我們知道CPU的結構包括:計算單元,存儲單元,控制單元。其實一個虛擬機也是一個CPU,也包括這三個部分;在我們的代碼結構中,這三個部分被封裝在了ExecutionEngine這個類中。
上面的代碼可以看到。其實ExecutionEngine就是控制單元。用于在不同數據棧(單元)中的數據的協調。我們介紹一下在引擎中的作用:
invocationStack: 調用棧,在調用其他函數時或調用其他合約都會有一個新的調用棧。
EvaluationStack:計算棧,相當于CPU中的計算單元。存儲的是程序中的opCode指令。
AltStack:備用棧,計算棧算出的中間結果可以保存在備用棧.
table:存儲單元,持久化合約代碼的hash或其他數據的數據庫。
從上面的代碼可以看出,除了上面的基本運算單元外,還有其他數據結構,我們也簡單介紹下:
crypto:區塊鏈系統用到的加密算法。一般是ECDSA(橢圓加密)
dataContainer:觸發此合約的數據對象,通常是一個交易(transaction)
state:合約指令執行結果的狀態。(是否成功)
opCode:當前執行的指令碼。
service:虛擬機交互層,用于一些系統指令的調用。
gas: 合約執行指定的燃料。
gasConsumed:當前已經消耗的燃料.
現在我們對相應數據的代碼文件進行簡單的介紹:
上面的圖忘記了最重要的數據結構(堆棧)在utils包中:
有了上面的內容,基本上就是一個虛擬機了,可以執行一些簡單的邏輯處理了。但是我們除了基本的運算功能之外,既然智能合約是運行在區塊鏈上的。就要訪問區塊鏈的數據。比如:BlockChain.GetHeight();獲取當前區塊鏈的高度。這樣的指令我們稱為系統指令。其實這部分指令也就是上面我們介紹的交互層(service):只要我們實現相應的數據結構,就要以當作參數傳入虛擬機。然后虛擬機就可以根據解析出的指令找到相應的邏輯處理。在我們的代碼中是定義在了一個叫做StateReader(狀態讀取,就是對區塊鏈系統的相應數據讀取)的文件中
上面的代碼只是一部分,實現的是相應的運行時狀態讀取和區塊鏈數據的讀取。當然,除了讀取也會有寫入操作,區塊鏈中最寶貴的資源當然是空間。寫入數據我們是按照字節收費的。相應的代碼我們定義在stateMachine文件中。
既然提到了收費,就簡單介紹下。我們的合約里是按指令收費的:
OK。到這里,基本上一個虛擬機運行所需的代碼結構我們基本上有了個框架。其中的細節,就是相應的虛擬機運行過程,還需要大家仔細閱讀相應的源碼。