1/18兄弟连区块链技术培训Fabric1.0源代码分析(2)blockfile(区块文件存储)#Fabric1.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相关结构体2/18Block结构体:```gotypeBlockstruct{Header*BlockHeader//BlockHeaderData*BlockData//BlockDataMetadata*BlockMetadata}func(m*Block)GetHeader()*BlockHeader//获取BlockHeader,即m.Headerfunc(m*Block)GetData()*BlockData//获取BlockData,即m.Datafunc(m*Block)GetMetadata()*BlockMetadata//m.Metadata//代码在protos/common/common.pb.go```BlockHeader结构体:```gotypeBlockHeaderstruct{Numberuint64//区块编号PreviousHash[]byte//前一个区块哈希DataHash[]byte//当前区块哈希}func(m*BlockHeader)GetNumber()uint64//获取区块编号,即m.Numberfunc(m*BlockHeader)GetPreviousHash()[]byte//获取前一个区块哈希,即m.PreviousHashfunc(m*BlockHeader)GetDataHash()[]byte//获取当前区块哈希,即m.DataHash3/18//代码在protos/common/common.pb.go```BlockData结构体:```gotypeBlockDatastruct{Data[][]byte//Data,存储交易信息}func(m*BlockData)GetData()[][]byte//获取Data,即m.Data//代码在protos/common/common.pb.go```BlockMetadata结构体:```gotypeBlockMetadatastruct{Metadata[][]byte//K/V均为[]byte格式}func(m*BlockMetadata)GetMetadata()[][]byte//m.Metadata//代码在protos/common/common.pb.go```补充BlockMetadataIndex:```gotypeBlockMetadataIndexint32const(BlockMetadataIndex_SIGNATURESBlockMetadataIndex=0BlockMetadataIndex_LAST_CONFIGBlockMetadataIndex=1BlockMetadataIndex_TRANSACTIONS_FILTERBlockMetadataIndex=2BlockMetadataIndex_ORDERERBlockMetadataIndex=3)```###2.2、Block序列化serializedBlockInfo结构体定义及工具函数:```go4/18typeserializedBlockInfostruct{blockHeader*common.BlockHeader//BlockHeadertxOffsets[]*txindexInfo//交易索引信息metadata*common.BlockMetadata}typetxindexInfostruct{txIDstring//交易IDloc*locPointer//文件指针}//序列化区块,返回序列化后字节,以及serializedBlockInfo(含BlockHeader和交易索引信息)funcserializeBlock(block*common.Block)([]byte,*serializedBlockInfo,error)//反序列化区块,构建Block结构体funcdeserializeBlock(serializedBlockBytes[]byte)(*common.Block,error)//反序列化区块,并构造serializedBlockInfofuncextractSerializedBlockInfo(serializedBlockBytes[]byte)(*serializedBlockInfo,error)//序列化中添加BlockHeader,即Number、DataHash和PreviousHashfuncaddHeaderBytes(blockHeader*common.BlockHeader,buf*proto.Buffer)error//序列化中添加BlockData,并从BlockData中解析txid,返回交易索引信息数组funcaddDataBytes(blockData*common.BlockData,buf*proto.Buffer)([]*txindexInfo,error)//序列化中添加MetadatafuncaddMetadataBytes(blockMetadata*common.BlockMetadata,buf*proto.Buffer)error//反序列化出BlockHeaderfuncextractHeader(buf*ledgerutil.Buffer)(*common.BlockHeader,error)//反序列化出BlockData,并返回交易索引信息数组funcextractData(buf*ledgerutil.Buffer)(*common.BlockData,[]*txindexInfo,error)//反序列化出MetadatafuncextractMetadata(buf*ledgerutil.Buffer)(*common.BlockMetadata,error)//从BlockData中解析出交易IDfuncextractTxID(txEnvelopBytes[]byte)(string,error)//代码在common/ledger/blkstorage/fsblkstorage/block_serialization.go```5/18##3、checkpointInfo结构体定义及方法checkpointInfo,即检查点信息,结构体定义如下:```gotypecheckpointInfostruct{latestFileChunkSuffixNumint//最新的区块文件后缀,如blockfile_000000latestFileChunksizeint//最新的区块文件大小isChainEmptybool//是否空链lastBlockNumberuint64//最新的区块编号}//代码在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go```涉及方法如下:```gofunc(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、blockfileStreamblockfileStream定义如下:```gotypeblockfileStreamstruct{fileNumint//blockfile文件后缀file*os.File//os.Filereader*bufio.Reader//bufio.ReadercurrentOffsetint64//当前偏移量}//代码在common/ledger/blkstorage/fsblkstorage/block_stream.go```涉及方法如下:6/18```go//构造blockfileStreamfuncnewBlockfileStream(rootDirstring,fileNumint,startOffsetint64)(*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)代码如下:```govarlenBytes[]bytevarerrerrorvarfileInfoos.FileInfomoreContentAvailable:=truefileInfo,err=s.file.Stat()//获取文件状态remainingBytes:=fi