194 lines
6.0 KiB
Go
194 lines
6.0 KiB
Go
/*
|
|
Copyright IBM Corp. All Rights Reserved.
|
|
|
|
SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
package blkstorage
|
|
|
|
import (
|
|
"github.com/golang/protobuf/proto"
|
|
"github.com/hyperledger/fabric-protos-go/common"
|
|
"github.com/hyperledger/fabric/protoutil"
|
|
"github.com/pkg/errors"
|
|
)
|
|
|
|
type serializedBlockInfo struct {
|
|
blockHeader *common.BlockHeader
|
|
txOffsets []*txindexInfo
|
|
metadata *common.BlockMetadata
|
|
}
|
|
|
|
// The order of the transactions must be maintained for history
|
|
type txindexInfo struct {
|
|
txID string
|
|
loc *locPointer
|
|
}
|
|
|
|
func serializeBlock(block *common.Block) ([]byte, *serializedBlockInfo, error) {
|
|
buf := proto.NewBuffer(nil)
|
|
var err error
|
|
info := &serializedBlockInfo{}
|
|
info.blockHeader = block.Header
|
|
info.metadata = block.Metadata
|
|
if err = addHeaderBytes(block.Header, buf); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if info.txOffsets, err = addDataBytesAndConstructTxIndexInfo(block.Data, buf); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
if err = addMetadataBytes(block.Metadata, buf); err != nil {
|
|
return nil, nil, err
|
|
}
|
|
return buf.Bytes(), info, nil
|
|
}
|
|
|
|
func deserializeBlock(serializedBlockBytes []byte) (*common.Block, error) {
|
|
block := &common.Block{}
|
|
var err error
|
|
b := newBuffer(serializedBlockBytes)
|
|
if block.Header, err = extractHeader(b); err != nil {
|
|
return nil, err
|
|
}
|
|
if block.Data, _, err = extractData(b); err != nil {
|
|
return nil, err
|
|
}
|
|
if block.Metadata, err = extractMetadata(b); err != nil {
|
|
return nil, err
|
|
}
|
|
return block, nil
|
|
}
|
|
|
|
func extractSerializedBlockInfo(serializedBlockBytes []byte) (*serializedBlockInfo, error) {
|
|
info := &serializedBlockInfo{}
|
|
var err error
|
|
b := newBuffer(serializedBlockBytes)
|
|
info.blockHeader, err = extractHeader(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
_, info.txOffsets, err = extractData(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
info.metadata, err = extractMetadata(b)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return info, nil
|
|
}
|
|
|
|
func addHeaderBytes(blockHeader *common.BlockHeader, buf *proto.Buffer) error {
|
|
if err := buf.EncodeVarint(blockHeader.Number); err != nil {
|
|
return errors.Wrapf(err, "error encoding the block number [%d]", blockHeader.Number)
|
|
}
|
|
if err := buf.EncodeRawBytes(blockHeader.DataHash); err != nil {
|
|
return errors.Wrapf(err, "error encoding the data hash [%v]", blockHeader.DataHash)
|
|
}
|
|
if err := buf.EncodeRawBytes(blockHeader.PreviousHash); err != nil {
|
|
return errors.Wrapf(err, "error encoding the previous hash [%v]", blockHeader.PreviousHash)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func addDataBytesAndConstructTxIndexInfo(blockData *common.BlockData, buf *proto.Buffer) ([]*txindexInfo, error) {
|
|
var txOffsets []*txindexInfo
|
|
|
|
if err := buf.EncodeVarint(uint64(len(blockData.Data))); err != nil {
|
|
return nil, errors.Wrap(err, "error encoding the length of block data")
|
|
}
|
|
for _, txEnvelopeBytes := range blockData.Data {
|
|
offset := len(buf.Bytes())
|
|
txid, err := protoutil.GetOrComputeTxIDFromEnvelope(txEnvelopeBytes)
|
|
if err != nil {
|
|
logger.Warningf("error while extracting txid from tx envelope bytes during serialization of block. Ignoring this error as this is caused by a malformed transaction. Error:%s",
|
|
err)
|
|
}
|
|
if err := buf.EncodeRawBytes(txEnvelopeBytes); err != nil {
|
|
return nil, errors.Wrap(err, "error encoding the transaction envelope")
|
|
}
|
|
idxInfo := &txindexInfo{txID: txid, loc: &locPointer{offset, len(buf.Bytes()) - offset}}
|
|
txOffsets = append(txOffsets, idxInfo)
|
|
}
|
|
return txOffsets, nil
|
|
}
|
|
|
|
func addMetadataBytes(blockMetadata *common.BlockMetadata, buf *proto.Buffer) error {
|
|
numItems := uint64(0)
|
|
if blockMetadata != nil {
|
|
numItems = uint64(len(blockMetadata.Metadata))
|
|
}
|
|
if err := buf.EncodeVarint(numItems); err != nil {
|
|
return errors.Wrap(err, "error encoding the length of metadata")
|
|
}
|
|
for _, b := range blockMetadata.Metadata {
|
|
if err := buf.EncodeRawBytes(b); err != nil {
|
|
return errors.Wrap(err, "error encoding the block metadata")
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func extractHeader(buf *buffer) (*common.BlockHeader, error) {
|
|
header := &common.BlockHeader{}
|
|
var err error
|
|
if header.Number, err = buf.DecodeVarint(); err != nil {
|
|
return nil, errors.Wrap(err, "error decoding the block number")
|
|
}
|
|
if header.DataHash, err = buf.DecodeRawBytes(false); err != nil {
|
|
return nil, errors.Wrap(err, "error decoding the data hash")
|
|
}
|
|
if header.PreviousHash, err = buf.DecodeRawBytes(false); err != nil {
|
|
return nil, errors.Wrap(err, "error decoding the previous hash")
|
|
}
|
|
if len(header.PreviousHash) == 0 {
|
|
header.PreviousHash = nil
|
|
}
|
|
return header, nil
|
|
}
|
|
|
|
func extractData(buf *buffer) (*common.BlockData, []*txindexInfo, error) {
|
|
data := &common.BlockData{}
|
|
var txOffsets []*txindexInfo
|
|
var numItems uint64
|
|
var err error
|
|
|
|
if numItems, err = buf.DecodeVarint(); err != nil {
|
|
return nil, nil, errors.Wrap(err, "error decoding the length of block data")
|
|
}
|
|
for i := uint64(0); i < numItems; i++ {
|
|
var txEnvBytes []byte
|
|
var txid string
|
|
txOffset := buf.GetBytesConsumed()
|
|
if txEnvBytes, err = buf.DecodeRawBytes(false); err != nil {
|
|
return nil, nil, errors.Wrap(err, "error decoding the transaction envelope")
|
|
}
|
|
if txid, err = protoutil.GetOrComputeTxIDFromEnvelope(txEnvBytes); err != nil {
|
|
logger.Warningf("error while extracting txid from tx envelope bytes during deserialization of block. Ignoring this error as this is caused by a malformed transaction. Error:%s",
|
|
err)
|
|
}
|
|
data.Data = append(data.Data, txEnvBytes)
|
|
idxInfo := &txindexInfo{txID: txid, loc: &locPointer{txOffset, buf.GetBytesConsumed() - txOffset}}
|
|
txOffsets = append(txOffsets, idxInfo)
|
|
}
|
|
return data, txOffsets, nil
|
|
}
|
|
|
|
func extractMetadata(buf *buffer) (*common.BlockMetadata, error) {
|
|
metadata := &common.BlockMetadata{}
|
|
var numItems uint64
|
|
var metadataEntry []byte
|
|
var err error
|
|
if numItems, err = buf.DecodeVarint(); err != nil {
|
|
return nil, errors.Wrap(err, "error decoding the length of block metadata")
|
|
}
|
|
for i := uint64(0); i < numItems; i++ {
|
|
if metadataEntry, err = buf.DecodeRawBytes(false); err != nil {
|
|
return nil, errors.Wrap(err, "error decoding the block metadata")
|
|
}
|
|
metadata.Metadata = append(metadata.Metadata, metadataEntry)
|
|
}
|
|
return metadata, nil
|
|
}
|