github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/common/ledger/blkstorage/blockstore_provider_test.go (about)

     1  /*
     2  Copyright IBM Corp. 2016 All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package blkstorage
     8  
     9  import (
    10  	"fmt"
    11  	"os"
    12  	"testing"
    13  
    14  	"github.com/hyperledger/fabric-protos-go/common"
    15  	"github.com/hyperledger/fabric-protos-go/peer"
    16  	"github.com/osdi23p228/fabric/common/ledger/testutil"
    17  	"github.com/osdi23p228/fabric/internal/pkg/txflags"
    18  	"github.com/osdi23p228/fabric/protoutil"
    19  	"github.com/stretchr/testify/require"
    20  )
    21  
    22  func TestIndexConfig(t *testing.T) {
    23  	ic := &IndexConfig{
    24  		AttrsToIndex: []IndexableAttr{
    25  			IndexableAttrBlockNum,
    26  			IndexableAttrTxID,
    27  		},
    28  	}
    29  
    30  	require := require.New(t)
    31  	require.True(ic.Contains(IndexableAttrBlockNum))
    32  	require.True(ic.Contains(IndexableAttrTxID))
    33  	require.False(ic.Contains(IndexableAttrBlockNumTranNum))
    34  }
    35  
    36  func TestMultipleBlockStores(t *testing.T) {
    37  	tempdir := testPath()
    38  	defer os.RemoveAll(tempdir)
    39  
    40  	env := newTestEnv(t, NewConf(tempdir, 0))
    41  	provider := env.provider
    42  	defer provider.Close()
    43  
    44  	subdirs, err := provider.List()
    45  	require.NoError(t, err)
    46  	require.Empty(t, subdirs)
    47  
    48  	store1, err := provider.Open("ledger1")
    49  	require.NoError(t, err)
    50  	defer store1.Shutdown()
    51  	store2, err := provider.Open("ledger2")
    52  	require.NoError(t, err)
    53  	defer store2.Shutdown()
    54  
    55  	blocks1 := addBlocksToStore(t, store1, 5)
    56  	blocks2 := addBlocksToStore(t, store2, 10)
    57  
    58  	checkBlocks(t, blocks1, store1)
    59  	checkBlocks(t, blocks2, store2)
    60  	checkWithWrongInputs(t, store1, 5)
    61  	checkWithWrongInputs(t, store2, 10)
    62  
    63  	store1.Shutdown()
    64  	store2.Shutdown()
    65  	provider.Close()
    66  
    67  	// Reopen provider
    68  	newenv := newTestEnv(t, NewConf(tempdir, 0))
    69  	newprovider := newenv.provider
    70  	defer newprovider.Close()
    71  
    72  	subdirs, err = newprovider.List()
    73  	require.NoError(t, err)
    74  	require.Len(t, subdirs, 2)
    75  
    76  	newstore1, err := newprovider.Open("ledger1")
    77  	require.NoError(t, err)
    78  	defer newstore1.Shutdown()
    79  	newstore2, err := newprovider.Open("ledger2")
    80  	require.NoError(t, err)
    81  	defer newstore2.Shutdown()
    82  
    83  	checkBlocks(t, blocks1, newstore1)
    84  	checkBlocks(t, blocks2, newstore2)
    85  	checkWithWrongInputs(t, newstore1, 5)
    86  	checkWithWrongInputs(t, newstore2, 10)
    87  }
    88  
    89  func addBlocksToStore(t *testing.T, store *BlockStore, numBlocks int) []*common.Block {
    90  	blocks := testutil.ConstructTestBlocks(t, numBlocks)
    91  	for _, b := range blocks {
    92  		err := store.AddBlock(b)
    93  		require.NoError(t, err)
    94  	}
    95  	return blocks
    96  }
    97  
    98  func checkBlocks(t *testing.T, expectedBlocks []*common.Block, store *BlockStore) {
    99  	bcInfo, _ := store.GetBlockchainInfo()
   100  	require.Equal(t, uint64(len(expectedBlocks)), bcInfo.Height)
   101  	require.Equal(t, protoutil.BlockHeaderHash(expectedBlocks[len(expectedBlocks)-1].GetHeader()), bcInfo.CurrentBlockHash)
   102  
   103  	itr, _ := store.RetrieveBlocks(0)
   104  	for i := 0; i < len(expectedBlocks); i++ {
   105  		block, _ := itr.Next()
   106  		require.Equal(t, expectedBlocks[i], block)
   107  	}
   108  
   109  	for blockNum := 0; blockNum < len(expectedBlocks); blockNum++ {
   110  		block := expectedBlocks[blockNum]
   111  		flags := txflags.ValidationFlags(block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   112  		retrievedBlock, _ := store.RetrieveBlockByNumber(uint64(blockNum))
   113  		require.Equal(t, block, retrievedBlock)
   114  
   115  		retrievedBlock, _ = store.RetrieveBlockByHash(protoutil.BlockHeaderHash(block.Header))
   116  		require.Equal(t, block, retrievedBlock)
   117  
   118  		for txNum := 0; txNum < len(block.Data.Data); txNum++ {
   119  			txEnvBytes := block.Data.Data[txNum]
   120  			txEnv, _ := protoutil.GetEnvelopeFromBlock(txEnvBytes)
   121  			txid, err := protoutil.GetOrComputeTxIDFromEnvelope(txEnvBytes)
   122  			require.NoError(t, err)
   123  
   124  			retrievedBlock, _ := store.RetrieveBlockByTxID(txid)
   125  			require.Equal(t, block, retrievedBlock)
   126  
   127  			retrievedTxEnv, _ := store.RetrieveTxByID(txid)
   128  			require.Equal(t, txEnv, retrievedTxEnv)
   129  
   130  			retrievedTxEnv, _ = store.RetrieveTxByBlockNumTranNum(uint64(blockNum), uint64(txNum))
   131  			require.Equal(t, txEnv, retrievedTxEnv)
   132  
   133  			retrievedTxValCode, err := store.RetrieveTxValidationCodeByTxID(txid)
   134  			require.NoError(t, err)
   135  			require.Equal(t, flags.Flag(txNum), retrievedTxValCode)
   136  		}
   137  	}
   138  }
   139  
   140  func checkWithWrongInputs(t *testing.T, store *BlockStore, numBlocks int) {
   141  	block, err := store.RetrieveBlockByHash([]byte("non-existent-hash"))
   142  	require.Nil(t, block)
   143  	require.Equal(t, ErrNotFoundInIndex, err)
   144  
   145  	block, err = store.RetrieveBlockByTxID("non-existent-txid")
   146  	require.Nil(t, block)
   147  	require.Equal(t, ErrNotFoundInIndex, err)
   148  
   149  	tx, err := store.RetrieveTxByID("non-existent-txid")
   150  	require.Nil(t, tx)
   151  	require.Equal(t, ErrNotFoundInIndex, err)
   152  
   153  	tx, err = store.RetrieveTxByBlockNumTranNum(uint64(numBlocks+1), uint64(0))
   154  	require.Nil(t, tx)
   155  	require.Equal(t, ErrNotFoundInIndex, err)
   156  
   157  	txCode, err := store.RetrieveTxValidationCodeByTxID("non-existent-txid")
   158  	require.Equal(t, peer.TxValidationCode(-1), txCode)
   159  	require.Equal(t, ErrNotFoundInIndex, err)
   160  }
   161  
   162  func TestBlockStoreProvider(t *testing.T) {
   163  	env := newTestEnv(t, NewConf(testPath(), 0))
   164  	defer env.Cleanup()
   165  
   166  	provider := env.provider
   167  	storeNames, err := provider.List()
   168  	require.NoError(t, err)
   169  	require.Empty(t, storeNames)
   170  
   171  	var stores []*BlockStore
   172  	numStores := 10
   173  	for i := 0; i < numStores; i++ {
   174  		store, _ := provider.Open(constructLedgerid(i))
   175  		defer store.Shutdown()
   176  		stores = append(stores, store)
   177  	}
   178  	require.Equal(t, numStores, len(stores))
   179  
   180  	storeNames, err = provider.List()
   181  	require.NoError(t, err)
   182  	require.Equal(t, numStores, len(storeNames))
   183  
   184  	for i := 0; i < numStores; i++ {
   185  		exists, err := provider.Exists(constructLedgerid(i))
   186  		require.NoError(t, err)
   187  		require.Equal(t, true, exists)
   188  	}
   189  
   190  	exists, err := provider.Exists(constructLedgerid(numStores + 1))
   191  	require.NoError(t, err)
   192  	require.Equal(t, false, exists)
   193  
   194  }
   195  
   196  func TestRemove(t *testing.T) {
   197  	env := newTestEnv(t, NewConf(testPath(), 0))
   198  	defer env.Cleanup()
   199  
   200  	provider := env.provider
   201  	store1, err := provider.Open("ledger1")
   202  	require.NoError(t, err)
   203  	defer store1.Shutdown()
   204  	store2, err := provider.Open("ledger2")
   205  	require.NoError(t, err)
   206  	defer store2.Shutdown()
   207  
   208  	blocks1 := addBlocksToStore(t, store1, 5)
   209  	blocks2 := addBlocksToStore(t, store2, 10)
   210  
   211  	checkBlocks(t, blocks1, store1)
   212  	checkBlocks(t, blocks2, store2)
   213  	storeNames, err := provider.List()
   214  	require.NoError(t, err)
   215  	require.ElementsMatch(t, storeNames, []string{"ledger1", "ledger2"})
   216  
   217  	require.NoError(t, provider.Remove("ledger1"))
   218  
   219  	// verify ledger1 block dir and block indexes are deleted
   220  	exists, err := provider.Exists("ledger1")
   221  	require.NoError(t, err)
   222  	require.False(t, exists)
   223  	itr, err := provider.leveldbProvider.GetDBHandle("ledger1").GetIterator(nil, nil)
   224  	require.NoError(t, err)
   225  	defer itr.Release()
   226  	require.False(t, itr.Next())
   227  
   228  	// verify ledger2 ledger data are remained same
   229  	checkBlocks(t, blocks2, store2)
   230  	storeNames, err = provider.List()
   231  	require.NoError(t, err)
   232  	require.ElementsMatch(t, storeNames, []string{"ledger2"})
   233  
   234  	// remove again should return no error
   235  	require.NoError(t, provider.Remove("ledger1"))
   236  
   237  	// verify "ledger1" store can be opened again after remove, but it is an empty store
   238  	newstore1, err := provider.Open("ledger1")
   239  	require.NoError(t, err)
   240  	bcInfo, err := newstore1.GetBlockchainInfo()
   241  	require.NoError(t, err)
   242  	require.Equal(t, &common.BlockchainInfo{}, bcInfo)
   243  
   244  	// negative test
   245  	provider.Close()
   246  	require.EqualError(t, provider.Remove("ledger2"), "internal leveldb error while obtaining db iterator: leveldb: closed")
   247  }
   248  
   249  func constructLedgerid(id int) string {
   250  	return fmt.Sprintf("ledger_%d", id)
   251  }