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 }