github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/common/ledger/blkstorage/fsblkstorage/rollback_test.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 "os" 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 "github.com/hyperledger/fabric/common/metrics/disabled" 18 "github.com/hyperledger/fabric/protoutil" 19 "github.com/pkg/errors" 20 "github.com/stretchr/testify/assert" 21 ) 22 23 func TestRollback(t *testing.T) { 24 path := testPath() 25 blocks := testutil.ConstructTestBlocks(t, 50) // 50 blocks persisted in ~5 block files 26 blocksPerFile := 50 / 5 27 env := newTestEnv(t, NewConf(path, 0)) 28 defer env.Cleanup() 29 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 30 blkfileMgr := blkfileMgrWrapper.blockfileMgr 31 // 1. Store blocks 32 for i, b := range blocks { 33 assert.NoError(t, blkfileMgr.addBlock(b)) 34 if i != 0 && i%blocksPerFile == 0 { 35 // block ranges in files [(0, 10):file0, (11,20):file1, (21,30):file2, (31, 40):file3, (41,49):file4] 36 blkfileMgr.moveToNextFile() 37 } 38 } 39 40 // 2. Check the BlockchainInfo 41 expectedBlockchainInfo := &common.BlockchainInfo{ 42 Height: 50, 43 CurrentBlockHash: protoutil.BlockHeaderHash(blocks[49].Header), 44 PreviousBlockHash: protoutil.BlockHeaderHash(blocks[48].Header), 45 } 46 actualBlockchainInfo := blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 47 assert.Equal(t, expectedBlockchainInfo, actualBlockchainInfo) 48 49 // 3. Check the checkpointInfo 50 expectedCheckpointInfoLastBlockNumber := uint64(49) 51 expectedCheckpointInfoIsChainEmpty := false 52 actualCheckpointInfo, err := blkfileMgrWrapper.blockfileMgr.loadCurrentInfo() 53 assert.NoError(t, err) 54 assert.Equal(t, expectedCheckpointInfoLastBlockNumber, actualCheckpointInfo.lastBlockNumber) 55 assert.Equal(t, expectedCheckpointInfoIsChainEmpty, actualCheckpointInfo.isChainEmpty) 56 assert.Equal(t, actualCheckpointInfo.latestFileChunkSuffixNum, 4) 57 58 // 4. Check whether all blocks are stored correctly 59 blkfileMgrWrapper.testGetBlockByNumber(blocks, 0, nil) 60 blkfileMgrWrapper.testGetBlockByHash(blocks, nil) 61 blkfileMgrWrapper.testGetBlockByTxID(blocks, nil) 62 63 // 5. Close the blkfileMgrWrapper 64 env.provider.Close() 65 blkfileMgrWrapper.close() 66 lastBlockNumberInLastFile := uint64(49) 67 middleBlockNumberInLastFile := uint64(45) 68 firstBlockNumberInLastFile := uint64(41) 69 70 // 7. Rollback to one before the lastBlockNumberInLastFile 71 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 72 err = Rollback(path, "testLedger", lastBlockNumberInLastFile-uint64(1), indexConfig) 73 assert.NoError(t, err) 74 assertBlockStoreRollback(t, path, "testLedger", blocks, lastBlockNumberInLastFile-uint64(1), 4, indexConfig) 75 76 // 8. Rollback to middleBlockNumberInLastFile 77 err = Rollback(path, "testLedger", middleBlockNumberInLastFile, indexConfig) 78 assert.NoError(t, err) 79 assertBlockStoreRollback(t, path, "testLedger", blocks, middleBlockNumberInLastFile, 4, indexConfig) 80 81 // 9. Rollback to firstBlockNumberInLastFile 82 err = Rollback(path, "testLedger", firstBlockNumberInLastFile, indexConfig) 83 assert.NoError(t, err) 84 assertBlockStoreRollback(t, path, "testLedger", blocks, firstBlockNumberInLastFile, 4, indexConfig) 85 86 // 10. Rollback to one before the firstBlockNumberInLastFile 87 err = Rollback(path, "testLedger", firstBlockNumberInLastFile-1, indexConfig) 88 assert.NoError(t, err) 89 assertBlockStoreRollback(t, path, "testLedger", blocks, firstBlockNumberInLastFile-1, 3, indexConfig) 90 91 // 11. In the middle block file (among a range of block files), find the middle block number 92 middleBlockNumberInMiddleFile := uint64(25) 93 94 // 12. Rollback to middleBlockNumberInMiddleFile 95 err = Rollback(path, "testLedger", middleBlockNumberInMiddleFile, indexConfig) 96 assert.NoError(t, err) 97 assertBlockStoreRollback(t, path, "testLedger", blocks, middleBlockNumberInMiddleFile, 2, indexConfig) 98 99 // 13. Rollback to block 5 100 err = Rollback(path, "testLedger", 5, indexConfig) 101 assert.NoError(t, err) 102 assertBlockStoreRollback(t, path, "testLedger", blocks, 5, 0, indexConfig) 103 104 // 14. Rollback to block 1 105 err = Rollback(path, "testLedger", 1, indexConfig) 106 assert.NoError(t, err) 107 assertBlockStoreRollback(t, path, "testLedger", blocks, 1, 0, indexConfig) 108 } 109 110 // TestRollbackWithOnlyBlockIndexAttributes mimics the scenario when ledger is used for orderer 111 // i.e., only block is index and transancations are not indexed 112 func TestRollbackWithOnlyBlockIndexAttributes(t *testing.T) { 113 path := testPath() 114 blocks := testutil.ConstructTestBlocks(t, 50) // 50 blocks persisted in ~5 block files 115 blocksPerFile := 50 / 5 116 onlyBlockNumIndex := []blkstorage.IndexableAttr{ 117 blkstorage.IndexableAttrBlockNum, 118 } 119 env := newTestEnvSelectiveIndexing(t, NewConf(path, 0), onlyBlockNumIndex, &disabled.Provider{}) 120 defer env.Cleanup() 121 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 122 blkfileMgr := blkfileMgrWrapper.blockfileMgr 123 124 // 1. Store blocks 125 for i, b := range blocks { 126 assert.NoError(t, blkfileMgr.addBlock(b)) 127 if i != 0 && i%blocksPerFile == 0 { 128 // block ranges in files [(0, 10):file0, (11,20):file1, (21,30):file2, (31, 40):file3, (41,49):file4] 129 blkfileMgr.moveToNextFile() 130 } 131 } 132 133 // 2. Check the BlockchainInfo 134 expectedBlockchainInfo := &common.BlockchainInfo{ 135 Height: 50, 136 CurrentBlockHash: protoutil.BlockHeaderHash(blocks[49].Header), 137 PreviousBlockHash: protoutil.BlockHeaderHash(blocks[48].Header), 138 } 139 actualBlockchainInfo := blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 140 assert.Equal(t, expectedBlockchainInfo, actualBlockchainInfo) 141 142 // 3. Check the checkpointInfo 143 expectedCheckpointInfoLastBlockNumber := uint64(49) 144 expectedCheckpointInfoIsChainEmpty := false 145 actualCheckpointInfo, err := blkfileMgrWrapper.blockfileMgr.loadCurrentInfo() 146 assert.NoError(t, err) 147 assert.Equal(t, expectedCheckpointInfoLastBlockNumber, actualCheckpointInfo.lastBlockNumber) 148 assert.Equal(t, expectedCheckpointInfoIsChainEmpty, actualCheckpointInfo.isChainEmpty) 149 assert.Equal(t, actualCheckpointInfo.latestFileChunkSuffixNum, 4) 150 151 // 4. Close the blkfileMgrWrapper 152 env.provider.Close() 153 blkfileMgrWrapper.close() 154 155 // 5. Rollback to block 2 156 onlyBlockNumIndexCfg := &blkstorage.IndexConfig{ 157 AttrsToIndex: onlyBlockNumIndex, 158 } 159 err = Rollback(path, "testLedger", 2, onlyBlockNumIndexCfg) 160 assert.NoError(t, err) 161 assertBlockStoreRollback(t, path, "testLedger", blocks, 2, 0, onlyBlockNumIndexCfg) 162 } 163 164 func TestRollbackWithNoIndexDir(t *testing.T) { 165 path := testPath() 166 blocks := testutil.ConstructTestBlocks(t, 50) 167 blocksPerFile := 50 / 5 168 conf := NewConf(path, 0) 169 env := newTestEnv(t, conf) 170 defer env.Cleanup() 171 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 172 blkfileMgr := blkfileMgrWrapper.blockfileMgr 173 174 // 1. Store blocks 175 for i, b := range blocks { 176 assert.NoError(t, blkfileMgr.addBlock(b)) 177 if i != 0 && i%blocksPerFile == 0 { 178 // block ranges in files [(0, 10):file0, (11,20):file1, (21,30):file2, (31, 40):file3, (41,49):file4] 179 blkfileMgr.moveToNextFile() 180 } 181 } 182 183 // 2. Check the BlockchainInfo 184 expectedBlockchainInfo := &common.BlockchainInfo{ 185 Height: 50, 186 CurrentBlockHash: protoutil.BlockHeaderHash(blocks[49].Header), 187 PreviousBlockHash: protoutil.BlockHeaderHash(blocks[48].Header), 188 } 189 actualBlockchainInfo := blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 190 assert.Equal(t, expectedBlockchainInfo, actualBlockchainInfo) 191 192 // 3. Check the checkpointInfo 193 expectedCheckpointInfoLastBlockNumber := uint64(49) 194 expectedCheckpointInfoIsChainEmpty := false 195 actualCheckpointInfo, err := blkfileMgrWrapper.blockfileMgr.loadCurrentInfo() 196 assert.NoError(t, err) 197 assert.Equal(t, expectedCheckpointInfoLastBlockNumber, actualCheckpointInfo.lastBlockNumber) 198 assert.Equal(t, expectedCheckpointInfoIsChainEmpty, actualCheckpointInfo.isChainEmpty) 199 assert.Equal(t, actualCheckpointInfo.latestFileChunkSuffixNum, 4) 200 201 // 4. Close the blkfileMgrWrapper 202 env.provider.Close() 203 blkfileMgrWrapper.close() 204 205 // 5. Remove the index directory 206 indexDir := conf.getIndexDir() 207 err = os.RemoveAll(indexDir) 208 assert.NoError(t, err) 209 210 // 6. Rollback to block 2 211 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 212 err = Rollback(path, "testLedger", 2, indexConfig) 213 assert.NoError(t, err) 214 assertBlockStoreRollback(t, path, "testLedger", blocks, 2, 0, indexConfig) 215 } 216 217 func TestValidateRollbackParams(t *testing.T) { 218 path := testPath() 219 env := newTestEnv(t, NewConf(path, 1024*24)) 220 defer env.Cleanup() 221 222 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 223 224 // 1. Create 10 blocks 225 blocks := testutil.ConstructTestBlocks(t, 10) 226 blkfileMgrWrapper.addBlocks(blocks) 227 228 // 2. Valid inputs 229 err := ValidateRollbackParams(path, "testLedger", 5) 230 assert.NoError(t, err) 231 232 // 3. ledgerID does not exist 233 err = ValidateRollbackParams(path, "noLedger", 5) 234 assert.Equal(t, "ledgerID [noLedger] does not exist", err.Error()) 235 236 err = ValidateRollbackParams(path, "testLedger", 15) 237 assert.Equal(t, "target block number [15] should be less than the biggest block number [9]", err.Error()) 238 } 239 240 func TestDuplicateTxIDDuringRollback(t *testing.T) { 241 path := testPath() 242 blocks := testutil.ConstructTestBlocks(t, 4) 243 maxFileSize := 1024 * 1024 * 4 244 env := newTestEnv(t, NewConf(path, maxFileSize)) 245 defer env.Cleanup() 246 blkfileMgrWrapper := newTestBlockfileWrapper(env, "testLedger") 247 blocks[3].Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER][0] = byte(peer.TxValidationCode_DUPLICATE_TXID) 248 testutil.SetTxID(t, blocks[3], 0, "tx0") 249 testutil.SetTxID(t, blocks[2], 0, "tx0") 250 251 // 1. Store blocks 252 blkfileMgrWrapper.addBlocks(blocks) 253 254 // 2. Check the BlockchainInfo 255 expectedBlockchainInfo := &common.BlockchainInfo{ 256 Height: 4, 257 CurrentBlockHash: protoutil.BlockHeaderHash(blocks[3].Header), 258 PreviousBlockHash: protoutil.BlockHeaderHash(blocks[2].Header), 259 } 260 actualBlockchainInfo := blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 261 assert.Equal(t, expectedBlockchainInfo, actualBlockchainInfo) 262 263 // 3. Retrieve tx 264 blkfileMgrWrapper.testGetTransactionByTxID("tx0", blocks[2].Data.Data[0], nil) 265 266 // 4. Close the blkfileMgrWrapper 267 env.provider.Close() 268 blkfileMgrWrapper.close() 269 270 // 5. Rollback to block 2 271 indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex} 272 err := Rollback(path, "testLedger", 2, indexConfig) 273 assert.NoError(t, err) 274 275 env = newTestEnv(t, NewConf(path, maxFileSize)) 276 blkfileMgrWrapper = newTestBlockfileWrapper(env, "testLedger") 277 278 // 6. Check the BlockchainInfo 279 expectedBlockchainInfo = &common.BlockchainInfo{ 280 Height: 3, 281 CurrentBlockHash: protoutil.BlockHeaderHash(blocks[2].Header), 282 PreviousBlockHash: protoutil.BlockHeaderHash(blocks[1].Header), 283 } 284 actualBlockchainInfo = blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 285 assert.Equal(t, expectedBlockchainInfo, actualBlockchainInfo) 286 287 // 8. Retrieve tx (should not have been deleted) 288 blkfileMgrWrapper.testGetTransactionByTxID("tx0", blocks[2].Data.Data[0], nil) 289 } 290 291 func assertBlockStoreRollback(t *testing.T, path, ledgerID string, blocks []*common.Block, 292 rollbackedToBlkNum uint64, lastFileSuffixNum int, indexConfig *blkstorage.IndexConfig) { 293 294 env := newTestEnvSelectiveIndexing(t, NewConf(path, 0), indexConfig.AttrsToIndex, &disabled.Provider{}) 295 blkfileMgrWrapper := newTestBlockfileWrapper(env, ledgerID) 296 297 // 1. Check the BlockchainInfo after the rollback 298 expectedBlockchainInfo := &common.BlockchainInfo{ 299 Height: rollbackedToBlkNum + 1, 300 CurrentBlockHash: protoutil.BlockHeaderHash(blocks[rollbackedToBlkNum].Header), 301 PreviousBlockHash: protoutil.BlockHeaderHash(blocks[rollbackedToBlkNum-1].Header), 302 } 303 actualBlockchainInfo := blkfileMgrWrapper.blockfileMgr.getBlockchainInfo() 304 assert.Equal(t, expectedBlockchainInfo, actualBlockchainInfo) 305 306 // 2. Check the checkpointInfo after the rollback 307 expectedCheckpointInfoLastBlockNumber := rollbackedToBlkNum 308 expectedCheckpointInfoIsChainEmpty := false 309 expectedBlockchainInfoLastFileSuffixNum := lastFileSuffixNum 310 actualCheckpointInfo, err := blkfileMgrWrapper.blockfileMgr.loadCurrentInfo() 311 assert.NoError(t, err) 312 assert.Equal(t, expectedCheckpointInfoLastBlockNumber, actualCheckpointInfo.lastBlockNumber) 313 assert.Equal(t, expectedCheckpointInfoIsChainEmpty, actualCheckpointInfo.isChainEmpty) 314 assert.Equal(t, expectedBlockchainInfoLastFileSuffixNum, actualCheckpointInfo.latestFileChunkSuffixNum) 315 316 // 3. Check whether all blocks till the target block number are stored correctly 317 if blkfileMgrWrapper.blockfileMgr.index.isAttributeIndexed(blkstorage.IndexableAttrBlockNum) { 318 blkfileMgrWrapper.testGetBlockByNumber(blocks[:rollbackedToBlkNum+1], 0, nil) 319 } 320 if blkfileMgrWrapper.blockfileMgr.index.isAttributeIndexed(blkstorage.IndexableAttrBlockHash) { 321 blkfileMgrWrapper.testGetBlockByHash(blocks[:rollbackedToBlkNum+1], nil) 322 } 323 if blkfileMgrWrapper.blockfileMgr.index.isAttributeIndexed(blkstorage.IndexableAttrTxID) { 324 blkfileMgrWrapper.testGetBlockByTxID(blocks[:rollbackedToBlkNum+1], nil) 325 } 326 327 // 4. Check whether all blocks with number greater than target block number 328 // are removed including index entries 329 expectedErr := errors.New("Entry not found in index") 330 if blkfileMgrWrapper.blockfileMgr.index.isAttributeIndexed(blkstorage.IndexableAttrBlockHash) { 331 blkfileMgrWrapper.testGetBlockByHash(blocks[rollbackedToBlkNum+1:], expectedErr) 332 } 333 if blkfileMgrWrapper.blockfileMgr.index.isAttributeIndexed(blkstorage.IndexableAttrTxID) { 334 blkfileMgrWrapper.testGetBlockByTxID(blocks[rollbackedToBlkNum+1:], expectedErr) 335 } 336 337 // 5. Close the blkfileMgrWrapper 338 env.provider.Close() 339 blkfileMgrWrapper.close() 340 }