趙羽龍,牛保寧,李 鵬,樊 星
(太原理工大學信息與計算機學院太原030600)
(?通信作者電子郵箱niubaoning@tyut.edu.cn)
區(qū)塊鏈技術由于其不可篡改、可追溯、去中心化等特性逐漸得到廣泛的關注。它最早起源于中本聰的比特幣白皮書[1],在數字加密貨幣[1]、供應鏈金融[2]、數據公證[3]、資源共享[4]等領域有許多的應用場景。區(qū)塊鏈使用鏈式的結構和一致性協議保證區(qū)塊數據不可篡改和可追溯,但無休止的數據追加對單個節(jié)點的存儲造成很大壓力。采用完全副本(每個節(jié)點保存一份)的數據存儲方式,對系統(tǒng)存儲空間也造成很大浪費。
以比特幣為例,截至2019 年3 月27 日,共產生569 001 個區(qū)塊、17 612 496個比特幣,總交易量395 438 152筆,數據總容量196.15 GB,鏈上認證地址49 245 944,市值近5 000 億[5]。據BitNodes[6]統(tǒng)計,全網使用70001 協議(>=Satoshi:0.8.x)同時在線的全節(jié)點有近10 000個。單個節(jié)點需要的磁盤空間約200 GB,每個節(jié)點保存一份,那么保守的估計整個系統(tǒng)需要2 PB 的存儲容量來存儲區(qū)塊數據,而且每年還以線性的速度增長。
SPV(Simplified Payment Verification)節(jié)點模型[1]不存儲區(qū)塊鏈交易數據,只具有錢包功能,可以減輕存儲壓力;但減弱節(jié)點間的對等性,使得系統(tǒng)日趨中心化。全節(jié)點存儲全部的區(qū)塊數據,可以驗證交易(挖礦),為其他節(jié)點提供數據,具有完備的節(jié)點功能。針對存儲資源較少的設備,比特幣白皮書中介紹了SPV節(jié)點,它在初始化同步過程中只下載區(qū)塊頭,然后根據自身需要從全節(jié)點請求數據。這種節(jié)點所需的存儲大小只與區(qū)塊高度成線性關系,與區(qū)塊大小無關。每個區(qū)塊頭80 B,一年僅需4.2 MB 的空間,極大地減輕了存儲壓力。但這種節(jié)點完全依賴于全節(jié)點,無法驗證交易,容易遭受拒絕服務攻擊[7]、女巫攻擊[8]等安全性問題。隨著數據量的增加,SPV 節(jié)點增多,全節(jié)點個數減少,區(qū)塊鏈系統(tǒng)的去中心化程度減弱,數據安全性、穩(wěn)定性下降。SPV 節(jié)點減少了數據存儲,但是增大了網絡帶寬壓力,在數據存儲和數據共享方面對系統(tǒng)沒有貢獻。
本文提出一種增強型輕量級節(jié)點模型ESPV(Enhanced SPV):采用完全副本方式保存新區(qū)塊(最近產生的n個區(qū)塊),讓輕量級節(jié)點具有交易驗證功能;同時把舊區(qū)塊(新區(qū)塊之前的區(qū)塊)進行分片存儲,降低數據的冗余度;并且創(chuàng)建分級區(qū)塊分區(qū)路由表,加快數據檢索的速度,保證數據的可用性。
本文的主要工作為:
1)提出增強型輕量級節(jié)點模型ESPV,使輕量級節(jié)點可以驗證交易,具有完整的節(jié)點功能,增強節(jié)點間的對等關系,保障區(qū)塊鏈系統(tǒng)的去中心化、穩(wěn)定性和安全性
2)在確保數據的可靠性和可用性的前提下對舊區(qū)塊進行分片存儲,減少存儲空間浪費,增強系統(tǒng)的可擴展性;保存完整的區(qū)塊頭數據,保障系統(tǒng)中區(qū)塊數據的真實性。
3)提出適合ESPV 存儲特征的路由表,既提高了數據查找效率,又達到負載均衡的作用,避免全節(jié)點壓力過大的問題。
比特幣網絡中的節(jié)點模型主要包括全節(jié)點和SPV 節(jié)點,它們具有不同的功能和機制。全節(jié)點[1]是第一個也是最安全的節(jié)點模型,它通過下載和驗證從創(chuàng)世塊到最近發(fā)現的區(qū)塊來確保區(qū)塊鏈的有效性,可以獨立地共享數據和驗證交易。SPV 節(jié)點只保存區(qū)塊頭數據,僅可以驗證支付,不能驗證交易(挖礦)。驗證支付時,SPV 節(jié)點需要依賴從全節(jié)點拉取符合布隆過濾器條件的MerkleBlock 消息[9],通過其中的Merkle 樹的哈希認證路徑,判斷目標交易是否在該塊中;同時,利用區(qū)塊頭檢測該塊是否在鏈中已被壓入足夠的深度,來確認交易是否成功。Delgado-Segura 等[10]對比特幣的UTXO(Unspent Transaction Output)數據進行了分析,發(fā)現大部分UTXO 產生于最近的少部分區(qū)塊中。
在簡化單節(jié)點數據存儲方面,目前主要有區(qū)塊修剪、副本策略、糾刪碼技術、共識單元等解決方案。Bitcoin-core[11]提出一種區(qū)塊修剪策略,下載的區(qū)塊數據構建完UTXO 集后就可以刪除,極大地減少節(jié)點所需的存儲空間。但隨著修剪策略的流行,系統(tǒng)中區(qū)塊數據的可靠性會下降。Jia 等[12]提出一種存儲可擴展性模型,將區(qū)塊鏈中的區(qū)塊數據保存在一定比例的網絡節(jié)點中,增加了額外的兩條鏈,在減少存儲空間的同時也增加了系統(tǒng)復雜性。Dai 等[13]提出一種低存儲要求的區(qū)塊鏈存儲框架,使用糾刪碼技術[14]對區(qū)塊數據進行分塊存儲,降低單節(jié)點的存儲和帶寬壓力,增加了節(jié)點的計算量。Xu等[15]提出共識單元的方法,讓節(jié)點形成社區(qū),在社區(qū)內自治式分片存儲區(qū)塊數據,但僅針對私有鏈,對公有鏈存在查詢開銷太大的問題。本文僅在單節(jié)點中維護分片信息,建立路由表,采樣處理數據,系統(tǒng)復雜度和計算量都比較小,且適用于公有鏈。
P2P(Peer-to-Peer)網絡[16]中節(jié)點具有不同的類型和數據存儲狀況,為了加快數據的檢索,通常會建立集中式或基于DHT(Distributed Hash Table)[17]的分散式路由表。集中式的路由表適合于網絡節(jié)點數目較少的情況[18],網絡中的節(jié)點在搜索數據時首先向路由中心請求數據所在位置,在得到目標節(jié)點的位置后它與目標節(jié)點單獨進行聯系。系統(tǒng)的響應時間短,數據可用性強,但中心服務器壓力較大,存在單點故障問題?;贒HT技術的路由表查找算法性能為log N[19],進行了負載均衡,適用于較大規(guī)模的節(jié)點網絡,不存在單點故障問題。它是基于內容的查找方式,可以直接找到每個小數據分片的位置,同時也都需要維護一份索引數據,導致整個索引表很大,數據更新維護的成本高。
由前兩章內容可知,完備的節(jié)點功能包括交易驗證(挖礦)、數據存儲和數據共享。為了讓節(jié)點功能完整,增強型輕量級節(jié)點模型的設計也從這三部分出發(fā)。SPV 節(jié)點為減少數據存儲不再保存完整的區(qū)塊數據,也不能進行挖礦,致使其對全節(jié)點產生嚴重的依賴,節(jié)點之間的關系不再對等。同時,比特幣中每一筆交易的輸入為歷史交易的輸出或者為coinbase交易,即挖礦獎勵。在進行交易驗證時需要追溯到交易輸入中的每個交易,而且大部分的交易輸入都集中在后面生成的區(qū)塊中。于是我們構想是否可以通過保存最近生成的部分區(qū)塊數據(新區(qū)塊),讓輕量級節(jié)點可以驗證大部分交易,具有挖礦功能。而對于舊區(qū)塊,主要用途是構建完整的UTXO 庫,請求量較少且不會發(fā)生更改,因此,不需要全部冗余保存,可以采用數據分片技術,降低數據的冗余度,減少存儲空間浪費。舊區(qū)塊分片保存后,為了保證數據可用性,可以通過設計適當的路由機制,加快數據檢索速度。
如圖1 所示,本文對高度為567 301~568 201 的區(qū)塊進行固定間隔采樣,查詢向前追溯一定塊數范圍時可以驗證當前區(qū)塊中交易的比率,即通過向前遍歷區(qū)塊,查找其中是否包含該區(qū)塊中交易的輸入??梢园l(fā)現僅需保存少量最新的區(qū)塊就可以驗證較高比例的交易。于是本文針對比特幣的交易特性和現有節(jié)點模型存在的問題,提出增強型輕量級節(jié)點模型。模型的核心思想是區(qū)別對待新區(qū)塊和舊區(qū)塊,對新區(qū)塊進行完全副本存儲,對舊區(qū)塊進行分片存儲,采用不同的存儲策略,為輕量級節(jié)點增加交易驗證的功能,提高系統(tǒng)在存儲方面的可擴展性,維護節(jié)點之間的對等性,保障系統(tǒng)的去中心化程度和穩(wěn)定性。
網絡中的節(jié)點對于新區(qū)塊的請求量較大,為網絡帶寬型。網絡中的全節(jié)點需要同步最新的區(qū)塊數據,參與挖礦的節(jié)點也想盡早獲取最新的區(qū)塊數據,在它之上開始挖礦以更大概率地獲取區(qū)塊獎勵。SPV 節(jié)點需要同步其區(qū)塊頭來完成支付驗證。這是因為比特幣采用鏈式的追加模式,每筆交易的成功需要確保其被打包在區(qū)塊中,連接上鏈,且在該區(qū)塊之上有不小于6塊新區(qū)塊的確認。
根據新區(qū)塊的網絡特性,ESPV采用完全冗余的存儲策略來保存新區(qū)塊數據,即保存一定窗口大小的新區(qū)塊數據。這樣可以為其他節(jié)點提供數據共享服務,減少全節(jié)點帶寬壓力,增加系統(tǒng)的穩(wěn)定性。
節(jié)點在初始化時首先查詢最新的區(qū)塊高度h,然后從網絡中下載區(qū)塊高度為h - 3 000 到h 的區(qū)塊數據,同時構建UTXO 庫。在進行交易驗證時如果未在UTXO 庫中發(fā)現交易的輸入,那么將此交易轉發(fā)給全節(jié)點。由圖1 可知這樣可以驗證大部分的交易,當已驗證的交易數目足夠多時,對應的區(qū)塊大小會達到系統(tǒng)設定的最大閾值進而可以將它們打包成塊開始挖礦計算。
目前區(qū)塊交易數目正以線性的速率增長,為保證系統(tǒng)的可用性,ESPV 設計了相應的動態(tài)調整策略。從圖1 可知,交易的驗證率隨著新區(qū)塊數的增長而增長,據此我們展開相應的設計。與挖礦難度值調整周期相同,ESPV 也采用每2 周進行一次調整。比特幣系統(tǒng)平均10 min 生成一個區(qū)塊,則每2 016 塊區(qū)塊就需要進行一次調整。節(jié)點需要記錄上次調整的區(qū)塊高度,并以此為起點直到之后產生2 016塊數據。在這2 016 塊中隨機采樣40 塊區(qū)塊,如果這些區(qū)塊在其前3 000 塊區(qū)塊中可驗證交易數低于80%的區(qū)塊數大于4,則為新區(qū)塊存儲區(qū)塊數n 加32;如果可驗證比率超過95%的區(qū)塊數大于32,則n減32;否則n不發(fā)生改變。這里的32是由現有區(qū)塊數和能保證較高比例交易驗證率時所需的最新區(qū)塊數按時間增長比率得出,較為合適。這些具體的參數都可以進行自定義配置,以適應不同節(jié)點的硬件環(huán)境和需求。
圖2 增強型輕量級節(jié)點模型Fig. 2 Enhanced lightweight node model
系統(tǒng)對舊區(qū)塊的請求量較小,為非帶寬型。只有當網絡中有新的全節(jié)點加入或者重新構建全節(jié)點時,才需要拉取它們。這是因為其使用類似日志的形式,一旦生成就已經成為不會發(fā)生更改的歷史數據,節(jié)點無須重復獲取它們。在全節(jié)點進行驗證交易時,需要從創(chuàng)世區(qū)塊到最新產生的區(qū)塊之中構建出完整的UTXO 集,從中查找交易的輸入,確保它是未花費的,余額大于等于支出花費,且驗證簽名確認資產所屬權,所以舊區(qū)塊的可靠性和可用性對于整個系統(tǒng)來說是十分重要的。
考慮到舊區(qū)塊的訪問特性,ESPV對其采用分片存儲的方式,即每個節(jié)點保存部分歷史區(qū)塊數據。這使得每個節(jié)點的存儲壓力變小,減少系統(tǒng)對存儲空間的浪費,增加系統(tǒng)的可擴展性。
本文使用開源項目Bitnodes 對比特幣網絡中的全節(jié)點數據進行了統(tǒng)計分析。截至2019 年4 月10 日,近兩年內比特幣使用70001 版本協議的全節(jié)點同時在線的個數中最大值為12 770,最小值為6 671,平均值為9 931[6];并且同時在線的節(jié)點個數具有一定的穩(wěn)定性。由此本文對節(jié)點的可靠度進行了統(tǒng)計,可得圖3。在P2P系統(tǒng)中,可靠性關系[20]為:
其中:a為系統(tǒng)可靠度;p為節(jié)點可靠度;r為副本數??山獾?
r = log(1- a) log(1- p)
根據Borel 定律[21]定義低于10-50的概率都是不可能的。故設
a = 1- 10-50
根據圖3可以保守估計節(jié)點可靠度p=0.1,由此可以計算出r約為1 000。
圖3 節(jié)點可靠性Fig. 3 Node reliability
由于比特幣系統(tǒng)中區(qū)塊大小是分布不均勻的[5],且節(jié)點通常需要獲取連續(xù)的區(qū)塊數據,所以進行分片時采用連續(xù)、固定存儲空間大小的方式較為合適。根據現有數據存儲情況進行分析,可設置一個分片的大小為5 GB。為更好地適應節(jié)點間不同的存儲空間差異,對舊區(qū)塊制定不同的初始分片大小,即小、中、大3 種,對應的分片個數為4、8、12。節(jié)點在接收到區(qū)塊時需要統(tǒng)計其大小,并記錄系統(tǒng)區(qū)塊分片的起始和終止區(qū)塊高度,將這些高度值添加入到一個數組中,定義為分片錨定高度集,這些值將不會發(fā)生改變。每個節(jié)點在加入P2P 網絡或者進行數據的擴充和刪減時都以這些固定的區(qū)塊高度為界限。在節(jié)點加入網絡時,節(jié)點產生一個從0 到最新區(qū)塊高度的隨機數,以分片錨定高度集中離這個隨機數最近的高度值作為其數據存儲的起始高度,根據其可用空間的大小保存對應級別的分片數目。
假設整個系統(tǒng)中種子節(jié)點和礦池等性能良好、存儲空間充足、穩(wěn)定性強的節(jié)點運行全節(jié)點,其他硬件等條件受限的節(jié)點運行ESPV 節(jié)點,這樣系統(tǒng)中區(qū)塊數據的可靠性和可用性具有基礎的保障。目前完整的區(qū)塊數據量在線性地增長,為保障系統(tǒng)的可用性每年需要將初始分片大小加1,已經加入的節(jié)點向后延伸一個分片。
為了激勵節(jié)點盡可能多地保存區(qū)塊數據,ESPV對存儲量不同的節(jié)點請求設置不同的優(yōu)先級,在節(jié)點內部通過獲取節(jié)點分片屬性進行請求隊列排序,存儲數據較多的節(jié)點優(yōu)先得到請求回復。
結合舊區(qū)塊的存儲策略,ESPV 設計了新的路由機制:分級區(qū)塊分區(qū)路由表。根據節(jié)點存儲分片的大小,構建4 個區(qū)塊分區(qū)路由表,分別為小、中、大、全節(jié)點路由表。路由表以Map 形式存儲,key 為分片起始塊號,value 是節(jié)點數組,每個節(jié)點為ip:port。
查找指定高度區(qū)塊所在節(jié)點時,需要在分片錨定高度集中找到離它最近的分片起始塊號h。之后依次按小、中、大、全節(jié)點路由表查詢key 為h 的節(jié)點列表。根據獲取的節(jié)點列表長度L,產生從0~L 的隨機數N。把節(jié)點列表中第N 個元素作為起始節(jié)點依次嘗試連接節(jié)點:如果在小路由表中未找到連通的節(jié)點則繼續(xù)向下,從中路由表中進行查找;如果找到目標節(jié)點則終止查詢,向目標節(jié)點發(fā)起請求。為加快查詢,將小、中、大路由表嘗試節(jié)點數的最大值分別設置為8、4、2,全節(jié)點路由表不作限制。采用直接定位的方式避免請求數據的洪泛廣播,減少系統(tǒng)帶寬壓力,提高數據檢索速度,保障數據可用性。根據節(jié)點存儲數據量的大小,采用分級的方式從小到大進行節(jié)點訪問,可以盡可能地利用不穩(wěn)定節(jié)點,減少全節(jié)點和存儲數據較多節(jié)點的帶寬壓力,進行負載均衡,避免局部熱點產生。ESPV在節(jié)點加入路由表時設置了審核機制,其持續(xù)在線時長需要超過30 min,由此得到的節(jié)點相對穩(wěn)定,防止數據頻繁更新對系統(tǒng)網絡帶寬造成壓力。節(jié)點在加入網絡后可以從其他節(jié)點獲取路由表信息,并且定期檢測節(jié)點的連通性,更新路由表。
為驗證數據的真實性,ESPV保存全部的區(qū)塊頭數據。節(jié)點每次從網絡中獲取到區(qū)塊數據后將鏈上的區(qū)塊哈希值與計算出的該區(qū)塊哈希值進行比對就可以驗證區(qū)塊數據的真實性,維護系統(tǒng)數據的安全性。區(qū)塊頭的數據量很小,不會對節(jié)點的存儲造成壓力。
ESPV 使用不同的端口與網絡中的節(jié)點進行數據共享。用端口1進行交易的接收和轉發(fā),端口2進行區(qū)塊的請求和發(fā)送,端口3獲取和共享路由信息,端口4發(fā)送和接收區(qū)塊頭。
各模塊都有相應的功能。新舊區(qū)塊的獲取都需要由區(qū)塊分區(qū)路由表取得目標節(jié)點地址,以快速從網絡中拉取數據。通過得到的新區(qū)塊構建UTXO 庫,用于交易的驗證。為加快檢索速度為UTXO構建緩存機制,將一部分最近產生的UTXO加載到內存中。舊區(qū)塊為系統(tǒng)中的其他節(jié)點提供數據服務。區(qū)塊頭信息可以校驗從其他節(jié)點得到的區(qū)塊的真實性,保障系統(tǒng)安全。
圖4 ESPV模塊架構Fig. 4 ESPV module architecture
實驗的開發(fā)環(huán)境為Intel Xeo E5-2609 v4 1.70 GHz CPU和16 GB 內存的服務器。利用比特幣現有區(qū)塊數據進行模擬實驗。
通過搭建真實節(jié)點,使用BitcoinETL[22]開源工具,對區(qū)塊數據進行處理,只保留所需字段信息,獲得了實驗所需數據。實驗過程中使用BloomFilter 算法解決了超大數據量的關聯查詢問題。
首先,以10 萬塊為一組,從中隨機抽取100 個區(qū)塊,從目標區(qū)塊開始向前追溯3 000塊區(qū)塊,查詢這些區(qū)塊中包含該區(qū)塊交易的輸入的比率,即可驗證交易的比率,求均值可得圖5。
圖5 總體交易驗證率分布Fig. 5 Overall transaction verification rate distribution
從圖5 可以看出,ESPV 適用于整個比特幣現有生命周期。比特幣總體的交易特征是類似的,在得到數字貨幣后較大可能會在近期進行交易。
其次,使用最新的區(qū)塊數據測試ESPV 的交易驗證功能。實驗從高度為568 201塊開始,每2 016塊為一個周期,隨機抽取其中10%的區(qū)塊進行采樣處理,計算交易驗證的平均比率值,可得圖6。
圖6 交易驗證率Fig. 6 Transaction verification rate
由圖6 可知,ESPV 對新區(qū)塊采用的策略可以驗證較高比率的交易,動態(tài)調整策略有效。
然后,ESPV 與全節(jié)點在568 201 塊時的存儲空間對比如圖7所示。
圖7 存儲空間對比Fig. 7 Storage space comparison
通過分析圖7,可以得出下面的結論:
1)ESPV節(jié)點比全節(jié)點所需的存儲空間明顯減少;
2)ESPV的數據量增長速度遠小于全節(jié)點,可以符合普通PC的硬件條件,增加系統(tǒng)的可擴展性。
假設全網70%的節(jié)點使用ESPV 節(jié)點,30%為全節(jié)點,同時在線節(jié)點約1 萬個,那么保守估計整個系統(tǒng)可以節(jié)省約1 PB數據存儲空間。
最后,測試ESPV的可靠性和可用性。本文使用Java語言設計了節(jié)點對象,它具有節(jié)點類型、可靠度、IP、端口、區(qū)塊段和網絡帶寬屬性。通過創(chuàng)建1 萬個節(jié)點對象來模擬P2P 節(jié)點,建立分級區(qū)塊分區(qū)路由表;同時,創(chuàng)建1 萬個全節(jié)點對象,作對比實驗。分別從兩組節(jié)點中隨機獲取長度為10、100、1 000和10 000的區(qū)塊數據。
根據現有網絡節(jié)點的分布和可靠性情況設置節(jié)點屬性。200 個種子節(jié)點(全節(jié)點)的可靠度為0.9,網絡帶寬為10 MB/s;剩余30%為全節(jié)點,70%為ESPV 節(jié)點,可靠度都為0.1,網絡帶寬為0.2 MB/s~5 MB/s 的隨機數。在創(chuàng)建節(jié)點對象時給區(qū)塊段屬性隨機賦予由真實比特幣數據得到的分片錨定高度集中的值,區(qū)塊大小采用現有比特幣中區(qū)塊的大小數據。每試錯一個節(jié)點需要延時10 ms。遍歷節(jié)點,為節(jié)點建立路由表。用于對比的1 萬個模擬全節(jié)點的帶寬和可靠度與非種子節(jié)點相同,建立路由表。由實驗結果可得圖8。
圖8 數據可靠性和可用性Fig. 8 Data reliability and availability
從實驗結果可以看出,ESPV節(jié)點模型和全節(jié)點的數據可得率相同都為100%,可靠性有保障。在獲取區(qū)塊數據的平均用時上,ESPV 節(jié)點模型略高于全節(jié)點,這是因為系統(tǒng)盡可能地利用不穩(wěn)定節(jié)點造成延時;但P2P網絡本身不穩(wěn)定,較低的延時差對于單個節(jié)點的影響很小,還可以滿足應用需求,能夠應用于實際生產環(huán)境中。
區(qū)塊鏈的數據量呈線性增長模式,對單個節(jié)點的存儲造成很大的壓力。SPV 節(jié)點模型解決了存儲問題,但它們完全依賴于全節(jié)點,使得全節(jié)點壓力增大,系統(tǒng)的去中心化程度減弱。本文提出一個功能完備的增強型輕量級節(jié)點模型。通過對區(qū)塊數據進行分析,發(fā)現保存最近的少量數據就可以驗證一定量的交易,讓節(jié)點具有挖礦功能。通過對網絡中全節(jié)點數據進行統(tǒng)計分析,在保障數據可靠性和可用性的前提下,對舊區(qū)塊進行隨機分片存儲,降低單個節(jié)點的存儲壓力,增加系統(tǒng)存儲可擴展性、安全性和穩(wěn)定性。為加快數據查找,設計出分級區(qū)塊分區(qū)路由表,防止數據請求進行洪泛廣播對網絡帶寬造成壓力。使用鏈信息保證數據的真實性。為適應區(qū)塊數據線性增長的模式,提出動態(tài)調整策略,保證增強型輕量級節(jié)點模型的可用性。
增強型輕量級節(jié)點模型在數據存儲空間和交易驗證之間進行了折中,對早期舊區(qū)塊產生的UTXO 支持性較差,還需要全節(jié)點進行驗證和打包,未來還需要進一步優(yōu)化。