Hyperledger Fabric數(shù)據(jù)存儲(chǔ)結(jié)構(gòu)
概述
Hyperledger Fabric支持多鏈。每個(gè)鏈對(duì)應(yīng)一套賬本。所以區(qū)塊鏈每個(gè)peer節(jié)點(diǎn)會(huì)維護(hù)多套賬本。每個(gè)超級(jí)賬本包含以下元素:
- 賬本編號(hào):快速查詢存在哪些賬本
- 賬本數(shù)據(jù):實(shí)際的區(qū)塊數(shù)據(jù)存儲(chǔ)
- 區(qū)塊索引:快速查詢區(qū)塊/交易
- 狀態(tài)數(shù)據(jù):最新的世界狀態(tài)數(shù)據(jù)
- 歷史數(shù)據(jù):跟蹤鍵的歷史
每個(gè)peer節(jié)點(diǎn)會(huì)維護(hù)4個(gè)DB,它們分別是:
- idStore,存儲(chǔ)chainID。用戶快速查詢節(jié)點(diǎn)存在哪些賬本
- stateDB,存儲(chǔ)world state(默認(rèn)為L(zhǎng)evelDB,可替換為CouchDB)
- historyDB,存儲(chǔ)stateDB的key的版本變化
- blockIndex,存儲(chǔ)區(qū)塊文件索引
如下圖:(因只展示了單鏈的數(shù)據(jù)存儲(chǔ)情況,故idStore未在圖中展示)

其中,世界狀態(tài)和賬本數(shù)據(jù)是兩個(gè)賬本最重要的組成部分。

賬本編號(hào)(LedgerId)
賬本編號(hào)的數(shù)據(jù)存儲(chǔ)在LevelDB數(shù)據(jù)庫(kù)中,只是記錄了有哪些賬本,創(chuàng)建新的賬本會(huì)檢查是否有相同的賬本編號(hào)存在,保證了全局唯一性。賬本編號(hào)庫(kù)并不存儲(chǔ)與區(qū)塊相關(guān)的數(shù)據(jù)。
賬本數(shù)據(jù)(Ledger)
賬本數(shù)據(jù)是以二進(jìn)制文件的形式存儲(chǔ)的,每個(gè)賬本數(shù)據(jù)存儲(chǔ)在不同的目錄下。賬本數(shù)據(jù)的所有操作都是通過(guò)區(qū)塊文件管理器(blockfileMgr)實(shí)現(xiàn)的。區(qū)塊文件管理器創(chuàng)建的文件以“blockfile_”為前綴,6位數(shù)字為后綴,后綴必須是從小到大連續(xù)的數(shù)字,中間不能有缺失。默認(rèn)的區(qū)塊文件大小上限是64M(目前這個(gè)大小是硬編碼在代碼中的),一個(gè)賬本能保存最大數(shù)據(jù)量大概是61TB。
下圖是區(qū)塊賬本數(shù)據(jù)的結(jié)構(gòu):

- 信息描述:B代表區(qū)塊鏈賬本數(shù)據(jù)。其中B0為創(chuàng)世區(qū)塊,其中包含了區(qū)塊頭H0,區(qū)塊數(shù)據(jù)D0(因?yàn)槭莿?chuàng)世區(qū)塊,區(qū)塊數(shù)據(jù)里不包含交易數(shù)據(jù)),區(qū)塊元數(shù)據(jù)M0。區(qū)塊B1區(qū)塊頭H1,其中包含了前一個(gè)區(qū)塊B0的加密hash和本身區(qū)塊的加密hash。
區(qū)塊(Block)

每個(gè)區(qū)塊包含三個(gè)部分。
區(qū)塊頭(Block Header)
區(qū)塊數(shù)(Block Number):一個(gè)從0(創(chuàng)世區(qū)塊)開始的整數(shù),并且對(duì)于附加到區(qū)塊鏈的每個(gè)新塊增加1。
當(dāng)前區(qū)塊hash(Current Block Hash):當(dāng)前區(qū)塊中包含的所有交易的hash。
前一區(qū)塊hash(Previous Block Hash):前一個(gè)區(qū)塊的hash。
區(qū)塊數(shù)據(jù)(Block Data)
區(qū)塊數(shù)據(jù)包含了一組交易,交易在區(qū)塊創(chuàng)建時(shí)寫入。
區(qū)塊元數(shù)據(jù)(Block Matadata)
元數(shù)據(jù)包含了區(qū)塊創(chuàng)建時(shí)間,寫入程序的證書,公鑰和簽名。
交易(transaction)

交易頭(Header)
交易頭中包含了一些重要的交易元數(shù)據(jù),例如鏈碼的名稱、版本。
簽名(Signature)
包含由application創(chuàng)建的加密簽名。它是由application的私鑰生成的。用于檢查交易有沒(méi)有被篡改。
交易提案(Proposal)
包含了由application生成的交易請(qǐng)求參數(shù)。
交易提案返回(Response)
包含了由背書節(jié)點(diǎn)返回的模擬執(zhí)行結(jié)果(讀寫集RWset)。這是鏈碼的輸出,如果交易驗(yàn)證通過(guò),這些數(shù)據(jù)會(huì)被用于更新世界狀態(tài)。
背書(Endorsements)
包含了交易的背書。一個(gè)返回對(duì)應(yīng)多個(gè)背書。
區(qū)塊索引(Block Index)
Hyperledger Fabric提供了多種區(qū)塊索引的方式,以便能快速找到區(qū)塊。索引的內(nèi)容是文件位置指針(File Location Pointer)。文件位置指針由三個(gè)部分組成:所在文件的編號(hào)(fileSuffixNum)、文件內(nèi)的偏移量(offset)、區(qū)塊占用的字節(jié)數(shù)(bytesLength)。
狀態(tài)數(shù)據(jù)(State Database)
狀態(tài)數(shù)據(jù)(state database)記錄的是交易執(zhí)行的結(jié)果,最新的狀態(tài)代表了通道(channel)上所有鍵的最新值,所以又稱為“世界狀態(tài)”。狀態(tài)數(shù)據(jù)庫(kù)目前支持LevelDB和CouchDB。
- LevelDB(默認(rèn)的KV數(shù)據(jù)庫(kù)):支持鍵的查詢,組合鍵的查詢、范圍鍵的查詢。
- CouchDB(可選的KV數(shù)據(jù)庫(kù)):支持鍵的查詢、組合件的查詢,還有復(fù)雜的查詢。
不同賬本的狀態(tài)數(shù)據(jù)庫(kù)存放在不同的目錄下,不同鏈碼的數(shù)據(jù)是按鏈碼編號(hào)(chaincodeID)作為命名空間來(lái)劃分?jǐn)?shù)據(jù)。
狀態(tài)數(shù)據(jù)庫(kù)的基本操作是基于鍵值對(duì)的管理。讀取狀態(tài)數(shù)據(jù)的時(shí)候不用指定版本,讀取到的狀態(tài)數(shù)據(jù)是某個(gè)時(shí)刻最新的版本,返回的數(shù)據(jù)包含版本和數(shù)據(jù)兩個(gè)部分。

- 信息描述:狀態(tài)數(shù)據(jù)庫(kù)W包含兩條數(shù)據(jù)。第一條,key=CAR1,value=Audi,版本=0.第二條,key=CAR2,value為一條復(fù)雜json表達(dá)式,版本也是0.
上述圖片描述了世界狀態(tài)數(shù)據(jù)庫(kù)的基本存儲(chǔ)結(jié)構(gòu)。當(dāng)發(fā)生交易后,改變數(shù)據(jù)內(nèi)容,并變更版本號(hào)。
歷史數(shù)據(jù)(History Database)
歷史數(shù)據(jù)記錄了每個(gè)狀態(tài)數(shù)據(jù)的歷史信息,歷史信息是保存在LevelDB數(shù)據(jù)庫(kù)中的。