github.com/anjalikarhana/fabric@v2.1.1+incompatible/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  }