我們都知道一個智能合約其實就是一段代碼,最終執(zhí)行的是相應(yīng)的編譯器編譯出的二進制代碼唱歧。這個執(zhí)行二進制代碼的環(huán)境就叫虛擬機宪摧。如果一條區(qū)塊鏈系統(tǒng)上集成了相應(yīng)平臺的虛擬機粒竖,就可以說這個區(qū)塊鏈系統(tǒng)支持了某個平臺的智能合約。
我們知道第一個實現(xiàn)智能合約的公鏈是以太坊几于,而以太坊實現(xiàn)智能合約的技術(shù)原理來源于比特幣的腳本代碼蕊苗。比特幣的腳本的運行原理是基于堆棧這種數(shù)據(jù)結(jié)構(gòu)的。具體可以去看《精通比特幣》的交易章節(jié)---比特幣交易腳本和腳本語言孩革。
所以一個虛擬機里最基本也是最核心的數(shù)據(jù)結(jié)構(gòu)就是要實現(xiàn)一個堆棧(stack);如同CPU結(jié)構(gòu)里的寄存器得运。我們知道CPU的結(jié)構(gòu)包括:計算單元膝蜈,存儲單元,控制單元熔掺。其實一個虛擬機也是一個CPU饱搏,也包括這三個部分;在我們的代碼結(jié)構(gòu)中置逻,這三個部分被封裝在了ExecutionEngine這個類中推沸。
上面的代碼可以看到。其實ExecutionEngine就是控制單元券坞。用于在不同數(shù)據(jù)棧(單元)中的數(shù)據(jù)的協(xié)調(diào)鬓催。我們介紹一下在引擎中的作用:
invocationStack: 調(diào)用棧,在調(diào)用其他函數(shù)時或調(diào)用其他合約都會有一個新的調(diào)用棧恨锚。
EvaluationStack:計算棧宇驾,相當于CPU中的計算單元。存儲的是程序中的opCode指令猴伶。
AltStack:備用棧课舍,計算棧算出的中間結(jié)果可以保存在備用棧.
table:存儲單元,持久化合約代碼的hash或其他數(shù)據(jù)的數(shù)據(jù)庫他挎。
從上面的代碼可以看出筝尾,除了上面的基本運算單元外,還有其他數(shù)據(jù)結(jié)構(gòu)办桨,我們也簡單介紹下:
crypto:區(qū)塊鏈系統(tǒng)用到的加密算法筹淫。一般是ECDSA(橢圓加密)
dataContainer:觸發(fā)此合約的數(shù)據(jù)對象,通常是一個交易(transaction)
state:合約指令執(zhí)行結(jié)果的狀態(tài)呢撞。(是否成功)
opCode:當前執(zhí)行的指令碼贸街。
service:虛擬機交互層,用于一些系統(tǒng)指令的調(diào)用狸相。
gas: 合約執(zhí)行指定的燃料薛匪。
gasConsumed:當前已經(jīng)消耗的燃料.
現(xiàn)在我們對相應(yīng)數(shù)據(jù)的代碼文件進行簡單的介紹:
上面的圖忘記了最重要的數(shù)據(jù)結(jié)構(gòu)(堆棧)在utils包中:
有了上面的內(nèi)容,基本上就是一個虛擬機了脓鹃,可以執(zhí)行一些簡單的邏輯處理了逸尖。但是我們除了基本的運算功能之外,既然智能合約是運行在區(qū)塊鏈上的。就要訪問區(qū)塊鏈的數(shù)據(jù)娇跟。比如:BlockChain.GetHeight();獲取當前區(qū)塊鏈的高度岩齿。這樣的指令我們稱為系統(tǒng)指令。其實這部分指令也就是上面我們介紹的交互層(service):只要我們實現(xiàn)相應(yīng)的數(shù)據(jù)結(jié)構(gòu)苞俘,就要以當作參數(shù)傳入虛擬機盹沈。然后虛擬機就可以根據(jù)解析出的指令找到相應(yīng)的邏輯處理。在我們的代碼中是定義在了一個叫做StateReader(狀態(tài)讀取,就是對區(qū)塊鏈系統(tǒng)的相應(yīng)數(shù)據(jù)讀瘸砸ァ)的文件中
上面的代碼只是一部分乞封,實現(xiàn)的是相應(yīng)的運行時狀態(tài)讀取和區(qū)塊鏈數(shù)據(jù)的讀取。當然岗憋,除了讀取也會有寫入操作肃晚,區(qū)塊鏈中最寶貴的資源當然是空間。寫入數(shù)據(jù)我們是按照字節(jié)收費的仔戈。相應(yīng)的代碼我們定義在stateMachine文件中关串。
既然提到了收費,就簡單介紹下监徘。我們的合約里是按指令收費的:
OK晋修。到這里,基本上一個虛擬機運行所需的代碼結(jié)構(gòu)我們基本上有了個框架凰盔。其中的細節(jié)飞蚓,就是相應(yīng)的虛擬機運行過程,還需要大家仔細閱讀相應(yīng)的源碼廊蜒。