「虛擬機器專欄」熟悉的新朋友 - 鏈上JVM

—— 導讀 ——

前文,我們介紹了對虛擬機器的歷史、特點、發展以及Solidity和EVM進行詳細介紹。Solidity和EVM的出現為區塊鏈的應用場景打開了新的大門,但是合約開發者使用Solidity進行智慧合約的開發,不可避免地存在著新語言的學習成本問題。

那麼,是否有這樣一位老朋友,能讓「合約開發者」和「區塊鏈」快速打成一片呢?

眾所周知,Java是一種被廣泛使用的、面向物件的程式語言,

具有

“一次編寫,處處執行”

的跨平臺特性。於是,我們將Java請到了我們的區塊鏈平臺,自研了一套可以

執行Java智慧合約

的執行引擎HVM。將Java智慧合約引入區塊鏈,主要有以下目的:

降低智慧合約開發的成本,讓合約開發者能專注於合約邏輯本身而不是語法細節。

為開發者提供熟悉的、適合區塊鏈場景的工具類和方法,避免重複“造輪子”。

解決傳統智慧合約與賬本互動模式單一的問題,提供多種更方便、更靈活的賬本互動的資料結構和方法,更好地滿足業務場景的需要。

本文將主要講解如何讓Java編寫的智慧合約執行在區塊鏈上,不會涉及大量JVM細節。從

Java合約使用、虛擬機器適配、賬本互動機制

三個方面進行介紹。

—— Java智慧合約的使用 ——

從合約開發者的角度來看,Java智慧合約的使用流程通常包括以下三個步驟:

合約開發、合約部署、合約呼叫

Java合約開發

相比傳統智慧合約,Java智慧合約的開發和使用更為簡單方便,主要體現在:

1)

專案搭建快

:開發者只需要在本地IDE中新建Java專案,引入合約開發依賴包,便可以開發合約。完成編碼後,將程式碼打包成合約Jar檔案即可用於部署上鍊。

2)

工具方法多

:開發者可以使用JDK中的類和方法,避免重複”造輪子“的麻煩。

3)

學習成本低

:Java語言使用廣泛,大部分開發者只需要瞭解合約開發依賴包的介面,便能熟練使用Java智慧合約。

Java合約部署

對於Java智慧合約的部署,開發者透過一筆交易將合約Jar包上傳到鏈上,區塊鏈會對合約進行初始化,生成一個唯一的合約地址,並透過交易回執將合約地址給開發者。

「虛擬機器專欄」熟悉的新朋友 - 鏈上JVM

Java合約呼叫

開發者可以透過指定合約地址,並輸入合約方法名和引數,構造併發送一筆合約呼叫交易。區塊鏈平臺收到交易以後,獲取一個JVM例項,將合約地址對應的合約Jar中的類檔案載入JVM中,建立一個合約類的例項並呼叫指定方法,得到執行結果並透過交易回執返回給開發者。

「虛擬機器專欄」熟悉的新朋友 - 鏈上JVM

▲JVM接入區塊鏈

要實現一個Java智慧合約執行引擎,一定繞不開將JVM接入區塊鏈的問題。目前大部分割槽塊鏈系統使用Golang開發,而大部分開源的JVM通常是C++編寫。如果想要快速地將JVM接入到區塊鏈系統中,可以透過CGO將Golang和C++打通。但考慮到在區塊鏈系統中對JVM內部最佳化的需要,HVM選擇了透過Golang實現了JVM。雖然自己實現JVM會引入大量的開發成本,但是極大地方便了後續針對區塊鏈場景進行

效能最佳化

功能拓展

工作的開展。

“當區塊鏈中接入JVM後,還需要做些什麼讓JVM成為區塊鏈中的Java合約執行引擎呢?”

虛擬機器安全適配

前文中提到,我們在區塊鏈的Java合約引擎中支援使用者使用JDK中的類和方法。考慮到區塊鏈上的合約執行引擎需要滿足執行環境的隔離以及執行結果的確定性,我們需要對JDK和JVM進行安全適配。其中包括以下幾點:

1)

禁用”不安全”類和方法

:在智慧合約引擎中,可能引起執行結果不一致的方法是”不安全“的。比如Java中生成的隨機數方法,其執行結果是不確定的,區塊鏈中的Java合約引擎會禁用這些”不安全”的類和方法。

2)

隔離合約的執行環境

:區塊鏈平臺中的Java智慧合約需要一個隔離的執行環境,即Java智慧合約無法像普通的Java程式使用執行緒、網路、訪問系統時間等功能。此外,我們在JDK中實現了一部分與區塊鏈相關的方法,部分方法不允許被Java合約呼叫。因此,我們在HVM內部實現了方法呼叫過濾器,攔截不被允許的方法呼叫。

3)

確定邏輯執行順序

:同EVM一樣,我們在HVM內部實現了一套Gas機制,對合約執行進行代價計算。指令執行的不同,會引起不同節點計算的Gas值不同。在原始的JDK中,部分方法在兩次呼叫時,雖然其結果一致,其邏輯執行的程式碼路徑不同。以使用單例模式的類為例,首次呼叫這個類的例項方法時,需要建立這個類的例項;之後呼叫其方法時,不再需要建立例項。這種邏輯的差異,會導致新啟動的節點與其他節點的執行的Gas值不一致。因此,我們需要對JDK中這類邏輯進行適配,保證

邏輯

執行順序始終一致

賬本互動機制

將JVM接入區塊鏈,還需要保證合約與賬本資料互動的功能。EVM中存在賬本互動的指令,但是在JVM規範中不存在用於賬本互動的指令,所以我們需要提供一套賬本資料互動機制,讓Java智慧合約能夠操作區塊鏈上的賬本資料。

實現賬本互動機制可以有兩種方案:

1)在JVM中實現一套賬本互動的

自定義指令集

。同時提供一種Java合約的編譯器或外掛,在合約位元組碼中生成專用於區塊鏈中賬本互動的自定義指令。

2)在JDK中實現一套讀寫賬本資料的

工具類和方法

,在合約執行過程中,由合約執行引擎來呼叫這些方法,負責合約持久化欄位的讀寫操作。

HVM在實現的過程中,選擇了第二種方案。

在合約執行的過程中,如果使用到合約的持久化欄位,合約執行引擎會呼叫賬本讀取的方法從賬本中獲取其資料。對於賬本寫入操作,執行引擎會先進行快取,待合約執行結束後,掃描合約中有

資料

更新的持久化欄位,將欄位更新的

資料

統一刷入到賬本中。

相比指令的方法,使用Java方法來實現賬本資料互動的功能雖然會有更多的指令開銷,但是能夠為使用者提供

更友好地方式操作持久化欄位

。以Map為例,我們在Java智慧合約中為Map提供了除Get和Put以外的方法,允許使用者使用迭代器等方法方便地操作Map。考慮到讀寫Map的複雜場景,維護一個可靠的迭代器邏輯較為複雜。而以指令的方式操作賬本資料,那麼勢必要實現一套複雜的賬本互動指令集。顯然工具類和方法更適合完成這些複雜的邏輯操作,並更容易支援合約資料結構功能的拓展。

「虛擬機器專欄」熟悉的新朋友 - 鏈上JVM

透過這種方案,使用者在編寫Java智慧合約時,能夠

選用功能強大的資料結構類操作賬本

。這些資料結構類,將賬本互動的Java方法進行封裝,使使用者無法感知,並儘可能實現JDK中的介面。如HVMMap、HVMList等資料結構,分別實現了JDK中的Map和List介面,使用起來與JDK提供的其他Map、List幾乎一致。

虛擬機器對比分析

除了HVM合約以外,常見的合約還有EVM的Solidity合約、Fabric的Chaincode等等。

EVM提供了沙盒化的、完全隔離的合約執行環境。Solidity從設計初就作為智慧合約語言來考慮,其在賬本操作上有較大優勢。

Fabric的Chaincode支援多種語言編寫。Chaincode執行在一個受保護的Docker容器中,在接收到客戶端傳送的呼叫請求後,會在容器中模擬執行出對賬本的讀寫集並返回給客戶端,最後由客戶端再次發起將模擬交易產生讀寫集寫入賬本的請求。

HVM相比與其他的執行引擎,主要以下特性:

HVM合約是在安全的封閉式

沙箱

環境執行,安全性高

執行引擎內嵌於平臺,

無網路依賴

HVM提供完整的合約

生命週期管理機制

,只需透過sdk、api呼叫就可進行合約的升級

提供

豐富的內建功能

,例如日誌輸出、密碼套件、多樣化呼叫合約

除了Java語言JDK本身提供的功能外,HVM

提供多種基於區塊鏈賬本資料操作的資料結構

—— 小結

——

本文首先從開發者的角度,介紹Java智慧合約的開發及使用流程,再講解了在區塊鏈中接入JVM的技術方案,探討了對JDK的程式碼改造以及賬本互動機制的實現。

HVM始終向著更好的效能和更友好的使用體驗目標摸索前進。

與此同時,行業內的合約執行引擎正處於百花齊放的狀態,接下來我們還會對支援Rust等語言編寫智慧合約的FVM以及支援區塊鏈上SQL執行的KVSQL進行詳細介紹,敬請期待!

對於虛擬機器感

興趣的小夥伴,可以

新增小助手桔子(18458407117)加入技術交流群,歡迎您和我們共享觀點,共論區塊鏈的無限未來~

作者簡介

盧益

銘、姚兵

趣鏈科技基礎平臺

部區塊鏈

虛擬機器研究小組

參考文獻

[1] Java虛擬機器規範。