github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/ledger/blkstorage/fsblkstorage/blockindex_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package fsblkstorage
     8  
     9  import (
    10  	"fmt"
    11  	"testing"
    12  
    13  	"github.com/hyperledger/fabric-protos-go/common"
    14  	"github.com/hyperledger/fabric-protos-go/peer"
    15  	"github.com/hyperledger/fabric/common/ledger/blkstorage"
    16  	"github.com/hyperledger/fabric/common/ledger/testutil"
    17  	commonledgerutil "github.com/hyperledger/fabric/common/ledger/util"
    18  	"github.com/hyperledger/fabric/common/metrics/disabled"
    19  	"github.com/hyperledger/fabric/core/ledger/util"
    20  	"github.com/hyperledger/fabric/protoutil"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  )
    24  
    25  type noopIndex struct {
    26  }
    27  
    28  func (i *noopIndex) getLastBlockIndexed() (uint64, error) {
    29  	return 0, nil
    30  }
    31  func (i *noopIndex) indexBlock(blockIdxInfo *blockIdxInfo) error {
    32  	return nil
    33  }
    34  func (i *noopIndex) getBlockLocByHash(blockHash []byte) (*fileLocPointer, error) {
    35  	return nil, nil
    36  }
    37  func (i *noopIndex) getBlockLocByBlockNum(blockNum uint64) (*fileLocPointer, error) {
    38  	return nil, nil
    39  }
    40  func (i *noopIndex) getTxLoc(txID string) (*fileLocPointer, error) {
    41  	return nil, nil
    42  }
    43  func (i *noopIndex) getTXLocByBlockNumTranNum(blockNum uint64, tranNum uint64) (*fileLocPointer, error) {
    44  	return nil, nil
    45  }
    46  
    47  func (i *noopIndex) getBlockLocByTxID(txID string) (*fileLocPointer, error) {
    48  	return nil, nil
    49  }
    50  
    51  func (i *noopIndex) getTxValidationCodeByTxID(txID string) (peer.TxValidationCode, error) {
    52  	return peer.TxValidationCode(-1), nil
    53  }
    54  
    55  func (i *noopIndex) isAttributeIndexed(attribute blkstorage.IndexableAttr) bool {
    56  	return true
    57  }
    58  
    59  func TestBlockIndexSync(t *testing.T) {
    60  	testBlockIndexSync(t, 10, 5, false)
    61  	testBlockIndexSync(t, 10, 5, true)
    62  	testBlockIndexSync(t, 10, 0, true)
    63  	testBlockIndexSync(t, 10, 10, true)
    64  }
    65  
    66  func testBlockIndexSync(t *testing.T, numBlocks int, numBlocksToIndex int, syncByRestart bool) {
    67  	testName := fmt.Sprintf("%v/%v/%v", numBlocks, numBlocksToIndex, syncByRestart)
    68  	t.Run(testName, func(t *testing.T) {
    69  		env := newTestEnv(t, NewConf(testPath(), 0))
    70  		defer env.Cleanup()
    71  		ledgerid := "testledger"
    72  		blkfileMgrWrapper := newTestBlockfileWrapper(env, ledgerid)
    73  		defer blkfileMgrWrapper.close()
    74  		blkfileMgr := blkfileMgrWrapper.blockfileMgr
    75  		origIndex := blkfileMgr.index
    76  		// construct blocks for testing
    77  		blocks := testutil.ConstructTestBlocks(t, numBlocks)
    78  		// add a few blocks
    79  		blkfileMgrWrapper.addBlocks(blocks[:numBlocksToIndex])
    80  
    81  		// Plug-in a noop index and add remaining blocks
    82  		blkfileMgr.index = &noopIndex{}
    83  		blkfileMgrWrapper.addBlocks(blocks[numBlocksToIndex:])
    84  
    85  		// Plug-in back the original index
    86  		blkfileMgr.index = origIndex
    87  		// The first set of blocks should be present in the original index
    88  		for i := 0; i < numBlocksToIndex; i++ {
    89  			block, err := blkfileMgr.retrieveBlockByNumber(uint64(i))
    90  			assert.NoError(t, err, "block [%d] should have been present in the index", i)
    91  			assert.Equal(t, blocks[i], block)
    92  		}
    93  
    94  		// The last set of blocks should not be present in the original index
    95  		for i := numBlocksToIndex + 1; i <= numBlocks; i++ {
    96  			_, err := blkfileMgr.retrieveBlockByNumber(uint64(i))
    97  			assert.Exactly(t, blkstorage.ErrNotFoundInIndex, err)
    98  		}
    99  
   100  		// perform index sync
   101  		if syncByRestart {
   102  			blkfileMgrWrapper.close()
   103  			blkfileMgrWrapper = newTestBlockfileWrapper(env, ledgerid)
   104  			defer blkfileMgrWrapper.close()
   105  			blkfileMgr = blkfileMgrWrapper.blockfileMgr
   106  		} else {
   107  			blkfileMgr.syncIndex()
   108  		}
   109  
   110  		// Now, last set of blocks should also be present in original index
   111  		for i := numBlocksToIndex; i < numBlocks; i++ {
   112  			block, err := blkfileMgr.retrieveBlockByNumber(uint64(i))
   113  			assert.NoError(t, err, "block [%d] should have been present in the index", i)
   114  			assert.Equal(t, blocks[i], block)
   115  		}
   116  	})
   117  }
   118  
   119  func TestBlockIndexSelectiveIndexing(t *testing.T) {
   120  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{})
   121  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{blkstorage.IndexableAttrBlockHash})
   122  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{blkstorage.IndexableAttrBlockNum})
   123  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{blkstorage.IndexableAttrTxID})
   124  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{blkstorage.IndexableAttrBlockNumTranNum})
   125  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{blkstorage.IndexableAttrBlockHash, blkstorage.IndexableAttrBlockNum})
   126  	testBlockIndexSelectiveIndexing(t, []blkstorage.IndexableAttr{blkstorage.IndexableAttrTxID, blkstorage.IndexableAttrBlockNumTranNum})
   127  }
   128  
   129  func testBlockIndexSelectiveIndexing(t *testing.T, indexItems []blkstorage.IndexableAttr) {
   130  	var testName string
   131  	for _, s := range indexItems {
   132  		testName = testName + string(s)
   133  	}
   134  	t.Run(testName, func(t *testing.T) {
   135  		env := newTestEnvSelectiveIndexing(t, NewConf(testPath(), 0), indexItems, &disabled.Provider{})
   136  		defer env.Cleanup()
   137  		blkfileMgrWrapper := newTestBlockfileWrapper(env, "testledger")
   138  		defer blkfileMgrWrapper.close()
   139  
   140  		blocks := testutil.ConstructTestBlocks(t, 3)
   141  		// add test blocks
   142  		blkfileMgrWrapper.addBlocks(blocks)
   143  		blockfileMgr := blkfileMgrWrapper.blockfileMgr
   144  
   145  		// if index has been configured for an indexItem then the item should be indexed else not
   146  		// test 'retrieveBlockByHash'
   147  		block, err := blockfileMgr.retrieveBlockByHash(protoutil.BlockHeaderHash(blocks[0].Header))
   148  		if containsAttr(indexItems, blkstorage.IndexableAttrBlockHash) {
   149  			assert.NoError(t, err, "Error while retrieving block by hash")
   150  			assert.Equal(t, blocks[0], block)
   151  		} else {
   152  			assert.Exactly(t, blkstorage.ErrAttrNotIndexed, err)
   153  		}
   154  
   155  		// test 'retrieveBlockByNumber'
   156  		block, err = blockfileMgr.retrieveBlockByNumber(0)
   157  		if containsAttr(indexItems, blkstorage.IndexableAttrBlockNum) {
   158  			assert.NoError(t, err, "Error while retrieving block by number")
   159  			assert.Equal(t, blocks[0], block)
   160  		} else {
   161  			assert.Exactly(t, blkstorage.ErrAttrNotIndexed, err)
   162  		}
   163  
   164  		// test 'retrieveTransactionByID'
   165  		txid, err := protoutil.GetOrComputeTxIDFromEnvelope(blocks[0].Data.Data[0])
   166  		assert.NoError(t, err)
   167  		txEnvelope, err := blockfileMgr.retrieveTransactionByID(txid)
   168  		if containsAttr(indexItems, blkstorage.IndexableAttrTxID) {
   169  			assert.NoError(t, err, "Error while retrieving tx by id")
   170  			txEnvelopeBytes := blocks[0].Data.Data[0]
   171  			txEnvelopeOrig, err := protoutil.GetEnvelopeFromBlock(txEnvelopeBytes)
   172  			assert.NoError(t, err)
   173  			assert.Equal(t, txEnvelopeOrig, txEnvelope)
   174  		} else {
   175  			assert.Exactly(t, blkstorage.ErrAttrNotIndexed, err)
   176  		}
   177  
   178  		//test 'retrieveTrasnactionsByBlockNumTranNum
   179  		txEnvelope2, err := blockfileMgr.retrieveTransactionByBlockNumTranNum(0, 0)
   180  		if containsAttr(indexItems, blkstorage.IndexableAttrBlockNumTranNum) {
   181  			assert.NoError(t, err, "Error while retrieving tx by blockNum and tranNum")
   182  			txEnvelopeBytes2 := blocks[0].Data.Data[0]
   183  			txEnvelopeOrig2, err2 := protoutil.GetEnvelopeFromBlock(txEnvelopeBytes2)
   184  			assert.NoError(t, err2)
   185  			assert.Equal(t, txEnvelopeOrig2, txEnvelope2)
   186  		} else {
   187  			assert.Exactly(t, blkstorage.ErrAttrNotIndexed, err)
   188  		}
   189  
   190  		// test 'retrieveBlockByTxID'
   191  		txid, err = protoutil.GetOrComputeTxIDFromEnvelope(blocks[0].Data.Data[0])
   192  		assert.NoError(t, err)
   193  		block, err = blockfileMgr.retrieveBlockByTxID(txid)
   194  		if containsAttr(indexItems, blkstorage.IndexableAttrTxID) {
   195  			assert.NoError(t, err, "Error while retrieving block by txID")
   196  			assert.Equal(t, block, blocks[0])
   197  		} else {
   198  			assert.Exactly(t, blkstorage.ErrAttrNotIndexed, err)
   199  		}
   200  
   201  		for _, block := range blocks {
   202  			flags := util.TxValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   203  
   204  			for idx, d := range block.Data.Data {
   205  				txid, err = protoutil.GetOrComputeTxIDFromEnvelope(d)
   206  				assert.NoError(t, err)
   207  
   208  				reason, err := blockfileMgr.retrieveTxValidationCodeByTxID(txid)
   209  
   210  				if containsAttr(indexItems, blkstorage.IndexableAttrTxID) {
   211  					assert.NoError(t, err, "Error while retrieving tx validation code by txID")
   212  
   213  					reasonFromFlags := flags.Flag(idx)
   214  
   215  					assert.Equal(t, reasonFromFlags, reason)
   216  				} else {
   217  					assert.Exactly(t, blkstorage.ErrAttrNotIndexed, err)
   218  				}
   219  			}
   220  		}
   221  	})
   222  }
   223  
   224  func containsAttr(indexItems []blkstorage.IndexableAttr, attr blkstorage.IndexableAttr) bool {
   225  	for _, element := range indexItems {
   226  		if element == attr {
   227  			return true
   228  		}
   229  	}
   230  	return false
   231  }
   232  
   233  func TestTxIDKeyEncoding(t *testing.T) {
   234  	testcases := []struct {
   235  		txid   string
   236  		blkNum uint64
   237  		txNum  uint64
   238  	}{
   239  		{"txid1", 0, 0},
   240  		{"", 1, 1},
   241  		{"", 0, 0},
   242  		{"txid1", 100, 100},
   243  	}
   244  	for i, testcase := range testcases {
   245  		t.Run(fmt.Sprintf(" %d", i),
   246  			func(t *testing.T) {
   247  				verifyTxIDKeyDecodable(t,
   248  					constructTxIDKey(testcase.txid, testcase.blkNum, testcase.txNum),
   249  					testcase.txid, testcase.blkNum, testcase.txNum,
   250  				)
   251  			})
   252  	}
   253  }
   254  
   255  func verifyTxIDKeyDecodable(t *testing.T, txIDKey []byte, expectedTxID string, expectedBlkNum, expectedTxNum uint64) {
   256  	length, lengthBytes, err := commonledgerutil.DecodeOrderPreservingVarUint64(txIDKey[1:])
   257  	require.NoError(t, err)
   258  	firstIndexTxID := 1 + lengthBytes
   259  	firstIndexBlkNum := firstIndexTxID + int(length)
   260  	require.Equal(t, []byte(expectedTxID), txIDKey[firstIndexTxID:firstIndexBlkNum])
   261  
   262  	blkNum, n, err := commonledgerutil.DecodeOrderPreservingVarUint64(txIDKey[firstIndexBlkNum:])
   263  	require.NoError(t, err)
   264  	require.Equal(t, expectedBlkNum, blkNum)
   265  
   266  	firstIndexTxNum := firstIndexBlkNum + n
   267  	txNum, n, err := commonledgerutil.DecodeOrderPreservingVarUint64(txIDKey[firstIndexTxNum:])
   268  	require.NoError(t, err)
   269  	require.Equal(t, expectedTxNum, txNum)
   270  	require.Len(t, txIDKey, firstIndexTxNum+n)
   271  }