github.com/darrenli6/fabric-sdk-example@v0.0.0-20220109053535-94b13b56df8c/common/ledger/blkstorage/fsblkstorage/blockindex.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8  		 http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package fsblkstorage
    18  
    19  import (
    20  	"bytes"
    21  	"errors"
    22  	"fmt"
    23  
    24  	"github.com/golang/protobuf/proto"
    25  	"github.com/hyperledger/fabric/common/ledger/blkstorage"
    26  	"github.com/hyperledger/fabric/common/ledger/util"
    27  	"github.com/hyperledger/fabric/common/ledger/util/leveldbhelper"
    28  	ledgerUtil "github.com/hyperledger/fabric/core/ledger/util"
    29  	"github.com/hyperledger/fabric/protos/common"
    30  	"github.com/hyperledger/fabric/protos/peer"
    31  )
    32  
    33  const (
    34  	blockNumIdxKeyPrefix           = 'n'
    35  	blockHashIdxKeyPrefix          = 'h'
    36  	txIDIdxKeyPrefix               = 't'
    37  	blockNumTranNumIdxKeyPrefix    = 'a'
    38  	blockTxIDIdxKeyPrefix          = 'b'
    39  	txValidationResultIdxKeyPrefix = 'v'
    40  	indexCheckpointKeyStr          = "indexCheckpointKey"
    41  )
    42  
    43  var indexCheckpointKey = []byte(indexCheckpointKeyStr)
    44  var errIndexEmpty = errors.New("NoBlockIndexed")
    45  
    46  type index interface {
    47  	getLastBlockIndexed() (uint64, error)
    48  	indexBlock(blockIdxInfo *blockIdxInfo) error
    49  	getBlockLocByHash(blockHash []byte) (*fileLocPointer, error)
    50  	getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error)
    51  	getTxLoc(txID string) (*fileLocPointer, error)
    52  	getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error)
    53  	getBlockLocByTxID(txID string) (*fileLocPointer, error)
    54  	getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error)
    55  }
    56  
    57  type blockIdxInfo struct {
    58  	blockNum  uint64
    59  	blockHash []byte
    60  	flp       *fileLocPointer
    61  	txOffsets []*txindexInfo
    62  	metadata  *common.BlockMetadata
    63  }
    64  
    65  type blockIndex struct {
    66  	indexItemsMap map[blkstorage.IndexableAttr]bool
    67  	db            *leveldbhelper.DBHandle
    68  }
    69  
    70  func newBlockIndex(indexConfig *blkstorage.IndexConfig, db *leveldbhelper.DBHandle) *blockIndex {
    71  	indexItems := indexConfig.AttrsToIndex
    72  	logger.Debugf("newBlockIndex() - indexItems:[%s]", indexItems)
    73  	indexItemsMap := make(map[blkstorage.IndexableAttr]bool)
    74  	for _, indexItem := range indexItems {
    75  		indexItemsMap[indexItem] = true
    76  	}
    77  	return &blockIndex{indexItemsMap, db}
    78  }
    79  
    80  func (index *blockIndex) getLastBlockIndexed() (uint64, error) {
    81  	var blockNumBytes []byte
    82  	var err error
    83  	if blockNumBytes, err = index.db.Get(indexCheckpointKey); err != nil {
    84  		return 0, err
    85  	}
    86  	if blockNumBytes == nil {
    87  		return 0, errIndexEmpty
    88  	}
    89  	return decodeBlockNum(blockNumBytes), nil
    90  }
    91  
    92  func (index *blockIndex) indexBlock(blockIdxInfo *blockIdxInfo) error {
    93  	// do not index anything
    94  	if len(index.indexItemsMap) == 0 {
    95  		logger.Debug("Not indexing block... as nothing to index")
    96  		return nil
    97  	}
    98  	logger.Debugf("Indexing block [%s]", blockIdxInfo)
    99  	flp := blockIdxInfo.flp
   100  	txOffsets := blockIdxInfo.txOffsets
   101  	txsfltr := ledgerUtil.TxValidationFlags(blockIdxInfo.metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   102  	batch := leveldbhelper.NewUpdateBatch()
   103  	flpBytes, err := flp.marshal()
   104  	if err != nil {
   105  		return err
   106  	}
   107  
   108  	//Index1
   109  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockHash]; ok {
   110  		batch.Put(constructBlockHashKey(blockIdxInfo.blockHash), flpBytes)
   111  	}
   112  
   113  	//Index2
   114  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNum]; ok {
   115  		batch.Put(constructBlockNumKey(blockIdxInfo.blockNum), flpBytes)
   116  	}
   117  
   118  	//Index3 Used to find a transaction by it's transaction id
   119  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxID]; ok {
   120  		for _, txoffset := range txOffsets {
   121  			txFlp := newFileLocationPointer(flp.fileSuffixNum, flp.offset, txoffset.loc)
   122  			logger.Debugf("Adding txLoc [%s] for tx ID: [%s] to index", txFlp, txoffset.txID)
   123  			txFlpBytes, marshalErr := txFlp.marshal()
   124  			if marshalErr != nil {
   125  				return marshalErr
   126  			}
   127  			batch.Put(constructTxIDKey(txoffset.txID), txFlpBytes)
   128  		}
   129  	}
   130  
   131  	//Index4 - Store BlockNumTranNum will be used to query history data
   132  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNumTranNum]; ok {
   133  		for txIterator, txoffset := range txOffsets {
   134  			txFlp := newFileLocationPointer(flp.fileSuffixNum, flp.offset, txoffset.loc)
   135  			logger.Debugf("Adding txLoc [%s] for tx number:[%d] ID: [%s] to blockNumTranNum index", txFlp, txIterator, txoffset.txID)
   136  			txFlpBytes, marshalErr := txFlp.marshal()
   137  			if marshalErr != nil {
   138  				return marshalErr
   139  			}
   140  			batch.Put(constructBlockNumTranNumKey(blockIdxInfo.blockNum, uint64(txIterator)), txFlpBytes)
   141  		}
   142  	}
   143  
   144  	// Index5 - Store BlockNumber will be used to find block by transaction id
   145  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockTxID]; ok {
   146  		for _, txoffset := range txOffsets {
   147  			batch.Put(constructBlockTxIDKey(txoffset.txID), flpBytes)
   148  		}
   149  	}
   150  
   151  	// Index6 - Store transaction validation result by transaction id
   152  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxValidationCode]; ok {
   153  		for idx, txoffset := range txOffsets {
   154  			batch.Put(constructTxValidationCodeIDKey(txoffset.txID), []byte{byte(txsfltr.Flag(idx))})
   155  		}
   156  	}
   157  
   158  	batch.Put(indexCheckpointKey, encodeBlockNum(blockIdxInfo.blockNum))
   159  	// Setting snyc to true as a precaution, false may be an ok optimization after further testing.
   160  	if err := index.db.WriteBatch(batch, true); err != nil {
   161  		return err
   162  	}
   163  	return nil
   164  }
   165  
   166  func (index *blockIndex) getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) {
   167  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockHash]; !ok {
   168  		return nil, blkstorage.ErrAttrNotIndexed
   169  	}
   170  	b, err := index.db.Get(constructBlockHashKey(blockHash))
   171  	if err != nil {
   172  		return nil, err
   173  	}
   174  	if b == nil {
   175  		return nil, blkstorage.ErrNotFoundInIndex
   176  	}
   177  	blkLoc := &fileLocPointer{}
   178  	blkLoc.unmarshal(b)
   179  	return blkLoc, nil
   180  }
   181  
   182  func (index *blockIndex) getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) {
   183  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNum]; !ok {
   184  		return nil, blkstorage.ErrAttrNotIndexed
   185  	}
   186  	b, err := index.db.Get(constructBlockNumKey(blockNum))
   187  	if err != nil {
   188  		return nil, err
   189  	}
   190  	if b == nil {
   191  		return nil, blkstorage.ErrNotFoundInIndex
   192  	}
   193  	blkLoc := &fileLocPointer{}
   194  	blkLoc.unmarshal(b)
   195  	return blkLoc, nil
   196  }
   197  
   198  func (index *blockIndex) getTxLoc(txID string) (*fileLocPointer, error) {
   199  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxID]; !ok {
   200  		return nil, blkstorage.ErrAttrNotIndexed
   201  	}
   202  	b, err := index.db.Get(constructTxIDKey(txID))
   203  	if err != nil {
   204  		return nil, err
   205  	}
   206  	if b == nil {
   207  		return nil, blkstorage.ErrNotFoundInIndex
   208  	}
   209  	txFLP := &fileLocPointer{}
   210  	txFLP.unmarshal(b)
   211  	return txFLP, nil
   212  }
   213  
   214  func (index *blockIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error) {
   215  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockTxID]; !ok {
   216  		return nil, blkstorage.ErrAttrNotIndexed
   217  	}
   218  	b, err := index.db.Get(constructBlockTxIDKey(txID))
   219  	if err != nil {
   220  		return nil, err
   221  	}
   222  	if b == nil {
   223  		return nil, blkstorage.ErrNotFoundInIndex
   224  	}
   225  	txFLP := &fileLocPointer{}
   226  	txFLP.unmarshal(b)
   227  	return txFLP, nil
   228  }
   229  
   230  func (index *blockIndex) getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) {
   231  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrBlockNumTranNum]; !ok {
   232  		return nil, blkstorage.ErrAttrNotIndexed
   233  	}
   234  	b, err := index.db.Get(constructBlockNumTranNumKey(blockNum, tranNum))
   235  	if err != nil {
   236  		return nil, err
   237  	}
   238  	if b == nil {
   239  		return nil, blkstorage.ErrNotFoundInIndex
   240  	}
   241  	txFLP := &fileLocPointer{}
   242  	txFLP.unmarshal(b)
   243  	return txFLP, nil
   244  }
   245  
   246  func (index *blockIndex) getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
   247  	if _, ok := index.indexItemsMap[blkstorage.IndexableAttrTxValidationCode]; !ok {
   248  		return peer.TxValidationCode(-1), blkstorage.ErrAttrNotIndexed
   249  	}
   250  
   251  	raw, err := index.db.Get(constructTxValidationCodeIDKey(txID))
   252  
   253  	if err != nil {
   254  		return peer.TxValidationCode(-1), err
   255  	} else if raw == nil {
   256  		return peer.TxValidationCode(-1), blkstorage.ErrNotFoundInIndex
   257  	} else if len(raw) != 1 {
   258  		return peer.TxValidationCode(-1), errors.New("Invalid value in indexItems")
   259  	}
   260  
   261  	result := peer.TxValidationCode(int32(raw[0]))
   262  
   263  	return result, nil
   264  }
   265  
   266  func constructBlockNumKey(blockNum uint64) []byte {
   267  	blkNumBytes := util.EncodeOrderPreservingVarUint64(blockNum)
   268  	return append([]byte{blockNumIdxKeyPrefix}, blkNumBytes...)
   269  }
   270  
   271  func constructBlockHashKey(blockHash []byte) []byte {
   272  	return append([]byte{blockHashIdxKeyPrefix}, blockHash...)
   273  }
   274  
   275  func constructTxIDKey(txID string) []byte {
   276  	return append([]byte{txIDIdxKeyPrefix}, []byte(txID)...)
   277  }
   278  
   279  func constructBlockTxIDKey(txID string) []byte {
   280  	return append([]byte{blockTxIDIdxKeyPrefix}, []byte(txID)...)
   281  }
   282  
   283  func constructTxValidationCodeIDKey(txID string) []byte {
   284  	return append([]byte{txValidationResultIdxKeyPrefix}, []byte(txID)...)
   285  }
   286  
   287  func constructBlockNumTranNumKey(blockNum uint64, txNum uint64) []byte {
   288  	blkNumBytes := util.EncodeOrderPreservingVarUint64(blockNum)
   289  	tranNumBytes := util.EncodeOrderPreservingVarUint64(txNum)
   290  	key := append(blkNumBytes, tranNumBytes...)
   291  	return append([]byte{blockNumTranNumIdxKeyPrefix}, key...)
   292  }
   293  
   294  func encodeBlockNum(blockNum uint64) []byte {
   295  	return proto.EncodeVarint(blockNum)
   296  }
   297  
   298  func decodeBlockNum(blockNumBytes []byte) uint64 {
   299  	blockNum, _ := proto.DecodeVarint(blockNumBytes)
   300  	return blockNum
   301  }
   302  
   303  type locPointer struct {
   304  	offset      int
   305  	bytesLength int
   306  }
   307  
   308  func (lp *locPointer) String() string {
   309  	return fmt.Sprintf("offset=%d, bytesLength=%d",
   310  		lp.offset, lp.bytesLength)
   311  }
   312  
   313  // fileLocPointer
   314  type fileLocPointer struct {
   315  	fileSuffixNum int
   316  	locPointer
   317  }
   318  
   319  func newFileLocationPointer(fileSuffixNum int, beginningOffset int, relativeLP *locPointer) *fileLocPointer {
   320  	flp := &fileLocPointer{fileSuffixNum: fileSuffixNum}
   321  	flp.offset = beginningOffset + relativeLP.offset
   322  	flp.bytesLength = relativeLP.bytesLength
   323  	return flp
   324  }
   325  
   326  func (flp *fileLocPointer) marshal() ([]byte, error) {
   327  	buffer := proto.NewBuffer([]byte{})
   328  	e := buffer.EncodeVarint(uint64(flp.fileSuffixNum))
   329  	if e != nil {
   330  		return nil, e
   331  	}
   332  	e = buffer.EncodeVarint(uint64(flp.offset))
   333  	if e != nil {
   334  		return nil, e
   335  	}
   336  	e = buffer.EncodeVarint(uint64(flp.bytesLength))
   337  	if e != nil {
   338  		return nil, e
   339  	}
   340  	return buffer.Bytes(), nil
   341  }
   342  
   343  func (flp *fileLocPointer) unmarshal(b []byte) error {
   344  	buffer := proto.NewBuffer(b)
   345  	i, e := buffer.DecodeVarint()
   346  	if e != nil {
   347  		return e
   348  	}
   349  	flp.fileSuffixNum = int(i)
   350  
   351  	i, e = buffer.DecodeVarint()
   352  	if e != nil {
   353  		return e
   354  	}
   355  	flp.offset = int(i)
   356  	i, e = buffer.DecodeVarint()
   357  	if e != nil {
   358  		return e
   359  	}
   360  	flp.bytesLength = int(i)
   361  	return nil
   362  }
   363  
   364  func (flp *fileLocPointer) String() string {
   365  	return fmt.Sprintf("fileSuffixNum=%d, %s", flp.fileSuffixNum, flp.locPointer.String())
   366  }
   367  
   368  func (blockIdxInfo *blockIdxInfo) String() string {
   369  
   370  	var buffer bytes.Buffer
   371  	for _, txOffset := range blockIdxInfo.txOffsets {
   372  		buffer.WriteString("txId=")
   373  		buffer.WriteString(txOffset.txID)
   374  		buffer.WriteString(" locPointer=")
   375  		buffer.WriteString(txOffset.loc.String())
   376  		buffer.WriteString("\n")
   377  	}
   378  	txOffsetsString := buffer.String()
   379  
   380  	return fmt.Sprintf("blockNum=%d, blockHash=%#v txOffsets=\n%s", blockIdxInfo.blockNum, blockIdxInfo.blockHash, txOffsetsString)
   381  }