github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/ledger/blkstorage/fsblkstorage/block_serialization.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package fsblkstorage 8 9 import ( 10 "github.com/golang/protobuf/proto" 11 "github.com/hyperledger/fabric-protos-go/common" 12 ledgerutil "github.com/hyperledger/fabric/common/ledger/util" 13 "github.com/hyperledger/fabric/protoutil" 14 "github.com/pkg/errors" 15 ) 16 17 type serializedBlockInfo struct { 18 blockHeader *common.BlockHeader 19 txOffsets []*txindexInfo 20 metadata *common.BlockMetadata 21 } 22 23 //The order of the transactions must be maintained for history 24 type txindexInfo struct { 25 txID string 26 loc *locPointer 27 } 28 29 func serializeBlock(block *common.Block) ([]byte, *serializedBlockInfo, error) { 30 buf := proto.NewBuffer(nil) 31 var err error 32 info := &serializedBlockInfo{} 33 info.blockHeader = block.Header 34 info.metadata = block.Metadata 35 if err = addHeaderBytes(block.Header, buf); err != nil { 36 return nil, nil, err 37 } 38 if info.txOffsets, err = addDataBytesAndConstructTxIndexInfo(block.Data, buf); err != nil { 39 return nil, nil, err 40 } 41 if err = addMetadataBytes(block.Metadata, buf); err != nil { 42 return nil, nil, err 43 } 44 return buf.Bytes(), info, nil 45 } 46 47 func deserializeBlock(serializedBlockBytes []byte) (*common.Block, error) { 48 block := &common.Block{} 49 var err error 50 b := ledgerutil.NewBuffer(serializedBlockBytes) 51 if block.Header, err = extractHeader(b); err != nil { 52 return nil, err 53 } 54 if block.Data, _, err = extractData(b); err != nil { 55 return nil, err 56 } 57 if block.Metadata, err = extractMetadata(b); err != nil { 58 return nil, err 59 } 60 return block, nil 61 } 62 63 func extractSerializedBlockInfo(serializedBlockBytes []byte) (*serializedBlockInfo, error) { 64 info := &serializedBlockInfo{} 65 var err error 66 b := ledgerutil.NewBuffer(serializedBlockBytes) 67 info.blockHeader, err = extractHeader(b) 68 if err != nil { 69 return nil, err 70 } 71 _, info.txOffsets, err = extractData(b) 72 if err != nil { 73 return nil, err 74 } 75 76 info.metadata, err = extractMetadata(b) 77 if err != nil { 78 return nil, err 79 } 80 return info, nil 81 } 82 83 func addHeaderBytes(blockHeader *common.BlockHeader, buf *proto.Buffer) error { 84 if err := buf.EncodeVarint(blockHeader.Number); err != nil { 85 return errors.Wrapf(err, "error encoding the block number [%d]", blockHeader.Number) 86 } 87 if err := buf.EncodeRawBytes(blockHeader.DataHash); err != nil { 88 return errors.Wrapf(err, "error encoding the data hash [%v]", blockHeader.DataHash) 89 } 90 if err := buf.EncodeRawBytes(blockHeader.PreviousHash); err != nil { 91 return errors.Wrapf(err, "error encoding the previous hash [%v]", blockHeader.PreviousHash) 92 } 93 return nil 94 } 95 96 func addDataBytesAndConstructTxIndexInfo(blockData *common.BlockData, buf *proto.Buffer) ([]*txindexInfo, error) { 97 var txOffsets []*txindexInfo 98 99 if err := buf.EncodeVarint(uint64(len(blockData.Data))); err != nil { 100 return nil, errors.Wrap(err, "error encoding the length of block data") 101 } 102 for _, txEnvelopeBytes := range blockData.Data { 103 offset := len(buf.Bytes()) 104 txid, err := protoutil.GetOrComputeTxIDFromEnvelope(txEnvelopeBytes) 105 if err != nil { 106 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", 107 err) 108 } 109 if err := buf.EncodeRawBytes(txEnvelopeBytes); err != nil { 110 return nil, errors.Wrap(err, "error encoding the transaction envelope") 111 } 112 idxInfo := &txindexInfo{txID: txid, loc: &locPointer{offset, len(buf.Bytes()) - offset}} 113 txOffsets = append(txOffsets, idxInfo) 114 } 115 return txOffsets, nil 116 } 117 118 func addMetadataBytes(blockMetadata *common.BlockMetadata, buf *proto.Buffer) error { 119 numItems := uint64(0) 120 if blockMetadata != nil { 121 numItems = uint64(len(blockMetadata.Metadata)) 122 } 123 if err := buf.EncodeVarint(numItems); err != nil { 124 return errors.Wrap(err, "error encoding the length of metadata") 125 } 126 for _, b := range blockMetadata.Metadata { 127 if err := buf.EncodeRawBytes(b); err != nil { 128 return errors.Wrap(err, "error encoding the block metadata") 129 } 130 } 131 return nil 132 } 133 134 func extractHeader(buf *ledgerutil.Buffer) (*common.BlockHeader, error) { 135 header := &common.BlockHeader{} 136 var err error 137 if header.Number, err = buf.DecodeVarint(); err != nil { 138 return nil, errors.Wrap(err, "error decoding the block number") 139 } 140 if header.DataHash, err = buf.DecodeRawBytes(false); err != nil { 141 return nil, errors.Wrap(err, "error decoding the data hash") 142 } 143 if header.PreviousHash, err = buf.DecodeRawBytes(false); err != nil { 144 return nil, errors.Wrap(err, "error decoding the previous hash") 145 } 146 if len(header.PreviousHash) == 0 { 147 header.PreviousHash = nil 148 } 149 return header, nil 150 } 151 152 func extractData(buf *ledgerutil.Buffer) (*common.BlockData, []*txindexInfo, error) { 153 data := &common.BlockData{} 154 var txOffsets []*txindexInfo 155 var numItems uint64 156 var err error 157 158 if numItems, err = buf.DecodeVarint(); err != nil { 159 return nil, nil, errors.Wrap(err, "error decoding the length of block data") 160 } 161 for i := uint64(0); i < numItems; i++ { 162 var txEnvBytes []byte 163 var txid string 164 txOffset := buf.GetBytesConsumed() 165 if txEnvBytes, err = buf.DecodeRawBytes(false); err != nil { 166 return nil, nil, errors.Wrap(err, "error decoding the transaction enevelope") 167 } 168 if txid, err = protoutil.GetOrComputeTxIDFromEnvelope(txEnvBytes); err != nil { 169 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", 170 err) 171 172 } 173 data.Data = append(data.Data, txEnvBytes) 174 idxInfo := &txindexInfo{txID: txid, loc: &locPointer{txOffset, buf.GetBytesConsumed() - txOffset}} 175 txOffsets = append(txOffsets, idxInfo) 176 } 177 return data, txOffsets, nil 178 } 179 180 func extractMetadata(buf *ledgerutil.Buffer) (*common.BlockMetadata, error) { 181 metadata := &common.BlockMetadata{} 182 var numItems uint64 183 var metadataEntry []byte 184 var err error 185 if numItems, err = buf.DecodeVarint(); err != nil { 186 return nil, errors.Wrap(err, "error decoding the length of block metadata") 187 } 188 for i := uint64(0); i < numItems; i++ { 189 if metadataEntry, err = buf.DecodeRawBytes(false); err != nil { 190 return nil, errors.Wrap(err, "error decoding the block metadata") 191 } 192 metadata.Metadata = append(metadata.Metadata, metadataEntry) 193 } 194 return metadata, nil 195 }