github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/common/ledger/blkstorage/blockstore_provider_test.go (about)

     1  /*
     2  Copyright hechain. 2022 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/hechain20/hechain/common/ledger/testutil"
    15  	"github.com/hechain20/hechain/internal/pkg/txflags"
    16  	"github.com/hechain20/hechain/protoutil"
    17  	"github.com/hyperledger/fabric-protos-go/common"
    18  	"github.com/hyperledger/fabric-protos-go/peer"
    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, blkNum, err := store.RetrieveTxValidationCodeByTxID(txid)
   134  			require.NoError(t, err)
   135  			require.Equal(t, flags.Flag(txNum), retrievedTxValCode)
   136  			require.Equal(t, uint64(blockNum), blkNum)
   137  		}
   138  	}
   139  }
   140  
   141  func checkWithWrongInputs(t *testing.T, store *BlockStore, numBlocks int) {
   142  	block, err := store.RetrieveBlockByHash([]byte("non-existent-hash"))
   143  	require.Nil(t, block)
   144  	require.EqualError(t, err, fmt.Sprintf("no such block hash [%x] in index", []byte("non-existent-hash")))
   145  
   146  	block, err = store.RetrieveBlockByTxID("non-existent-txid")
   147  	require.Nil(t, block)
   148  	require.EqualError(t, err, "no such transaction ID [non-existent-txid] in index")
   149  
   150  	tx, err := store.RetrieveTxByID("non-existent-txid")
   151  	require.Nil(t, tx)
   152  	require.EqualError(t, err, "no such transaction ID [non-existent-txid] in index")
   153  
   154  	tx, err = store.RetrieveTxByBlockNumTranNum(uint64(numBlocks+1), uint64(0))
   155  	require.Nil(t, tx)
   156  	require.EqualError(t, err, fmt.Sprintf("no such blockNumber, transactionNumber <%d, 0> in index", numBlocks+1))
   157  
   158  	txCode, blkNum, err := store.RetrieveTxValidationCodeByTxID("non-existent-txid")
   159  	require.Equal(t, peer.TxValidationCode(-1), txCode)
   160  	require.Equal(t, uint64(0), blkNum)
   161  	require.EqualError(t, err, "no such transaction ID [non-existent-txid] in index")
   162  }
   163  
   164  func TestBlockStoreProvider(t *testing.T) {
   165  	env := newTestEnv(t, NewConf(testPath(), 0))
   166  	defer env.Cleanup()
   167  
   168  	provider := env.provider
   169  	storeNames, err := provider.List()
   170  	require.NoError(t, err)
   171  	require.Empty(t, storeNames)
   172  
   173  	var stores []*BlockStore
   174  	numStores := 10
   175  	for i := 0; i < numStores; i++ {
   176  		store, _ := provider.Open(constructLedgerid(i))
   177  		defer store.Shutdown()
   178  		stores = append(stores, store)
   179  	}
   180  	require.Equal(t, numStores, len(stores))
   181  
   182  	storeNames, err = provider.List()
   183  	require.NoError(t, err)
   184  	require.Equal(t, numStores, len(storeNames))
   185  
   186  	for i := 0; i < numStores; i++ {
   187  		exists, err := provider.Exists(constructLedgerid(i))
   188  		require.NoError(t, err)
   189  		require.Equal(t, true, exists)
   190  	}
   191  
   192  	exists, err := provider.Exists(constructLedgerid(numStores + 1))
   193  	require.NoError(t, err)
   194  	require.Equal(t, false, exists)
   195  }
   196  
   197  func TestDrop(t *testing.T) {
   198  	env := newTestEnv(t, NewConf(testPath(), 0))
   199  	defer env.Cleanup()
   200  
   201  	provider := env.provider
   202  	store1, err := provider.Open("ledger1")
   203  	require.NoError(t, err)
   204  	defer store1.Shutdown()
   205  	store2, err := provider.Open("ledger2")
   206  	require.NoError(t, err)
   207  	defer store2.Shutdown()
   208  
   209  	blocks1 := addBlocksToStore(t, store1, 5)
   210  	blocks2 := addBlocksToStore(t, store2, 10)
   211  
   212  	checkBlocks(t, blocks1, store1)
   213  	checkBlocks(t, blocks2, store2)
   214  	storeNames, err := provider.List()
   215  	require.NoError(t, err)
   216  	require.ElementsMatch(t, storeNames, []string{"ledger1", "ledger2"})
   217  
   218  	require.NoError(t, provider.Drop("ledger1"))
   219  
   220  	// verify ledger1 block dir and block indexes are deleted
   221  	exists, err := provider.Exists("ledger1")
   222  	require.NoError(t, err)
   223  	require.False(t, exists)
   224  
   225  	empty, err := provider.leveldbProvider.GetDBHandle("ledger1").IsEmpty()
   226  	require.NoError(t, err)
   227  	require.True(t, empty)
   228  
   229  	// verify ledger2 ledger data are remained same
   230  	checkBlocks(t, blocks2, store2)
   231  	storeNames, err = provider.List()
   232  	require.NoError(t, err)
   233  	require.ElementsMatch(t, storeNames, []string{"ledger2"})
   234  
   235  	// drop again should return no error
   236  	require.NoError(t, provider.Drop("ledger1"))
   237  
   238  	// verify "ledger1" store can be opened again after remove, but it is an empty store
   239  	newstore1, err := provider.Open("ledger1")
   240  	require.NoError(t, err)
   241  	bcInfo, err := newstore1.GetBlockchainInfo()
   242  	require.NoError(t, err)
   243  	require.Equal(t, &common.BlockchainInfo{}, bcInfo)
   244  
   245  	// negative test
   246  	provider.Close()
   247  	require.EqualError(t, provider.Drop("ledger2"), "internal leveldb error while obtaining db iterator: leveldb: closed")
   248  }
   249  
   250  func constructLedgerid(id int) string {
   251  	return fmt.Sprintf("ledger_%d", id)
   252  }