您好,登錄后才能下訂單哦!
Fabric里的數(shù)據(jù)以分布式賬本的形式存儲(chǔ)。賬本由一系列有順序和防篡改的記錄組成,記錄包含著數(shù)據(jù)的全部狀態(tài)改變。賬本中的數(shù)據(jù)項(xiàng)以鍵值對(duì)的形式存放,賬本中所有的鍵值對(duì)構(gòu)成了賬本的狀態(tài),也稱為世界狀態(tài)(World State)。?
每個(gè)通道中有唯一的賬本,由通道中所有成員共同維護(hù)著賬本,每個(gè)記賬節(jié)點(diǎn)上都保存了所屬通道的賬本的一個(gè)副本,因而是分布式賬本。對(duì)賬本的訪問需要通過鏈碼實(shí)現(xiàn)對(duì)賬本鍵值對(duì)的增加、刪除、更新和查詢等的操作。
賬本由區(qū)塊鏈和狀態(tài)數(shù)據(jù)庫兩部分組成。
區(qū)塊鏈?zhǔn)且唤M不可更改的有序的區(qū)塊(數(shù)據(jù)塊),記錄著全部交易的日志。每個(gè)區(qū)塊中包含若干個(gè)交易的數(shù)據(jù),不同區(qū)塊所包含的交易數(shù)量可以不同。區(qū)塊之間用哈希鏈(Hashed-link)關(guān)聯(lián):每個(gè)區(qū)塊頭包含該區(qū)塊所有交易的哈希值以及上一個(gè)區(qū)塊頭的哈希值。鏈?zhǔn)浇Y(jié)構(gòu)可以確保每個(gè)區(qū)塊的數(shù)據(jù)不可更改以及每個(gè)區(qū)塊之間的順序關(guān)系不可更改。因此,區(qū)塊鏈的區(qū)塊只可以添加在鏈的尾部。
狀態(tài)數(shù)據(jù)庫記錄了賬本中所有鍵值對(duì)的當(dāng)前值,相當(dāng)于對(duì)當(dāng)前賬本的交易日志做了索引。鏈碼執(zhí)行交易的時(shí)候需要讀取賬本的當(dāng)前狀態(tài),從狀態(tài)數(shù)據(jù)庫可以迅速獲取鍵值的最新狀態(tài)。
如果沒有狀態(tài)數(shù)據(jù)庫,要獲得某個(gè)鍵值時(shí),需要遍歷整個(gè)區(qū)塊鏈中和該鍵值相關(guān)的交易,效率非常低,因此,讀取狀態(tài)數(shù)據(jù)庫可以認(rèn)為是快速定位和訪問某個(gè)鍵值的方法。另外,當(dāng)狀態(tài)數(shù)據(jù)庫出現(xiàn)故障的時(shí)候,可以通過遍歷賬本重新生成。
當(dāng)一個(gè)區(qū)塊附加到區(qū)塊鏈尾部的時(shí)候,如果區(qū)塊中的有效交易修改了鍵值對(duì),則會(huì)在狀態(tài)數(shù)據(jù)庫中作相應(yīng)的更新,確保區(qū)塊鏈和狀態(tài)數(shù)據(jù)庫始終保持一致。
區(qū)塊鏈的數(shù)據(jù)塊以文件形式保存在各個(gè)節(jié)點(diǎn)中。狀態(tài)數(shù)據(jù)庫可以是各種鍵值數(shù)據(jù)庫,F(xiàn)abric缺省使用LevelDB ,也支持CouchDB的選項(xiàng)。CouchDB除了支持鍵值數(shù)據(jù)外,也支持JSON格式的文檔模型,能夠做復(fù)雜的查詢。
客戶端首先構(gòu)建交易提案,交易提案的作用是調(diào)用通道中的鏈碼來讀取或者寫入賬本的數(shù)據(jù)??蛻舳耸褂肍abric SDK創(chuàng)建交易提案,并使用用戶的私鑰對(duì)交易提案進(jìn)行簽名。
Fabric SDK作用有兩個(gè),一個(gè)是將交易提案封裝成符合gRPC協(xié)議的Protobuf格式的消息,一個(gè)是對(duì)創(chuàng)建的交易提案進(jìn)行簽名。
客戶端打包完交易提案后,將交易提案提交給通道中的背書節(jié)點(diǎn)。背書節(jié)點(diǎn)的背書策略定義了哪些背書節(jié)點(diǎn)簽名背書后交易才能有效,客戶端根據(jù)背書策略選擇相應(yīng)的背書節(jié)點(diǎn),并向相應(yīng)背書節(jié)點(diǎn)提交交易提案。
根據(jù)背書策略,E0,E1,E2三個(gè)背書節(jié)點(diǎn)需要完成簽名背書。
背書節(jié)點(diǎn)收到交易提案后,使用MSP模塊驗(yàn)證簽名并確定請(qǐng)求者是否被合理授權(quán)進(jìn)行交易提案的操作(使用每個(gè)channel對(duì)應(yīng)的ACL進(jìn)行驗(yàn)證),背書節(jié)點(diǎn)以交易提案憑證為輸入,基于當(dāng)前狀態(tài)的數(shù)據(jù)庫執(zhí)行來生成交易結(jié)果,輸出包括反饋值、讀取集和寫入集。此時(shí),賬本并未進(jìn)行更新。背書節(jié)點(diǎn)會(huì)將背書節(jié)點(diǎn)輸出、背書節(jié)點(diǎn)簽名、是否背書聲明作為交易提案反饋回傳給客戶端的SDK。
首先校驗(yàn)交易的簽名是否合法,然后根據(jù)簽名者的身份,確認(rèn)其是否具有權(quán)限進(jìn)行相關(guān)交易。此外,背書節(jié)點(diǎn)還需要檢查交易提案的格式是否正確以及是否已經(jīng)提交過(防止重放***)。
在所有合法性校驗(yàn)通過后,背書節(jié)點(diǎn)按照交易提案調(diào)用鏈碼模擬執(zhí)行交易。鏈碼執(zhí)行時(shí),讀取的數(shù)據(jù)(鍵值對(duì))是背書節(jié)點(diǎn)中本地的狀態(tài)數(shù)據(jù)庫,鏈碼讀取過的數(shù)據(jù)回被歸總到讀集(Read Set);鏈碼對(duì)狀態(tài)數(shù)據(jù)庫的寫操作并不會(huì)對(duì)賬本做改變,所有的寫操作將歸總到一個(gè)寫入集(Write Set)中記錄下來。讀集和寫集將在確認(rèn)節(jié)點(diǎn)中用于確定交易是否最終寫入賬本。
在鏈碼執(zhí)行完成后,背書節(jié)點(diǎn)把鏈碼模擬執(zhí)行后得到的讀寫集(Read-Write Set)等信息簽名后發(fā)回給客戶端。此時(shí),交易信息只在客戶端和單個(gè)背書節(jié)點(diǎn)之間達(dá)成共識(shí),并沒有完成全網(wǎng)共識(shí),各個(gè)客戶端的交易順序沒有確定,可能存在雙花問題,所以不是一個(gè)有效交易。同時(shí),客戶端需要收到大多數(shù)背書節(jié)點(diǎn)的驗(yàn)證回復(fù)后,才算驗(yàn)證成功,具體的背書策略由智能合約代碼控制,可以由開發(fā)者自由配置。
背書節(jié)點(diǎn)E0,E1,E2執(zhí)行簽名背書。
背書節(jié)點(diǎn)完成簽名背書后,將反饋值、讀取集和寫入集、背書節(jié)點(diǎn)簽名、是否背書聲明作為交易提案反饋回傳給客戶端。
客戶端在收到背書節(jié)點(diǎn)的簽名背書結(jié)果后,檢查背書節(jié)點(diǎn)的簽名并比較不同背書節(jié)點(diǎn)的結(jié)果是否一致。如果交易提案是查詢賬本的請(qǐng)求,則客戶端無需提交交易給排序節(jié)點(diǎn)。如果交易提案是更新賬本的請(qǐng)求,客戶端在收集到滿足背書策略的足夠多背書節(jié)點(diǎn)的簽名背書結(jié)果后,把背書節(jié)點(diǎn)返回的讀寫集、所有背書節(jié)點(diǎn)的簽名和通道號(hào)發(fā)給排序服務(wù)節(jié)點(diǎn)。
排序服務(wù)節(jié)點(diǎn)在收到各個(gè)節(jié)點(diǎn)發(fā)來的交易后,并不檢查交易的全部?jī)?nèi)容,而是按照交易中的通道號(hào)對(duì)交易分類排序,然后把相同通道的交易批量打包成區(qū)塊。排序服務(wù)的共識(shí)算法以組件化形式插入Fabric網(wǎng)絡(luò),即開發(fā)者可以自由選擇合適的共識(shí)算法。
排序服務(wù)節(jié)點(diǎn)將為特定通道生成的區(qū)塊廣播給通道中所有組織的主導(dǎo)節(jié)點(diǎn)。區(qū)塊的廣播有兩種觸發(fā)條件,一種是當(dāng)通道的交易數(shù)量達(dá)到某個(gè)預(yù)設(shè)的閾值,另一種是在交易數(shù)量沒有超過閾值但距離上次廣播的時(shí)間超過某個(gè)特定閾值,也可觸發(fā)廣播數(shù)據(jù)塊。兩種方式相結(jié)合,使得經(jīng)過排序的交易及時(shí)生成區(qū)塊并廣播給通道的Peer節(jié)點(diǎn)(記賬節(jié)點(diǎn))。
排序服務(wù)節(jié)點(diǎn)只是決定交易處理的順序,并不對(duì)交易的合法性進(jìn)行校驗(yàn),也不負(fù)責(zé)維護(hù)賬本信息,只有記賬節(jié)點(diǎn)才有賬本寫入權(quán)限。
記賬節(jié)點(diǎn)收到排序服務(wù)節(jié)點(diǎn)發(fā)來的區(qū)塊后,逐筆檢查區(qū)塊中的交易。先檢查交易的合法性以及該交易是否曾經(jīng)出現(xiàn)過。然后調(diào)用校驗(yàn)系統(tǒng)鏈碼(VSCC,Validation System Chaincode)檢驗(yàn)交易的簽名背書是否合法,以及背書的數(shù)量是否滿足背書策略的要求。
記賬節(jié)點(diǎn)對(duì)交易進(jìn)行多版本并發(fā)控制(MVCC)檢查,即校驗(yàn)交易的讀集(Read Set)是否和當(dāng)前賬本中的版本一致(即沒有變化)。如果沒有改變,說明交易寫集(Write Set)中對(duì)數(shù)據(jù)的修改有效,把該交易標(biāo)注為有效,交易的寫集更新到狀態(tài)數(shù)據(jù)庫中。如果當(dāng)前賬本的數(shù)據(jù)和讀集版本不一致,則該交易被標(biāo)注為無效,不更新狀態(tài)數(shù)據(jù)庫。區(qū)塊中的交易數(shù)據(jù)在標(biāo)注成有效或無效后封裝成區(qū)塊寫入賬本的區(qū)塊鏈中。
交易流程中,采用MVCC的樂觀鎖模型,提高了系統(tǒng)的并發(fā)能力。但MVCC也帶來了一些局限性。例如,在同一個(gè)區(qū)塊中若有兩個(gè)交易先后對(duì)某個(gè)數(shù)據(jù)項(xiàng)做更新,順序在后的交易將失敗,因?yàn)楹笮蚪灰椎淖x集版本和當(dāng)前數(shù)據(jù)項(xiàng)版本已經(jīng)不一致。
客戶端會(huì)收到每一個(gè)連接的記賬節(jié)點(diǎn)的通知。
區(qū)塊鏈的賬本由Peer節(jié)點(diǎn)維護(hù),并不是由排序服務(wù)集群維護(hù),所以,只有Peer節(jié)點(diǎn)(背書節(jié)點(diǎn)和記賬節(jié)點(diǎn))包含完整的區(qū)塊鏈信息,而排序服務(wù)集群只負(fù)責(zé)對(duì)交易進(jìn)行排序,只保留處理過程中的一部分區(qū)塊鏈信息。
Hyperledger Fabric網(wǎng)絡(luò)中的節(jié)點(diǎn)是一個(gè)邏輯的概念,并不一定是一個(gè)臺(tái)物理設(shè)備,但對(duì)于生產(chǎn)環(huán)境,為了系統(tǒng)架構(gòu)的解耦,提高擴(kuò)展性以及通過主機(jī)隔離提高安全性,Peer節(jié)點(diǎn)不能和排序服務(wù)節(jié)點(diǎn)部署在一臺(tái)機(jī)器上,而背書節(jié)點(diǎn)和記賬節(jié)點(diǎn)可以部署在同一臺(tái)機(jī)器上。 背書節(jié)點(diǎn)校驗(yàn)客戶端的簽名,然后執(zhí)行智能合約代碼模擬交易。交易處理完成后,對(duì)交易信息簽名,返回給客戶端??蛻舳耸盏胶灻蟮慕灰仔畔⒑?,發(fā)給排序服務(wù)節(jié)點(diǎn)排序。排序服務(wù)節(jié)點(diǎn)將交易信息排序打包成區(qū)塊后,廣播發(fā)給記賬節(jié)點(diǎn),寫入?yún)^(qū)塊鏈中。
Fabric區(qū)塊鏈網(wǎng)絡(luò)中,每個(gè)通道都有其賬本,每個(gè)Peer節(jié)點(diǎn)都保存著其所加入通道的賬本,Peer節(jié)點(diǎn)的賬本包含如下數(shù)據(jù):
A、賬本編號(hào),用于快速查詢存在哪些賬本
B、賬本數(shù)據(jù),用于區(qū)塊數(shù)據(jù)存儲(chǔ)
C、區(qū)塊索引,用于快速查詢區(qū)塊/交易
D、狀態(tài)數(shù)據(jù),用于最新的世界狀態(tài)數(shù)據(jù)
E、歷史數(shù)據(jù):跟蹤鍵的歷史
Fabric的Peer節(jié)點(diǎn)賬本中有四種數(shù)據(jù)庫,idStore(ledgerID數(shù)據(jù)庫)、blkstorage(block文件存儲(chǔ))、statedb(狀態(tài)數(shù)據(jù)庫)、historydb(歷史數(shù)據(jù)庫)。
賬本數(shù)據(jù)庫基于文件系統(tǒng),將區(qū)塊存儲(chǔ)在文件塊中,然后在區(qū)塊索引LevelDB中存儲(chǔ)區(qū)塊交易對(duì)應(yīng)的文件塊及其偏移,即將區(qū)塊索引LevelDB作為賬本數(shù)據(jù)庫的索引。目前支持的區(qū)塊索引有:區(qū)塊編號(hào)、區(qū)塊哈希、交易ID、區(qū)塊交易編號(hào)。
狀態(tài)數(shù)據(jù)庫存儲(chǔ)的是所有曾經(jīng)在交易中出現(xiàn)的鍵值對(duì)的最新值。調(diào)用鏈碼執(zhí)行交易可以改變狀態(tài)數(shù)據(jù),為了高效的執(zhí)行鏈碼調(diào)用,所有數(shù)據(jù)的最新值都被存放在狀態(tài)數(shù)據(jù)庫中;狀態(tài)數(shù)據(jù)庫是有序交易日志的快照,任何時(shí)候都可以根據(jù)交易日志重新生成狀態(tài)數(shù)據(jù)庫;狀態(tài)數(shù)據(jù)庫會(huì)在Peer節(jié)點(diǎn)啟動(dòng)的時(shí)候自動(dòng)恢復(fù)或重構(gòu),未完備前,本Peer節(jié)點(diǎn)不會(huì)接受新的交易;狀態(tài)數(shù)據(jù)庫可以使用LevelDB或者CouchDB,CouchDB能夠存儲(chǔ)任意的二進(jìn)制數(shù)據(jù),支持富文本查詢。
歷史狀態(tài)數(shù)據(jù)庫用于查詢某個(gè)key的歷史修改記錄,歷史狀態(tài)數(shù)據(jù)庫并不存儲(chǔ)key具體的值,而只記錄在某個(gè)區(qū)塊的某個(gè)交易里,某key變動(dòng)了一次。后續(xù)需要查詢的時(shí)候,根據(jù)變動(dòng)歷史去查詢實(shí)際變動(dòng)的值。
ledgerID數(shù)據(jù)庫存儲(chǔ)chainID,用于快速查詢節(jié)點(diǎn)存在哪些賬本。
對(duì)于單鏈的Peer節(jié)點(diǎn)賬本(不包含ledgerID數(shù)據(jù)庫)結(jié)構(gòu)如下:
ledgersData是Peer節(jié)點(diǎn)賬本的根目錄,Peer節(jié)點(diǎn)的賬本存儲(chǔ)在Peer節(jié)點(diǎn)容器的/var/hyperledger/production/ledgersData目錄下,通過命令行可以進(jìn)入Peer節(jié)點(diǎn)容器進(jìn)行查看,命令如下:
docker exec -it peer0.org1.example.com bash
Peer節(jié)點(diǎn)的本地賬本結(jié)構(gòu)如下:
chains/chains目錄下的mychannel目錄channel的名稱,F(xiàn)abric支持多通道的機(jī)制,而通道之間的賬本是隔離的,每個(gè)通道都有自己的賬本空間。
chains/index目錄包含levelDB數(shù)據(jù)庫文件,存儲(chǔ)區(qū)塊索引數(shù)據(jù)庫,使用leveldb實(shí)現(xiàn)。
historyLeveldb目錄存儲(chǔ)智能合約中寫入的key的歷史記錄的索引地址,使用leveldb實(shí)現(xiàn)。
ledgerProvider目錄存儲(chǔ)當(dāng)前節(jié)點(diǎn)所包含channel的信息(已經(jīng)創(chuàng)建的channel id 和正在創(chuàng)建中的channel id),使用leveldb實(shí)現(xiàn)。
stateLeveldb目錄存儲(chǔ)智能合約寫入的數(shù)據(jù),可選擇使用leveldb或couchDB
賬本數(shù)據(jù)以二進(jìn)制文件的形式存儲(chǔ)的,每個(gè)賬本數(shù)據(jù)存儲(chǔ)在不同的目錄下。賬本數(shù)據(jù)的所有操作都通過區(qū)塊文件管理器實(shí)現(xiàn)。區(qū)塊文件管理器創(chuàng)建的文件以blockfile_
為前綴,6位數(shù)字為后綴,后綴必須是從小到大連續(xù)的數(shù)字,中間不能有缺失,因此賬本最大可以持有1000000個(gè)文件塊。默認(rèn)的區(qū)塊文件塊大小的上限是64M(目前硬編碼在代碼中)。賬本數(shù)據(jù)的結(jié)構(gòu)如下:
B代表區(qū)塊鏈賬本數(shù)據(jù)。其中B0為創(chuàng)世區(qū)塊,其中包含了區(qū)塊頭H0,區(qū)塊數(shù)據(jù)D0(創(chuàng)世區(qū)塊里不包含交易數(shù)據(jù)),區(qū)塊元數(shù)據(jù)M0。區(qū)塊B1區(qū)塊頭H1,其中包含了前一個(gè)區(qū)塊B0的加密hash和本身區(qū)塊的加密hash。
(1)區(qū)塊頭
區(qū)塊頭(Block Header)包含三部分:
A、區(qū)塊數(shù)(Block Number):一個(gè)從0(創(chuàng)世區(qū)塊)開始的整數(shù),并且對(duì)于附加到區(qū)塊鏈的每個(gè)新塊增加1。
C、當(dāng)前區(qū)塊hash(Current Block Hash):當(dāng)前區(qū)塊中包含的所有交易的hash。
C、前一區(qū)塊hash(Previous Block Hash):前一個(gè)區(qū)塊的hash。
(2)區(qū)塊數(shù)據(jù)
區(qū)塊數(shù)據(jù)(Block Data)包含一組交易,交易在區(qū)塊創(chuàng)建時(shí)寫入。
(3)區(qū)塊元數(shù)據(jù)
區(qū)塊元數(shù)據(jù)(Block Matadata)包含區(qū)塊創(chuàng)建時(shí)間,寫入客戶端的證書,公鑰和簽名。
(1)交易頭
交易頭中包含了一些重要的交易元數(shù)據(jù),例如鏈碼的名稱、版本。
簽名
(2)簽名
簽名包含由客戶端創(chuàng)建的加密簽名,由客戶端的私鑰生成,用于檢查交易有沒有被篡改。
(3)交易提案
交易提案包含由客戶端生成的交易請(qǐng)求參數(shù)。
(4)交易提案返回
交易提案返回包含由背書節(jié)點(diǎn)返回的模擬執(zhí)行結(jié)果(讀寫集RWset)。
(5)背書
背書包含交易的背書,一個(gè)返回對(duì)應(yīng)多個(gè)背書。
區(qū)塊索引用于快速定位區(qū)塊。
索引鍵可以是區(qū)塊高度、區(qū)塊哈希、交易哈希。
索引值為區(qū)塊文件編號(hào)+文件內(nèi)偏移量+區(qū)塊數(shù)據(jù)長度。
Hyperledger Fabric提供了多種區(qū)塊索引的方式,以便能快速找到區(qū)塊。索引的內(nèi)容是文件位置指針(File Location Pointer)。文件位置指針由三個(gè)部分組成:所在文件的編號(hào)(fileSuffixNum)、文件內(nèi)的偏移量(offset)、區(qū)塊占用的字節(jié)數(shù)(bytesLength)。
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。