余 濤,牛保寧,樊 星
(太原理工大學 信息與計算機學院,山西 晉中 030600)
從中本聰描繪的比特幣[1],到Vitalik Buterin提出以太坊[2],再到Linux基金會發起的Hyperledger開源區塊鏈項目[3],區塊鏈技術逐步成熟和普及。Hyperledger Fabric與其它區塊鏈項目的技術類似,是一個使用智能合約、通過所有參與者共同管理交易的賬本系統,其主要的特點是私有和許可,因此更適用于企業級區塊鏈項目的開發。基于Fabric的區塊鏈系統,能有效解決目前以中心化模式為主的數據管理存在的問題,克服中心化系統的弊端,回避人為作惡的風險,使鏈上的參與方集體認定、共同維護同一賬本[4]。
區塊鏈的設計目的是在不可信、分布式的環境中進行安全、不可變的價值轉移。區塊鏈的本質可以理解為去中心化的數據庫,但是如果用傳統的數據庫標準來衡量區塊鏈,不管是在吞吐量、事務延遲、容量還是查詢能力上,區塊鏈的效果均顯不佳[5]。而區塊鏈的廣泛應用必然會要求對區塊鏈數據進行高效查詢。目前,區塊鏈查詢方面的研究大致有兩類:一類是通過區分記錄節點能力、優化查詢路徑解決泛洪循環和響應消息風暴等問題[6,7],這樣做并不能豐富區塊鏈的查詢功能;另一類是通過與數據庫連接,利用數據庫系統的查詢能力,豐富查詢功能,實現區塊鏈數據的高效查詢[5,8-11],但是,這一途徑存在數據庫中數據可篡改的問題。針對后一途徑存在的問題,本文將區塊鏈與關系型數據庫連接后,增加交易驗證機制,在保證數據不可篡改特性的前提下,實現區塊鏈豐富的查詢功能和高效的查詢。
本文的主要貢獻如下:
(1)針對區塊鏈查詢方面的不足,提出一種區塊鏈數據的關系查詢解決方案FabricSQL,將區塊鏈上的有效交易同步至SQL數據庫中,豐富區塊鏈系統的查詢功能,優化查詢方法;
(2)為增強用戶查詢的準確性,減少不必要的空間占用,通過偵聽每筆交易的狀態,實時同步區塊鏈上有效交易的信息,并將交易數據轉為SQL數據庫要求的格式存儲;
(3)為保證SQL數據庫的數據安全問題,提出一種交易數據存儲驗證機制,每筆交易數據對應一個哈希值,在存儲時生成,在訪問時驗證,保證交易數據的安全性。
在設計的實驗模型FabricSQL和Hyperledger Fabric區塊鏈系統上,進行多組查詢性能的對比實驗,結果表明FabricSQL在保證集體驗證維護、數據可回溯以及防篡改特性的同時,兼備關系型數據庫快速查詢、查詢功能豐富的特性。
隨著區塊鏈技術不斷發展應用,人們對于區塊鏈上數據查找速度和查找功能的要求隨之增加。針對區塊鏈查詢的研究,目前大致分為兩個方向:一是通過區分記錄或賦予節點不同的查詢能力,優化查詢路徑,實現區塊數據的有效查詢;二是將區塊鏈系統與數據庫結合,實現查詢功能優化。
首先,在第一種研究中,賈大宇等[6,7]在ElasticChain模型基礎上,提出一種新的容量可擴展區塊鏈系統的高效查詢方法ElasticQM,在用戶層、查詢層、存儲層和數據層實現創新優化,通過在用戶層設置數據緩存模塊,在查詢層增加超級節點、查詢葉子節點和查詢驗證節點3種角色,在數據層結合平衡二叉樹和梅克爾樹的各自特點建立基于B-M樹的區塊鏈存儲結構,提高查詢效率。
Tuan等[12]提出了Blockbench,可以對集成的私有區塊鏈系統的整體和組件的性能進行評估,并幫助他們識別和改進性能瓶頸。另外,Blockbench對3種主要的區塊鏈系統:Ethereum,Parity和Hyperledger進行全面分析,結果表明,這些系統在傳統的數據處理工作負載中還遠不能取代現有的數據庫系統。
在第二種研究中,McConaghy等[5]發布的BigchainDB是一個區塊鏈數據庫,其設計是從分布式數據庫開始,使BigchainDB繼承現代分布式數據庫高吞吐量、低延遲、大容量、豐富的查詢功能等特征的同時,通過增加區塊鏈去中心化、不可篡改和數字資產創建以及傳輸的特性,使它具有數據庫和區塊鏈的優良屬性。2018年BigchainDB 2.0[8]發布,網絡中的每個節點都有自己本地MongoDB數據庫,并且引入拜占庭容錯機制,允許網絡中即使有1/3的節點失敗,也能夠達成一致意見繼續進行。Bartoletti等[9]提出區塊鏈分析的通用框架,支持對比特幣和以太坊兩種加密貨幣進行數據分析,框架允許將相關的區塊鏈數據與從外部源檢索的數據集成在一起,并將它們組織到一個數據庫中,再用數據庫管理系統的查詢語言進行分析,文獻通過一系列用例包括分析區塊鏈元數據、按日期劃分的交易數量、交易費和地址標簽說明框架支持的不同功能。Li Yang等[10]提出EtherQL,是為Ethereum開發的一個高效查詢層,由同步管理器、鏈處理、持久化框架和開發者接口4個模塊組成。EtherQL通過內置的Ethereum客戶端實時同步來自Ethereum公共網絡的區塊鏈數據,并將其存儲在MongoDB數據庫中,提供的接口支持擴展查詢、范圍查詢和top-k查詢等分析查詢。北京眾享比特科技有限公司提出ChainSQL[11],通過構建Ripple與普通數據庫結合的區塊鏈數據庫,實現先入庫再共識的方法,將操作以交易的形式記錄在區塊鏈網絡中,而真實數據在數據庫中查看,如果共識不能通過,則回滾數據庫操作,增加數據入庫的速度。
本文所提出的FabricSQL方法與其它研究相比,是針對聯盟鏈Fabric實現的一種區塊鏈數據關系查詢解決方案,且設計相應的模塊解決其它研究中未能解決的數據庫中數據易被篡改的問題。
Hyperledger Fabric在一個僅追加復制的賬本數據結構中安全地跟蹤其執行歷史,沒有內置的加密貨幣,且具有高度的模塊化,將共識、執行和驗證過程完全分離[13]。在Fabric網絡中,節點是通信的主體,包括客戶端節點、CA節點、peer節點和排序服務節點,鏈上的節點共同維護同一賬本。
Hyperledger Fabric交易流程如圖1所示,交易是由客戶端發起的,客戶端通過SDK調用CA服務,交易提案經SDK創建后,發送給背書節點,背書節點驗證簽名并確定提交者是否有權執行操作,同時調用鏈碼并將鏈碼的模擬執行結果等提案響應返回給客戶端,客戶端判斷執行結果是否一致以及背書策略是否滿足,再將交易提案、模擬執行結果、背書信息封裝為一個交易,簽名后一并發給排序服務節點,排序服務節點將交易排序并將生成的區塊發送至提交節點,提交節點驗證交易的有效性,通過驗證的區塊會被追加到區塊鏈上,與之相關的狀態數據庫也會進行更新。

圖1 Hyperledger Fabric交易流程
Hyperledger Fabric的存儲系統由普通的文件和key-value數據庫組成。每個區塊的區塊頭和所有交易數據以二進制形式寫入blockfile文件中,并將區塊和交易在blockfile中的索引以key-value的形式保存。歷史數據和區塊索引均存儲在LevelDB數據庫中。而狀態數據庫記錄最新的交易執行結果,是所有狀態的最新值,支持LevelDB和CouchDB數據庫。在查詢賬本數據時,從索引數據庫中獲得文件位置指針,再通過文件位置指針獲取所需的數據。
Hyperledger Fabric中包括賬本數據、索引數據、歷史數據和狀態數據等,各種數據的存儲方式不同,即便是基于鍵值對的存儲方式其操作管理的方法也大不相同,在區塊提交時,各類存儲操作順序執行,極有可能發生中斷或出錯等情況。而且由于數據的存儲結構受限導致區塊鏈僅支持簡單和有限的查詢。在用戶提出查詢請求后,只能通過預先定義的key進行查詢,難以實現復雜的查詢功能,無法滿足用戶豐富的需求。
從應用開發者角度考慮,區塊鏈沒有標準的查詢語言,如果開發人員對區塊鏈的內部數據組織方式、存儲結構沒有較好的理解,將增大數據查詢的難度。當用戶的需求發生變更時,需要更改鏈碼操作。
本章介紹FabricSQL具體細節。3.1節討論提出FabricSQL的思路,3.2節給出FabricSQL的總體架構,3.3節、3.4節分別討論重要模塊的技術細節。
針對區塊鏈查詢方面存在的不足,本文將Fabric與關系型數據庫MySQL結合,提出區塊鏈數據的關系查詢解決方案FabricSQL,從而解決Fabric中各類數據存儲方式復雜、查詢功能有限以及需求變更難以實現等問題。但是,將數據從區塊鏈同步存儲至數據庫的同時,需要解決下面的問題:首先,區塊鏈中存在的無效交易如果直接同步至數據庫中,會對查詢結果的正確性產生干擾,這里的無效交易是指當區塊發送至提交節點后,提交節點會按順序對塊中的交易進行背書策略和讀寫沖突檢查,將不滿足背書策略和版本不匹配的交易標記為無效,但是所有有效和無效的交易最終都會追加至區塊鏈上;其次,由于數據庫本身安全能力有限,在使用過程中會不可避免暴露數據接口,被外部作惡者通過技術手段篡改數據的案例比比皆是,同時在使用過程中管理員的權限不可控制,存在著不信任因素,因此數據庫容易被作惡者篡改的情況,會對數據庫中數據的安全性產生影響。
針對上述問題,首先通過增加對交易狀態的偵聽,將有效交易同步存儲至數據庫中,從而保證存儲數據的正確性。另外提出交易數據的存儲驗證機制,在MySQL數據庫中,存儲和驗證數據時運用加鹽思想,即在經過哈希后的每筆交易數據的特定位置增加特定的字符串Salt,從而改變原始的字符串,實現數據加密,這樣即使知道原有的交易信息,在不知道Salt的情況下,也會增加一定的破解負擔;同時借鑒區塊鏈前哈希的思想,將交易生成的哈希值依序咬合,生成最終的交易哈希值存儲在數據庫中。當用戶發出數據請求時,首先完成對交易數據的一致性校驗,然后返回給用戶數據和校驗結果,從而保證數據的安全性。
FabricSQL由應用層、網絡層、數據處理層和存儲層4個層次構成。系統架構圖如圖2所示。

圖2 FabricSQL系統架構
應用層負責與區塊鏈網絡交互和查詢邏輯的實現,包括交互模塊、查詢模塊和校驗模塊。交互模塊包含與區塊鏈網絡交互的SDK程序在內的應用程序。查詢模塊在收到用戶查詢申請后,與存儲層交互。校驗模塊對查詢模塊的返回值進行一致性校驗,通過驗證的結果返回給交互模塊。
網絡層由排序服務節點、peer節點、CA節點構成。由于區塊鏈數據的關系查詢模型FabricSQL是在Hyperledger Fabric系統的基礎上實現的,所以,網絡層的結構保持不變。
數據處理層包括有效交易獲取模塊和數據處理模塊,負責組織區塊鏈上的有效交易數據,并轉換為可存儲在SQL數據庫中的關系型數據。
存儲層由兩部分組成,分別是存儲區塊鏈信息的普通文件和存儲由數據處理層輸出的交易數據的MySQL數據庫,它們存儲著驗證通過的每筆交易信息,不同點是,SQL數據庫只存儲有效交易。
FabricSQL的交易數據同步處理模塊在對區塊鏈有效交易信息判斷、同步和提取后,處理成SQL數據庫要求的格式存儲。FabricSQL系統模型如圖3所示,一條設備資產的交易信息在區塊鏈網絡中經過背書、打包、成塊和驗證后寫入區塊鏈中,其數據源是用戶提交的原始數據,經過SDK程序,實現對Fabric-CA節點和Fabric網絡的訪問。在完成區塊上鏈后,Fabric會發出特定的event來協助客戶端程序,客戶端通過SDK捕獲event事件,獲取交易信息的偵聽狀態,并將其提供給數據處理模塊處理其中的有效交易,最終將有效交易的數據存儲在MySQL數據庫中。

圖3 FabricSQL系統模型
FabricSQL在區塊鏈網絡中的交易過程如算法1所示,首先判斷用戶的身份證書,確定用戶注冊信息,然后連接區塊鏈網絡,當交易被認可,成功發送給排序服務節點前,需要注冊偵聽器。偵聽器存在的目的是檢測交易狀態,因為區塊鏈上的交易數據包括有效交易和無效交易,如果直接將區塊鏈上的所有交易數據直接同步至SQL數據庫中,不僅會增加存儲負擔,還會對查詢結果的正確性產生直接影響。最后,當包含交易的塊被提交至區塊鏈時,已注冊的偵聽器會被觸發。
算法1:FabricSQL在區塊鏈網絡中的交易過程
輸入:用戶提交的原始交易數據
輸出:交易上鏈,觸發偵聽器
(1)try {
(2) wallet = new FileSystemWallet(walletPath)
(3) if (!wallet.exists(user)) {
(4) return }
(5) 連接區塊鏈網絡,加入通道,調用鏈碼
(6) transaction=
contract.createTransaction(′transferDevice′)
(7) //完成偵聽器的注冊功能
(8) transaction.addCommitListener({callback
function: Data2SQL})
(9) transaction.submit(transaction args)
(10) 斷開區塊鏈網絡連接}
(11)catch{異常處理}
數據處理層,在偵聽器觸發后,執行回調函數Data2SQL,通過對交易狀態分析,返回所需的目標交易。所以,本模塊以區塊中的每筆交易作為一個處理單元,將有效交易的信息進行提取、分解,處理成不同的數據格式傳遞至后續的存儲層模塊。FabricSQL的數據處理過程如算法2所示。
算法2:FabricSQL數據處理過程
輸入:鏈上的每筆交易數據
輸出:每筆有效交易數據
(1)function Data2SQL(error, transId, status, blockNumber) {
(2) if status != VALID:
(3) return
(4) result = 由transId定位的交易信息
(5) obj=JSON.parse(result.transactionEnve-lope.payload.data)
(6) trans_time=result.transactionEnvelope.pay-load.Header.channel_header.timestamp
(7) data=obj[′senderID′,′receiverID′,′trans_time′,′deviceID′,′transId′, ′blockNumber′]
(8) insertData(data)
(9)}
FabricSQL的交易數據存儲驗證機制是在MySQL數據庫中利用Salthash值,實現對交易數據的存儲和驗證。Salthash是指對每筆交易數據進行散列后,在數據的任意固定位置插入特定的字符串Salt,再進行散列操作,這樣可以極大地降低數據被篡改的風險。
在FabricSQL存儲層中的區塊鏈文件系統和關系型數據庫MySQL都存儲著驗證通過的交易數據,不同點是,SQL數據庫中只存儲有效交易的信息。當交易數據傳至SQL數據庫時,每條交易數據順序追加,更新交易表和哈希表。在SQL數據庫中,交易表各字段的值記錄著每筆交易的重要信息,哈希表存儲著每筆交易的Salthash值,如式(1)所示,它是將Salt值、上一筆交易的Salthash值和此筆交易的哈希值相組合,并使用SHA256加密算法對其散列,得到的散列值即為此筆交易的最終哈希值。如果為第一筆交易,Salthash值是Salt值和此筆交易信息的哈希值組合哈希后的結果。FabricSQL在MySQL數據庫存儲數據的過程如算法3所示,首先與數據庫建立連接,然后將數據分別插入到對應表中
cur_Salthash=sha256(Salt+pre_Salthash+
sha256(transdata))
(1)
算法3:FabricSQL在MySQL數據庫中存儲數據的過程
輸入:每筆有效交易數據
輸出:數據存儲在MySQL數據庫中
(1)function insertData(data){
(2) 連接MySQL數據庫
(3) connection.execute(
′insert into t_transactions values(?)′, data)
(4) //pre_Salthash指上一筆交易的Salthash值
(5) pre_Salthash = connection.execute(
′select Salthash from t_hash order by tid
desc limit 1′)
(6) //cur_Salthash指當前交易的Salthash值
(7) cur_Salthash=sha256(pre_Salthash+Salt
+sha256(transdata))
(8) connection.execute(′insert into t_hash
values(?)′, (transId, cur_Salthash))
(9) 斷開連接
(10)}
為防止數據發生更改的情況,數據庫中不會存儲Salt值。Salthash值之間的連接方式也使得有一筆交易發生篡改時,作惡者需要更改這條交易之后的所有交易的Salthash值,這必然會提高作惡的成本。所以,Salthash值的存儲和連接方式,實現交易數據不可篡改的特性。SQL數據庫中數據存儲的流程如圖4所示。

圖4 MySQL數據庫中數據存儲的流程
應用層除了完成與區塊鏈網絡的交互,也負責查詢邏輯的實現。數據查詢校驗的流程如圖5所示。當收到用戶的查詢申請后,查詢模塊向存儲層提交查詢請求,存儲層將交易表各字段的值和哈希表中上一筆交易的pre_Salthash值,返回給校驗模塊,校驗模塊將返回值與Salt值相組合,使用SHA256加密算法對其散列,再將得到的散列值與哈希表返回的此筆交易的cur_Salthash值進行比較,如果校驗結果一致,將查詢結果返回給交互模塊,如果校驗結果不一致,說明SQL數據庫中的數據有被作惡者篡改的可能,返回的數據結果不可信。如果是數據庫中的第一筆交易,驗證原理一致,只是不需要加入pre_Salthash值進行驗證。當要查看用戶或資產的詳細信息時,交易表會關聯用戶數據表和資產數據表,返回用戶所需的全部信息。
為了更好地進行對比實驗,分別搭建了Hyperledger Fabric區塊鏈系統以及本文所設計的FabricSQL系統。在實驗中,Hyperledger Fabric區塊鏈系統選用相比LevelDB而言,查詢功能更加豐富的CouchDB數據庫作為原區塊鏈的狀態數據庫,FabricSQL選擇MySQL作為查詢數據庫,雖然CouchDB支持原生的json和字節數組的操作,但是相

圖5 數據查詢校驗流程
較而言,關系型數據庫只需要一條簡單的語句就可以實現復雜和豐富的查詢,查詢功能的可擴展性強,可以更好的對數據進行分析,滿足用戶的需求。
4.2.1 實驗環境和實驗數據
實驗的開發環境為Intel Core i5-3210M 2.50 GHz CPU和12 GB內存的PC機。利用VMware Workstation14.1.2建立虛擬機,以模擬真實節點,每個節點為內存1 GB硬盤大小為20 GB的ubuntu16.04系統。其中,Fabric系統,利用IBM的Hyperledger Fabric v1.4.0(https://github.com/hyperledger/fabric.git)開源項目搭建環境,使用Go語言編寫Chaincode,使用Node.js語言編寫用于交互操作的SDK程序,包括用戶注冊、交易創建和交易查詢等功能;FabricSQL系統在硬件方面與Fabric系統相同,仍在同一計算機上使用相同的VMware軟件模擬設備結點,每個結點所擁有的計算資源和存儲資源均與Fabric系統的資源相同,保證兩組實驗的硬件資源并無差異。特殊的是,FabricSQL添加了獨立的數據庫結點并在SDK程序中,增加對交易狀態判斷、有效交易提取和驗證等功能,還針對MySQL數據庫開發相應的工具程序用于實現數據庫相關的增刪查改等一系列基本操作。
本實驗的數據集來自設備資產管理數據(https://github.com/Y-tao/FabricSQL),共6萬用戶,約25萬條交易數據,區塊鏈上已完成的交易數據量大小為1 GB。
4.2.2 實驗分析
在FabricSQL和Fabric系統上分別進行多組對照實驗,通過查詢數據,對比分析FabricSQL模型的防篡改能力、查詢效率等多項性能。
實驗1:在FabricSQL上,不經過更改數據的正確流程,手動惡意篡改數據庫內的多項原始實驗數據,然后進行正常的查詢操作,測試FabricSQL模型的防篡改能力是否有效。
防篡改測試方案和結果如圖6所示,當更改一筆設備的擁有者后,執行查詢操作,因為一致性校驗無法通過,發現篡改,所以會有錯誤提示。而且,在SQL數據庫的哈希表中,Salthash值首尾相連,如果中間有改動,必然會對后面的數據產生影響。通過實驗結果可以發現,FabricSQL具有良好的防篡改能力。

圖6 FabricSQL防篡改測試
實驗2:在FabricSQL和基于Fabric的區塊鏈系統上分別錄入相同的原始數據,然后分別查詢一筆交易的響應時間,進行對照實驗。再通過更改交易量的規模,觀察分析FabricSQL模型在不同數據基數上的查詢效率及是否比區塊鏈系統的原始查詢操作有所優化。
狀態數據查詢響應時間如圖7所示,由于單個查詢以毫秒為單位完成,為了最小化隨機錯誤的影響,實驗中查詢時間是1000個獨立查詢的平均時間。圖中橫坐標為已上鏈的交易數據量大小,分別為500 M和1000 M,縱坐標是以10為基數的對數刻度,反映Fabric和FabricSQL進行查詢操作的響應時間,FabricSQL的查詢時間中已包含對每筆交易的安全性進行驗證的時間代價。通過對實驗結果分析,可以看出FabricSQL的查詢效率比區塊鏈系統的原始查詢效率有顯著提升。

圖7 狀態數據的查詢時間
實驗3:在設計的實驗模型和基于Fabric的區塊鏈系統上,基于相同版本號的多條歷史交易數據,分別進行溯源查詢操作。再通過更改交易的版本號,觀察分析FabricSQL模型在不同版本號下的查詢效率及是否比區塊鏈系統的溯源查詢有所優化。
歷史數據查詢時間如圖8所示,在數據庫中按照不同的版本號篩選出候選數據,在候選數據中隨機查詢5個設備,計算平均查詢時間。實驗中,分別在FabricSQL和Fabric上對版本號為10,20,30,40,50的交易數據進行溯源查詢,通過對實驗結果分析,可以看出FabricSQL比區塊鏈系統的溯源查詢效率有顯著提升,且查詢代價主要集中于最新版本的查詢時間。

圖8 歷史數據的查詢時間
Hyperledger Fabric通過文件系統和key-value數據庫實現對區塊鏈數據的查詢,但是存在著對其存儲數據的訪問方法支持有限、查詢功能單一且查詢功能的可擴展性不強、查詢效率較低等問題。本文針對區塊鏈在查詢方面的不足,提出一種區塊鏈數據的關系查詢解決方案FabricSQL,該方案在區塊鏈網絡中完成對交易數據驗證和更新后,根據返回的事件狀態提取其中有效交易的數據,并將其按照防篡改方案存儲至SQL數據庫中,依據存儲驗證機制實現對區塊鏈數據的關系查詢。在實驗模型和Hyperledger Fabric上進行多組查詢性能的對比實驗結果表明,本文提出的區塊鏈數據的關系查詢解決方案FabricSQL具有豐富的查詢功能、良好的防篡改性能以及高效的查詢效率。
區塊鏈的廣泛應用需要良好的查詢性能支持,后續還需要與其它區塊鏈數據庫方案在防篡改能力、空間復雜度和時間復雜度等方面進行比較,從而改進實驗方法,優化FabricSQL方案。