1. 程式人生 > >HyperLeger Fabric開發(五)——HyperLeger Fabric賬本存儲

HyperLeger Fabric開發(五)——HyperLeger Fabric賬本存儲

並不會 客戶端 vcc *** bytes 作用 data 一次 系列

HyperLeger Fabric開發(五)——HyperLeger Fabric賬本存儲

一、HyperLeger Fabric賬本簡介

Fabric裏的數據以分布式賬本的形式存儲。賬本由一系列有順序和防篡改的記錄組成,記錄包含著數據的全部狀態改變。賬本中的數據項以鍵值對的形式存放,賬本中所有的鍵值對構成了賬本的狀態,也稱為世界狀態(World State)。?
每個通道中有唯一的賬本,由通道中所有成員共同維護著賬本,每個記賬節點上都保存了所屬通道的賬本的一個副本,因而是分布式賬本。對賬本的訪問需要通過鏈碼實現對賬本鍵值對的增加、刪除、更新和查詢等的操作。
賬本由區塊鏈和狀態數據庫兩部分組成。
區塊鏈是一組不可更改的有序的區塊(數據塊),記錄著全部交易的日誌。每個區塊中包含若幹個交易的數據,不同區塊所包含的交易數量可以不同。區塊之間用哈希鏈(Hashed-link)關聯:每個區塊頭包含該區塊所有交易的哈希值以及上一個區塊頭的哈希值。鏈式結構可以確保每個區塊的數據不可更改以及每個區塊之間的順序關系不可更改。因此,區塊鏈的區塊只可以添加在鏈的尾部。

狀態數據庫記錄了賬本中所有鍵值對的當前值,相當於對當前賬本的交易日誌做了索引。鏈碼執行交易的時候需要讀取賬本的當前狀態,從狀態數據庫可以迅速獲取鍵值的最新狀態。
如果沒有狀態數據庫,要獲得某個鍵值時,需要遍歷整個區塊鏈中和該鍵值相關的交易,效率非常低,因此,讀取狀態數據庫可以認為是快速定位和訪問某個鍵值的方法。另外,當狀態數據庫出現故障的時候,可以通過遍歷賬本重新生成。
當一個區塊附加到區塊鏈尾部的時候,如果區塊中的有效交易修改了鍵值對,則會在狀態數據庫中作相應的更新,確保區塊鏈和狀態數據庫始終保持一致。
區塊鏈的數據塊以文件形式保存在各個節點中。狀態數據庫可以是各種鍵值數據庫,Fabric缺省使用LevelDB ,也支持CouchDB的選項。CouchDB除了支持鍵值數據外,也支持JSON格式的文檔模型,能夠做復雜的查詢。

二、HyperLeger Fabric交易流程

1、客戶端向背書節點發送交易提案請求

客戶端首先構建交易提案,交易提案的作用是調用通道中的鏈碼來讀取或者寫入賬本的數據。客戶端使用Fabric SDK創建交易提案,並使用用戶的私鑰對交易提案進行簽名。
Fabric SDK作用有兩個,一個是將交易提案封裝成符合gRPC協議的Protobuf格式的消息,一個是對創建的交易提案進行簽名。
客戶端打包完交易提案後,將交易提案提交給通道中的背書節點。背書節點的背書策略定義了哪些背書節點簽名背書後交易才能有效,客戶端根據背書策略選擇相應的背書節點,並向相應背書節點提交交易提案。
技術分享圖片
根據背書策略,E0,E1,E2三個背書節點需要完成簽名背書。

2、背書節點對交易提案進行簽名背書

背書節點收到交易提案後,使用MSP模塊驗證簽名並確定請求者是否被合理授權進行交易提案的操作(使用每個channel對應的ACL進行驗證),背書節點以交易提案憑證為輸入,基於當前狀態的數據庫執行來生成交易結果,輸出包括反饋值、讀取集和寫入集。此時,賬本並未進行更新。背書節點會將背書節點輸出、背書節點簽名、是否背書聲明作為交易提案反饋回傳給客戶端的SDK。
首先校驗交易的簽名是否合法,然後根據簽名者的身份,確認其是否具有權限進行相關交易。此外,背書節點還需要檢查交易提案的格式是否正確以及是否已經提交過(防止重放***)。
在所有合法性校驗通過後,背書節點按照交易提案調用鏈碼模擬執行交易。鏈碼執行時,讀取的數據(鍵值對)是背書節點中本地的狀態數據庫,鏈碼讀取過的數據回被歸總到讀集(Read Set);鏈碼對狀態數據庫的寫操作並不會對賬本做改變,所有的寫操作將歸總到一個寫入集(Write Set)中記錄下來。讀集和寫集將在確認節點中用於確定交易是否最終寫入賬本。
在鏈碼執行完成後,背書節點把鏈碼模擬執行後得到的讀寫集(Read-Write Set)等信息簽名後發回給客戶端。此時,交易信息只在客戶端和單個背書節點之間達成共識,並沒有完成全網共識,各個客戶端的交易順序沒有確定,可能存在雙花問題,所以不是一個有效交易。同時,客戶端需要收到大多數背書節點的驗證回復後,才算驗證成功,具體的背書策略由智能合約代碼控制,可以由開發者自由配置。
技術分享圖片
背書節點E0,E1,E2執行簽名背書。

3、背書節點將簽名背書結果返回給客戶端

技術分享圖片
背書節點完成簽名背書後,將反饋值、讀取集和寫入集、背書節點簽名、是否背書聲明作為交易提案反饋回傳給客戶端。

4、客戶端向排序服務提交交易

客戶端在收到背書節點的簽名背書結果後,檢查背書節點的簽名並比較不同背書節點的結果是否一致。如果交易提案是查詢賬本的請求,則客戶端無需提交交易給排序節點。如果交易提案是更新賬本的請求,客戶端在收集到滿足背書策略的足夠多背書節點的簽名背書結果後,把背書節點返回的讀寫集、所有背書節點的簽名和通道號發給排序服務節點。
技術分享圖片

5、排序服務節點生成區塊

排序服務節點在收到各個節點發來的交易後,並不檢查交易的全部內容,而是按照交易中的通道號對交易分類排序,然後把相同通道的交易批量打包成區塊。排序服務的共識算法以組件化形式插入Fabric網絡,即開發者可以自由選擇合適的共識算法。
排序服務節點將為特定通道生成的區塊廣播給通道中所有組織的主導節點。區塊的廣播有兩種觸發條件,一種是當通道的交易數量達到某個預設的閾值,另一種是在交易數量沒有超過閾值但距離上次廣播的時間超過某個特定閾值,也可觸發廣播數據塊。兩種方式相結合,使得經過排序的交易及時生成區塊並廣播給通道的Peer節點(記賬節點)。
排序服務節點只是決定交易處理的順序,並不對交易的合法性進行校驗,也不負責維護賬本信息,只有記賬節點才有賬本寫入權限。
技術分享圖片

6、記賬節點進行交易驗證

記賬節點收到排序服務節點發來的區塊後,逐筆檢查區塊中的交易。先檢查交易的合法性以及該交易是否曾經出現過。然後調用校驗系統鏈碼(VSCC,Validation System Chaincode)檢驗交易的簽名背書是否合法,以及背書的數量是否滿足背書策略的要求。
記賬節點對交易進行多版本並發控制(MVCC)檢查,即校驗交易的讀集(Read Set)是否和當前賬本中的版本一致(即沒有變化)。如果沒有改變,說明交易寫集(Write Set)中對數據的修改有效,把該交易標註為有效,交易的寫集更新到狀態數據庫中。如果當前賬本的數據和讀集版本不一致,則該交易被標註為無效,不更新狀態數據庫。區塊中的交易數據在標註成有效或無效後封裝成區塊寫入賬本的區塊鏈中。
技術分享圖片
交易流程中,采用MVCC的樂觀鎖模型,提高了系統的並發能力。但MVCC也帶來了一些局限性。例如,在同一個區塊中若有兩個交易先後對某個數據項做更新,順序在後的交易將失敗,因為後序交易的讀集版本和當前數據項版本已經不一致。

7、記賬節點通知客戶端

技術分享圖片
客戶端會收到每一個連接的記賬節點的通知。

8、交易流程總結

技術分享圖片
區塊鏈的賬本由Peer節點維護,並不是由排序服務集群維護,所以,只有Peer節點(背書節點和記賬節點)包含完整的區塊鏈信息,而排序服務集群只負責對交易進行排序,只保留處理過程中的一部分區塊鏈信息。
Hyperledger Fabric網絡中的節點是一個邏輯的概念,並不一定是一個臺物理設備,但對於生產環境,為了系統架構的解耦,提高擴展性以及通過主機隔離提高安全性,Peer節點不能和排序服務節點部署在一臺機器上,而背書節點和記賬節點可以部署在同一臺機器上。 背書節點校驗客戶端的簽名,然後執行智能合約代碼模擬交易。交易處理完成後,對交易信息簽名,返回給客戶端。客戶端收到簽名後的交易信息後,發給排序服務節點排序。排序服務節點將交易信息排序打包成區塊後,廣播發給記賬節點,寫入區塊鏈中。

三、HyperLeger Fabric賬本存儲原理

1、Fabric賬本存儲原理

Fabric區塊鏈網絡中,每個通道都有其賬本,每個Peer節點都保存著其所加入通道的賬本,Peer節點的賬本包含如下數據:
A、賬本編號,用於快速查詢存在哪些賬本
B、賬本數據,用於區塊數據存儲
C、區塊索引,用於快速查詢區塊/交易
D、狀態數據,用於最新的世界狀態數據
E、歷史數據:跟蹤鍵的歷史
Fabric的Peer節點賬本中有四種數據庫,idStore(ledgerID數據庫)、blkstorage(block文件存儲)、statedb(狀態數據庫)、historydb(歷史數據庫)。
賬本數據庫基於文件系統,將區塊存儲在文件塊中,然後在區塊索引LevelDB中存儲區塊交易對應的文件塊及其偏移,即將區塊索引LevelDB作為賬本數據庫的索引。目前支持的區塊索引有:區塊編號、區塊哈希、交易ID、區塊交易編號。
狀態數據庫存儲的是所有曾經在交易中出現的鍵值對的最新值。調用鏈碼執行交易可以改變狀態數據,為了高效的執行鏈碼調用,所有數據的最新值都被存放在狀態數據庫中;狀態數據庫是有序交易日誌的快照,任何時候都可以根據交易日誌重新生成狀態數據庫;狀態數據庫會在Peer節點啟動的時候自動恢復或重構,未完備前,本Peer節點不會接受新的交易;狀態數據庫可以使用LevelDB或者CouchDB,CouchDB能夠存儲任意的二進制數據,支持富文本查詢。
歷史狀態數據庫用於查詢某個key的歷史修改記錄,歷史狀態數據庫並不存儲key具體的值,而只記錄在某個區塊的某個交易裏,某key變動了一次。後續需要查詢的時候,根據變動歷史去查詢實際變動的值。
ledgerID數據庫存儲chainID,用於快速查詢節點存在哪些賬本。
對於單鏈的Peer節點賬本(不包含ledgerID數據庫)結構如下:
技術分享圖片

2、Peer賬本結構

ledgersData是Peer節點賬本的根目錄,Peer節點的賬本存儲在Peer節點容器的/var/hyperledger/production/ledgersData目錄下,通過命令行可以進入Peer節點容器進行查看,命令如下:
docker exec -it peer0.org1.example.com bash
Peer節點的本地賬本結構如下:
技術分享圖片
chains/chains目錄下的mychannel目錄channel的名稱,Fabric支持多通道的機制,而通道之間的賬本是隔離的,每個通道都有自己的賬本空間。
chains/index目錄包含levelDB數據庫文件,存儲區塊索引數據庫,使用leveldb實現。
historyLeveldb目錄存儲智能合約中寫入的key的歷史記錄的索引地址,使用leveldb實現。
ledgerProvider目錄存儲當前節點所包含channel的信息(已經創建的channel id 和正在創建中的channel id),使用leveldb實現。
stateLeveldb目錄存儲智能合約寫入的數據,可選擇使用leveldb或couchDB

3、賬本數據

賬本數據以二進制文件的形式存儲的,每個賬本數據存儲在不同的目錄下。賬本數據的所有操作都通過區塊文件管理器實現。區塊文件管理器創建的文件以blockfile_為前綴,6位數字為後綴,後綴必須是從小到大連續的數字,中間不能有缺失,因此賬本最大可以持有1000000個文件塊。默認的區塊文件塊大小的上限是64M(目前硬編碼在代碼中)。賬本數據的結構如下:
技術分享圖片
B代表區塊鏈賬本數據。其中B0為創世區塊,其中包含了區塊頭H0,區塊數據D0(創世區塊裏不包含交易數據),區塊元數據M0。區塊B1區塊頭H1,其中包含了前一個區塊B0的加密hash和本身區塊的加密hash。

4、區塊結構

技術分享圖片
(1)區塊頭
區塊頭(Block Header)包含三部分:
A、區塊數(Block Number):一個從0(創世區塊)開始的整數,並且對於附加到區塊鏈的每個新塊增加1。
C、當前區塊hash(Current Block Hash):當前區塊中包含的所有交易的hash。
C、前一區塊hash(Previous Block Hash):前一個區塊的hash。
(2)區塊數據
區塊數據(Block Data)包含一組交易,交易在區塊創建時寫入。
(3)區塊元數據
區塊元數據(Block Matadata)包含區塊創建時間,寫入客戶端的證書,公鑰和簽名。

5、交易結構

技術分享圖片
(1)交易頭
交易頭中包含了一些重要的交易元數據,例如鏈碼的名稱、版本。
簽名
(2)簽名
簽名包含由客戶端創建的加密簽名,由客戶端的私鑰生成,用於檢查交易有沒有被篡改。
(3)交易提案
交易提案包含由客戶端生成的交易請求參數。
(4)交易提案返回
交易提案返回包含由背書節點返回的模擬執行結果(讀寫集RWset)。
(5)背書
背書包含交易的背書,一個返回對應多個背書。

6、區塊索引

區塊索引用於快速定位區塊。
索引鍵可以是區塊高度、區塊哈希、交易哈希。
索引值為區塊文件編號+文件內偏移量+區塊數據長度。
Hyperledger Fabric提供了多種區塊索引的方式,以便能快速找到區塊。索引的內容是文件位置指針(File Location Pointer)。文件位置指針由三個部分組成:所在文件的編號(fileSuffixNum)、文件內的偏移量(offset)、區塊占用的字節數(bytesLength)。

HyperLeger Fabric開發(五)——HyperLeger Fabric賬本存儲