币安Binance交易所-币安官网注册-币安HT行情价格

区块链教程Fabric1.0源代码分析blockfile区块文件存储

作者:小雷 2021-09-23

  Go语言+区块链教程Fabric1.0源代码分析blockfile区块文件存储一,2018年下半年,区块链行业正逐渐褪去发展之初的浮躁、回归理性,表面上看相关人才需求与身价似乎正在回落。但事实上,正是初期泡沫的渐退,让人们更多的关注点放在了区块链真正的技术之上。

  # 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结构体:

  ```go

  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结构体:

  ```go

  type BlockData struct {

      Data [][]byte //Data,存储交易信息

  func (m *BlockData) GetData() [][]byte //获取Data,即m.Data

  //代码在protos/common/common.pb.go

  BlockMetadata结构体:

  ```go

  type BlockMetadata struct {

      Metadata [][]byte //K/V均为[]byte格式

  func (m *BlockMetadata) GetMetadata() [][]byte //m.Metadata

  //代码在protos/common/common.pb.go

  补充BlockMetadataIndex:

  ```go

  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结构体定义及工具函数:

  ```go

  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,即检查点信息,结构体定义如下:

  ```go

  type checkpointInfo struct {

      latestFileChunkSuffixNum int //最新的区块文件后缀,如blockfile_000000

      latestFileChunksize int //最新的区块文件大小

      isChainEmpty bool //是否空链

      lastBlockNumber uint64 //最新的区块编号

  //代码在common/ledger/blkstorage/fsblkstorage/blockfile_mgr.go

  涉及方法如下:

  ```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定义如下:

  ```go

  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

  涉及方法如下:

  ```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) 代码如下:

  ```go

  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:块位置信息

  ```go

  type blockPlacementInfo struct {

      fileNum int //块文件后缀

      blockStartOffset int64 //n+length,n之前

      blockBytesOffset int64 //n+length,length之前

  //代码在common/ledger/blkstorage/fsblkstorage/block_stream.go

  ## 5、blockfileWriter结构体定义及方法

  ```go

  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接口定义

  ```go

  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结构体定义如下:

  ```go

  type blockIndex struct {

      indexItemsMap map[blkstorage.IndexableAttr]bool //index属性映射

      db *leveldbhelper.DBHandle //index leveldb操作

  //代码在common/ledger/blkstorage/fsblkstorage/blockindex.go

  补充IndexableAttr:

  ```go

  const (

      IndexableAttrBlockNum = IndexableAttr("BlockNum")

      IndexableAttrBlockHash = IndexableAttr("BlockHash")

      IndexableAttrTxID = IndexableAttr("TxID")

      IndexableAttrBlockNumTranNum = IndexableAttr("BlockNumTranNum")

      IndexableAttrBlockTxID = IndexableAttr("BlockTxID")

      IndexableAttrTxValidationCode = IndexableAttr("TxValidationCode")

  //代码在common/ledger/blkstorage/blockstorage.go

  未完待遇欢迎继续关注兄弟连区块链教程分享!

目前有 0 条留言

发表留言

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。