1. 程式人生 > >兄弟連區塊鏈教程Fabric1.0源代碼分析blockfile區塊文件存儲1

兄弟連區塊鏈教程Fabric1.0源代碼分析blockfile區塊文件存儲1

last 路徑 poi prot ring ets ons retrieve hand

Fabric 1.0源代碼筆記 之 blockfile(區塊文件存儲)

1、blockfile概述

blockfile,即Fabric區塊鏈區塊文件存儲,默認目錄/var/hyperledger/production/ledgersData/chains,含index和chains兩個子目錄。
其中index為索引目錄,采用leveldb實現。而chains為各ledger的區塊鏈文件,子目錄以ledgerid為名,使用文件系統實現。
區塊文件以blockfile_為前綴,最大大小默認64M。

blockfile,相關代碼集中在common/ledger/blkstorage/fsblkstorage目錄,目錄結構如下:

  • blockfile_mgr.go,blockfileMgr和checkpointInfo結構體及方法。
  • block_stream.go,blockfileStream、blockStream、blockPlacementInfo結構體及方法。
  • blockfile_rw.go,blockfileWriter和blockfileReader結構體及方法(blockfileReader未使用)。
  • blockindex.go,index接口定義,index接口實現即blockIndex結構體及方法定義,以及blockIdxInfo、locPointer、fileLocPointer結構體及方法。
  • blockfile_helper.go,定義了4個工具函數,constructCheckpointInfoFromBlockFiles、retrieveLastFileSuffix、isBlockFileName、getFileInfoOrPanic。
    作用分別為:掃描最新的blockfile並重新構造檢查點信息、獲取最新的文件後綴、根據文件前綴判斷是否為區塊文件、獲取文件狀態信息。
  • block_serialization.go,block序列化相關工具函數。
  • blocks_itr.go,blocksItr結構體及方法。

2、Block結構體定、以及Block序列化

2.1、Block相關結構體

Block結構體:

```go
type Block struct {
    Header *BlockHeader //BlockHeader
    Data *BlockData //BlockData
    Metadata *BlockMetadata
}

func (m *Block) GetHeader() *BlockHeader //獲取BlockHeader,即m.Header
func (m *Block) GetData() *BlockData //獲取BlockData,即m.Data
func (m *Block) GetMetadata() *BlockMetadata //m.Metadata
//代碼在protos/common/common.pb.go

BlockHeader結構體:

type BlockHeader struct {
    Number uint64 //區塊編號
    PreviousHash []byte //前一個區塊哈希
    DataHash []byte //當前區塊哈希
}

func (m *BlockHeader) GetNumber() uint64 //獲取區塊編號,即m.Number
func (m *BlockHeader) GetPreviousHash() []byte //獲取前一個區塊哈希,即m.PreviousHash
func (m *BlockHeader) GetDataHash() []byte //獲取當前區塊哈希,即m.DataHash
//代碼在protos/common/common.pb.go

BlockData結構體:

type BlockData struct {
    Data [][]byte //Data,存儲交易信息
}

func (m *BlockData) GetData() [][]byte //獲取Data,即m.Data
//代碼在protos/common/common.pb.go

BlockMetadata結構體:

type BlockMetadata struct {
    Metadata [][]byte //K/V均為[]byte格式
}

func (m *BlockMetadata) GetMetadata() [][]byte //m.Metadata
//代碼在protos/common/common.pb.go

補充BlockMetadataIndex:

type BlockMetadataIndex int32

const (
    BlockMetadataIndex_SIGNATURES BlockMetadataIndex = 0
    BlockMetadataIndex_LAST_CONFIG BlockMetadataIndex = 1
    BlockMetadataIndex_TRANSACTIONS_FILTER BlockMetadataIndex = 2
    BlockMetadataIndex_ORDERER BlockMetadataIndex = 3
)

2.2、Block序列化

serializedBlockInfo結構體定義及工具函數:

type serializedBlockInfo struct {
    blockHeader *common.BlockHeader //BlockHeader
    txOffsets []*txindexInfo //交易索引信息
    metadata *common.BlockMetadata
}

type txindexInfo struct {
    txID string //交易ID
    loc *locPointer //文件指針
}

//序列化區塊,返回序列化後字節,以及serializedBlockInfo(含BlockHeader和交易索引信息)
func serializeBlock(block *common.Block) ([]byte, *serializedBlockInfo, error)
//反序列化區塊,構建Block結構體
func deserializeBlock(serializedBlockBytes []byte) (*common.Block, error)
//反序列化區塊,並構造serializedBlockInfo
func extractSerializedBlockInfo(serializedBlockBytes []byte) (*serializedBlockInfo, error)
//序列化中添加BlockHeader,即Number、DataHash和PreviousHash
func addHeaderBytes(blockHeader *common.BlockHeader, buf *proto.Buffer) error
//序列化中添加BlockData,並從BlockData中解析txid,返回交易索引信息數組
func addDataBytes(blockData *common.BlockData, buf *proto.Buffer) ([]*txindexInfo, error)
//序列化中添加Metadata
func addMetadataBytes(blockMetadata *common.BlockMetadata, buf *proto.Buffer) error
//反序列化出BlockHeader
func extractHeader(buf *ledgerutil.Buffer) (*common.BlockHeader, error)
//反序列化出BlockData,並返回交易索引信息數組
func extractData(buf *ledgerutil.Buffer) (*common.BlockData, []*txindexInfo, error)
//反序列化出Metadata
func extractMetadata(buf *ledgerutil.Buffer) (*common.BlockMetadata, error)
//從BlockData中解析出交易ID
func extractTxID(txEnvelopBytes []byte) (string, error)
//代碼在common/ledger/blkstorage/fsblkstorage/block_serialization.go

3、checkpointInfo結構體定義及方法

checkpointInfo,即檢查點信息,結構體定義如下:

type checkpointInfo struct {
    latestFileChunkSuffixNum int //最新的區塊文件後綴,如blockfile_000000
    latestFileChunksize int //最新的區塊文件大小
    isChainEmpty bool //是否空鏈
    lastBlockNumber uint64 //最新的區塊編號
}
//代碼在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go

涉及方法如下:

func (i *checkpointInfo) marshal() ([]byte, error) //checkpointInfo序列化
func (i *checkpointInfo) unmarshal(b []byte) error //checkpointInfo反序列化
func (i *checkpointInfo) String() string //轉換為string
//代碼在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go

4、blockfileStream相關結構體及方法

4.1、blockfileStream

blockfileStream定義如下:

type blockfileStream struct {
    fileNum int //blockfile文件後綴
    file *os.File //os.File
    reader *bufio.Reader //bufio.Reader
    currentOffset int64 //當前偏移量
}
//代碼在common/ledger/blkstorage/fsblkstorage/block_stream.go

涉及方法如下:

//構造blockfileStream
func newBlockfileStream(rootDir string, fileNum int, startOffset int64) (*blockfileStream, error) 
func (s *blockfileStream) nextBlockBytes() ([]byte, error) //下一個塊,調取s.nextBlockBytesAndPlacementInfo()
//下一個塊和位置信息
func (s *blockfileStream) nextBlockBytesAndPlacementInfo() ([]byte, *blockPlacementInfo, error) 
func (s *blockfileStream) close() error //關閉blockfileStream
//代碼在common/ledger/blkstorage/fsblkstorage/block_stream.go

func (s blockfileStream) nextBlockBytesAndPlacementInfo() ([]byte, blockPlacementInfo, error) 代碼如下:

var lenBytes []byte
var err error
var fileInfo os.FileInfo
moreContentAvailable := true

fileInfo, err = s.file.Stat() //獲取文件狀態
remainingBytes := fileInfo.Size() - s.currentOffset //文件讀取剩余字節
peekBytes := 8
if remainingBytes < int64(peekBytes) { //剩余字節小於8,按實際剩余字節,否則按8
    peekBytes = int(remainingBytes)
    moreContentAvailable = false
}
//存儲形式:前n位存儲block長度length,之後length位為實際block
lenBytes, err = s.reader.Peek(peekBytes) //Peek 返回緩存的一個切片,該切片引用緩存中前 peekBytes 個字節的數據
length, n := proto.DecodeVarint(lenBytes) //從切片中讀取 varint 編碼的整數,它返回整數和被消耗的字節數。
    err = s.reader.Discard(n) //丟棄存儲block長度length的前n位
    blockBytes := make([]byte, length)
    _, err = io.ReadAtLeast(s.reader, blockBytes, int(length))
    blockPlacementInfo := &blockPlacementInfo{
        fileNum: s.fileNum,
        blockStartOffset: s.currentOffset,
        blockBytesOffset: s.currentOffset + int64(n)}
    s.currentOffset += int64(n) + int64(length)
    return blockBytes, blockPlacementInfo, nil
//代碼在common/ledger/blkstorage/fsblkstorage/block_stream.go

補充blockPlacementInfo:塊位置信息

type blockPlacementInfo struct {
    fileNum int //塊文件後綴
    blockStartOffset int64 //n+length,n之前
    blockBytesOffset int64 //n+length,length之前
}
//代碼在common/ledger/blkstorage/fsblkstorage/block_stream.go

5、blockfileWriter結構體定義及方法

type blockfileWriter struct {
    filePath string //路徑
    file *os.File //os.File
}

func newBlockfileWriter(filePath string) (*blockfileWriter, error) //構造blockfileWriter,並調用writer.open()
func (w *blockfileWriter) truncateFile(targetSize int) error //截取文件
func (w *blockfileWriter) append(b []byte, sync bool) error //追加文件
func (w *blockfileWriter) open() error //打開文件
func (w *blockfileWriter) close() error //關閉文件
//代碼在common/ledger/blkstorage/fsblkstorage/blockfile_rw.go

6、blockIndex相關結構體及方法

6.1、index接口定義

type index interface {
    getLastBlockIndexed() (uint64, error) //獲取最後一個塊索引(或編號)
    indexBlock(blockIdxInfo *blockIdxInfo) error //索引區塊
    getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) //根據區塊哈希,獲取文件區塊指針
    getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) //根據區塊編號,獲取文件區塊指針
    getTxLoc(txID string) (*fileLocPointer, error) //根據交易ID,獲取文件交易指針
    getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) //根據區塊編號和交易編號,獲取文件交易指針
    getBlockLocByTxID(txID string) (*fileLocPointer, error)//根據交易ID,獲取文件區塊指針
    getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)//根據交易ID,獲取交易驗證代碼
}
//代碼在common/ledger/blkstorage/fsblkstorage/blockindex.go

6.2、blockIndex結構體

blockIndex結構體定義如下:

type blockIndex struct {
    indexItemsMap map[blkstorage.IndexableAttr]bool //index屬性映射
    db *leveldbhelper.DBHandle //index leveldb操作
}
//代碼在common/ledger/blkstorage/fsblkstorage/blockindex.go

補充IndexableAttr:

const (
    IndexableAttrBlockNum = IndexableAttr("BlockNum")
    IndexableAttrBlockHash = IndexableAttr("BlockHash")
    IndexableAttrTxID = IndexableAttr("TxID")
    IndexableAttrBlockNumTranNum = IndexableAttr("BlockNumTranNum")
    IndexableAttrBlockTxID = IndexableAttr("BlockTxID")
    IndexableAttrTxValidationCode = IndexableAttr("TxValidationCode")
)
//代碼在common/ledger/blkstorage/blockstorage.go

兄弟連區塊鏈教程Fabric1.0源代碼分析blockfile區塊文件存儲1