美文网首页区块链教程
兄弟连区块链教程Fabric1.0源代码分析blockfile区

兄弟连区块链教程Fabric1.0源代码分析blockfile区

作者: ab6973df9221 | 来源:发表于2018-10-26 13:57 被阅读4次

  兄弟连区块链教程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

```

欢迎继续关注兄弟连区块链教程分享:http://bbs.itxdl.cn/read-htm-tid-242411-page-1.html

相关文章

网友评论

    本文标题:兄弟连区块链教程Fabric1.0源代码分析blockfile区

    本文链接:https://www.haomeiwen.com/subject/bliktqtx.html