Fabric 1.0原始碼分析(18) Ledger(賬本)

尹成發表於2018-05-20
# Fabric 1.0原始碼筆記 之 Ledger(賬本)

## 1、Ledger概述

Ledger,即賬本資料庫。Fabric賬本中有四種資料庫,idStore(ledgerID資料庫)、blkstorage(block檔案儲存)、statedb(狀態資料庫)、historydb(歷史資料庫)。
其中idStore、historydb使用leveldb實現,statedb可選擇使用leveldb或couchDB。而blkstorage中index部分使用leveldb實現,實際區塊鏈資料儲存使用檔案實現。

* idStore,預設目錄/var/hyperledger/production/ledgersData/ledgerProvider,更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #idStore(ledgerID資料庫)](idstore.md)
* blkstorage,預設目錄/var/hyperledger/production/ledgersData/chains,更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #blkstorage(block檔案儲存)](blkstorage.md)
* statedb,預設目錄/var/hyperledger/production/ledgersData/stateLeveldb,更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #statedb(狀態資料庫)](statedb.md)
* historydb,預設目錄/var/hyperledger/production/ledgersData/historyLeveldb,更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #historydb(歷史資料庫)](historydb.md)

## 2、Ledger程式碼目錄結構

Ledger相關程式碼分佈在common/ledger、core/ledger和protos/ledger目錄下。目錄結構如下:

* common/ledger目錄
    * ledger_interface.go,定義了通用介面Ledger、ResultsIterator、以及QueryResult和PrunePolicy(暫時均為空介面)。
    * blkstorage目錄,**blkstorage相關介面及實現**
    * util/leveldbhelper目錄,LevelDB資料庫操作的封裝。
    
* core/ledger目錄
    * ledger_interface.go,定義了核心介面PeerLedgerProvider、PeerLedger、ValidatedLedger(暫時未定義)、QueryExecutor、HistoryQueryExecutor和TxSimulator。
    * kvledger目錄,目前PeerLedgerProvider、PeerLedger等介面僅有一種實現即:kvledger。
        * kv_ledger_provider.go,實現PeerLedgerProvider介面,即Provider結構體及其方法,以及**idStore結構體及方法**。
        * kv_ledger.go,實現PeerLedger介面,即kvLedger結構體及方法。
        * txmgmt目錄,交易管理。
            * statedb目錄,**statedb相關介面及實現**
        * history/historydb目錄,**historydb相關介面及實現**
    * ledgermgmt/ledger_mgmt.go,Ledger管理相關函式實現。
    * ledgerconfig/ledger_config.go,Ledger配置相關函式實現。
    * util目錄,Ledger工具相關函式實現。
    

## 3、核心介面定義

PeerLedgerProvider介面定義:提供PeerLedger例項handle。

```go
type PeerLedgerProvider interface {
    Create(genesisBlock *common.Block) (PeerLedger, error) //用給定的創世紀塊建立Ledger
    Open(ledgerID string) (PeerLedger, error) //開啟已建立的Ledger
    Exists(ledgerID string) (bool, error) //按ledgerID查Ledger是否存在
    List() ([]string, error) //列出現有的ledgerID
    Close() //關閉 PeerLedgerProvider
}
//程式碼在core/ledger/ledger_interface.go
```

PeerLedger介面定義:
PeerLedger和OrdererLedger的不同之處在於PeerLedger本地維護位掩碼,用於區分有效交易和無效交易。

```go
type PeerLedger interface {
    commonledger.Ledger //嵌入common/ledger/Ledger介面
    GetTransactionByID(txID string) (*peer.ProcessedTransaction, error) //按txID獲取交易
    GetBlockByHash(blockHash []byte) (*common.Block, error) //按blockHash獲取Block
    GetBlockByTxID(txID string) (*common.Block, error) //按txID獲取包含交易的Block
    GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) //獲取交易記錄驗證的原因程式碼
    NewTxSimulator() (TxSimulator, error) //建立交易模擬器,客戶端可以建立多個"TxSimulator"並行執行
    NewQueryExecutor() (QueryExecutor, error) //建立查詢執行器,客戶端可以建立多個'QueryExecutor'並行執行
    NewHistoryQueryExecutor() (HistoryQueryExecutor, error) //建立歷史記錄查詢執行器,客戶端可以建立多個'HistoryQueryExecutor'並行執行
    Prune(policy commonledger.PrunePolicy) error //裁剪滿足給定策略的塊或交易
}
//程式碼在core/ledger/ledger_interface.go
```

補充PeerLedger介面嵌入的commonledger.Ledger介面定義如下:

```go
type Ledger interface {
    GetBlockchainInfo() (*common.BlockchainInfo, error) //獲取blockchain基本資訊
    GetBlockByNumber(blockNumber uint64) (*common.Block, error) //按給定高度獲取Block,給定math.MaxUint64將獲取最新Block
    GetBlocksIterator(startBlockNumber uint64) (ResultsIterator, error) //獲取從startBlockNumber開始的迭代器(包含startBlockNumber),迭代器是阻塞迭代,直到ledger中下一個block可用
    Close() //關閉ledger
    Commit(block *common.Block) error //提交新block
}
//程式碼在common/ledger/ledger_interface.go
```

ValidatedLedger介面暫未定義方法,從PeerLedger篩選出無效交易後,ValidatedLedger表示最終賬本。暫時忽略。

QueryExecutor介面定義:用於執行查詢。
其中Get*方法用於支援KV-based資料模型,ExecuteQuery方法用於支援更豐富的資料和查詢支援。

```go
type QueryExecutor interface {
    GetState(namespace string, key string) ([]byte, error) //按namespace和key獲取value,對於chaincode,chaincodeId即為namespace
    GetStateMultipleKeys(namespace string, keys []string) ([][]byte, error) //一次呼叫獲取多個key的值
    //獲取迭代器,返回包括startKey、但不包括endKeyd的之間所有值
    GetStateRangeScanIterator(namespace string, startKey string, endKey string) (commonledger.ResultsIterator, error)
    ExecuteQuery(namespace, query string) (commonledger.ResultsIterator, error) //執行查詢並返回迭代器,僅用於查詢statedb
    Done() //釋放QueryExecutor佔用的資源
}
//程式碼在core/ledger/ledger_interface.go
```

HistoryQueryExecutor介面定義:執行歷史記錄查詢。

```go
type HistoryQueryExecutor interface {
    GetHistoryForKey(namespace string, key string) (commonledger.ResultsIterator, error) //按key查歷史記錄
}
//程式碼在core/ledger/ledger_interface.go
```

TxSimulator介面定義:在"儘可能"最新狀態的一致快照上模擬交易。
其中Set*方法用於支援KV-based資料模型,ExecuteUpdate方法用於支援更豐富的資料和查詢支援。

```go
type TxSimulator interface {
    QueryExecutor //嵌入QueryExecutor介面
    SetState(namespace string, key string, value []byte) error //按namespace和key寫入value
    DeleteState(namespace string, key string) error //按namespace和key刪除
    SetStateMultipleKeys(namespace string, kvs map[string][]byte) error //一次呼叫設定多個key的值
    ExecuteUpdate(query string) error //ExecuteUpdate用於支援豐富的資料模型
    GetTxSimulationResults() ([]byte, error) //獲取模擬交易的結果
}
//程式碼在core/ledger/ledger_interface.go
```

## 4、kvledger.kvLedger結構體及方法(實現PeerLedger介面)

kvLedger結構體定義:

```go
type kvLedger struct {
    ledgerID string //ledgerID
    blockStore blkstorage.BlockStore //blkstorage
    txtmgmt txmgr.TxMgr //txmgr
    historyDB historydb.HistoryDB //historyDB
}
//程式碼在core/ledger/kvledger/kv_ledger.go
```

涉及方法如下:

```go
//構造kvLedger
func newKVLedger(ledgerID string, blockStore blkstorage.BlockStore,versionedDB statedb.VersionedDB, historyDB historydb.HistoryDB) (*kvLedger, error)
//按最後一個有效塊恢復statedb和historydb
func (l *kvLedger) recoverDBs() error
//檢索指定範圍內的塊, 並將寫入集提交給狀態 db 或歷史資料庫, 或同時
func (l *kvLedger) recommitLostBlocks(firstBlockNum uint64, lastBlockNum uint64, recoverables ...recoverable) error
//按交易ID獲取交易
func (l *kvLedger) GetTransactionByID(txID string) (*peer.ProcessedTransaction, error)
//獲取BlockchainInfo
func (l *kvLedger) GetBlockchainInfo() (*common.BlockchainInfo, error)
//按區塊編號獲取塊
func (l *kvLedger) GetBlockByNumber(blockNumber uint64) (*common.Block, error)
//按起始塊獲取塊迭代器
func (l *kvLedger) GetBlocksIterator(startBlockNumber uint64) (commonledger.ResultsIterator, error)
//獲取塊雜湊
func (l *kvLedger) GetBlockByHash(blockHash []byte) (*common.Block, error)
//按交易ID獲取塊
func (l *kvLedger) GetBlockByTxID(txID string) (*common.Block, error)
//按交易ID獲取交易驗證程式碼
func (l *kvLedger) GetTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)
func (l *kvLedger) Prune(policy commonledger.PrunePolicy) error //暫未實現
//建立交易模擬器
func (l *kvLedger) NewTxSimulator() (ledger.TxSimulator, error)
//建立查詢執行器
func (l *kvLedger) NewQueryExecutor() (ledger.QueryExecutor, error)
func (l *kvLedger) NewHistoryQueryExecutor() (ledger.HistoryQueryExecutor, error)
//提交有效塊,塊寫入blkstorage,塊中寫集加入批處理並更新statedb,寫集本身入historyDB
func (l *kvLedger) Commit(block *common.Block) error
//建立歷史記錄查詢執行器
func (l *kvLedger) Close() //關閉
//程式碼在core/ledger/kvledger/kv_ledger.go
```

## 5、kvledger.Provider結構體及方法(實現PeerLedgerProvider介面)

Provider結構體定義:

```go
type Provider struct {
    idStore *idStore //idStore
    blockStoreProvider blkstorage.BlockStoreProvider //blkstorage
    vdbProvider statedb.VersionedDBProvider //statedb
    historydbProvider historydb.HistoryDBProvider //historydb
}
//程式碼在core/ledger/kvledger/kv_ledger_provider.go
```

* idStore更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #idStore(ledgerID資料庫)](idstore.md)
* blkstorage更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #blkstorage(block檔案儲存)](blkstorage.md)
* statedb更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #statedb(狀態資料庫)](statedb.md)
* historydb更詳細內容,參考:[Fabric 1.0原始碼筆記 之 Ledger #historydb(歷史資料庫)](historydb.md)

涉及方法如下:

```go
//分別構造idStore、blockStoreProvider、vdbProvider和historydbProvider,並用於構造Provider,並恢復之前未完成建立的Ledger
func NewProvider() (ledger.PeerLedgerProvider, error)
//按創世區塊建立並開啟Ledger,提交創世區塊(塊入blkstorage,寫集更新statedb,寫集本身寫入historydb),建立ledgerID
func (provider *Provider) Create(genesisBlock *common.Block) (ledger.PeerLedger, error)
//呼叫provider.openInternal(ledgerID),開啟Ledger
func (provider *Provider) Open(ledgerID string) (ledger.PeerLedger, error)
//按ledgerID開啟blkstorage、statedb和historydb,並建立kvledger
func (provider *Provider) openInternal(ledgerID string) (ledger.PeerLedger, error)
//ledgerID是否存在
func (provider *Provider) Exists(ledgerID string) (bool, error)
//獲取ledgerID列表,調取provider.idStore.getAllLedgerIds()
func (provider *Provider) List() ([]string, error)
//關閉idStore、blkstorage、statedb、historydb
func (provider *Provider) Close()
//檢查是否有之前未完成建立的Ledger,並恢復
func (provider *Provider) recoverUnderConstructionLedger()
func (provider *Provider) runCleanup(ledgerID string) error //暫時沒有實現
func panicOnErr(err error, mgsFormat string, args ...interface{}) //panicOnErr
//程式碼在core/ledger/kvledger/kv_ledger_provider.go
```

## 6、ledgermgmt(Ledger管理函式)

全域性變數:

```go
var openedLedgers map[string]ledger.PeerLedger //Ledger map,Key為ChainID(即ChannelId或LedgerId)
var ledgerProvider ledger.PeerLedgerProvider //LedgerProvider
//程式碼在core/ledger/ledgermgmt/ledger_mgmt.go
```

Ledger管理函式:

```go
func Initialize() //Ledger初始化,呼叫initialize(),once.Do確保僅呼叫一次
func initialize() //Ledger初始化,包括初始化openedLedgers及ledgerProvider
//呼叫ledgerProvider.Create(genesisBlock)建立Ledger,並加入openedLedgers
func CreateLedger(genesisBlock *common.Block) (ledger.PeerLedger, error)
//按id取Ledger,並呼叫ledgerProvider.Open(id)開啟Ledger
func OpenLedger(id string) (ledger.PeerLedger, error)
//獲取ledgerID列表,調取ledgerProvider.List()
func GetLedgerIDs() ([]string, error)
//關閉ledgerProvider
func Close()
//構造closableLedger
func wrapLedger(id string, l ledger.PeerLedger) ledger.PeerLedger
//程式碼在core/ledger/ledgermgmt/ledger_mgmt.go
```

closableLedger:

```go
type closableLedger struct {
    id string
    ledger.PeerLedger
}

func (l *closableLedger) Close() //調取l.closeWithoutLock()
func (l *closableLedger) closeWithoutLock() //delete(openedLedgers, l.id)
//程式碼在core/ledger/ledgermgmt/ledger_mgmt.go
```





網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN





網址:http://www.qukuailianxueyuan.io/



欲領取造幣技術與全套虛擬機器資料

區塊鏈技術交流QQ群:756146052  備註:CSDN

尹成學院微信:備註:CSDN

相關文章