github.com/hechain20/hechain@v0.0.0-20220316014945-b544036ba106/core/transientstore/store_test.go (about)

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package transientstore
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"path/filepath"
    14  	"sort"
    15  	"testing"
    16  
    17  	"github.com/golang/protobuf/proto"
    18  	"github.com/hechain20/hechain/common/policydsl"
    19  	commonutil "github.com/hechain20/hechain/common/util"
    20  	"github.com/hechain20/hechain/core/ledger"
    21  	"github.com/hechain20/hechain/core/ledger/util"
    22  	"github.com/hyperledger/fabric-protos-go/common"
    23  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    24  	"github.com/hyperledger/fabric-protos-go/peer"
    25  	"github.com/hyperledger/fabric-protos-go/transientstore"
    26  	"github.com/stretchr/testify/require"
    27  )
    28  
    29  func TestMain(m *testing.M) {
    30  	tempdir, err := ioutil.TempDir("", "ts")
    31  	if err != nil {
    32  		panic(err)
    33  	}
    34  
    35  	rc := m.Run()
    36  
    37  	os.RemoveAll(tempdir)
    38  	os.Exit(rc)
    39  }
    40  
    41  type testEnv struct {
    42  	storeProvider StoreProvider
    43  	store         *Store
    44  	tempdir       string
    45  	storedir      string
    46  	cleanup       func()
    47  }
    48  
    49  func initTestEnv(t *testing.T) *testEnv {
    50  	tempdir, err := ioutil.TempDir("", "ts")
    51  	require.NoErrorf(t, err, "failed to create test directory [%s]", tempdir)
    52  
    53  	storedir := filepath.Join(tempdir, "transientstore")
    54  	storeProvider, err := NewStoreProvider(storedir)
    55  	require.NoError(t, err)
    56  	require.NotNil(t, storeProvider)
    57  
    58  	store, err := storeProvider.OpenStore("TestStore")
    59  	require.NoError(t, err)
    60  	require.NotNil(t, store)
    61  
    62  	return &testEnv{
    63  		storeProvider: storeProvider,
    64  		store:         store,
    65  		tempdir:       tempdir,
    66  		storedir:      storedir,
    67  		cleanup: func() {
    68  			require.NoError(t, os.RemoveAll(tempdir))
    69  		},
    70  	}
    71  }
    72  
    73  func TestPurgeIndexKeyCodingEncoding(t *testing.T) {
    74  	require := require.New(t)
    75  	blkHts := []uint64{0, 10, 20000}
    76  	txids := []string{"txid", ""}
    77  	uuids := []string{"uuid", ""}
    78  	for _, blkHt := range blkHts {
    79  		for _, txid := range txids {
    80  			for _, uuid := range uuids {
    81  				testCase := fmt.Sprintf("blkHt=%d,txid=%s,uuid=%s", blkHt, txid, uuid)
    82  				t.Run(testCase, func(t *testing.T) {
    83  					t.Logf("Running test case [%s]", testCase)
    84  					purgeIndexKey := createCompositeKeyForPurgeIndexByHeight(blkHt, txid, uuid)
    85  					txid1, uuid1, blkHt1, err := splitCompositeKeyOfPurgeIndexByHeight(purgeIndexKey)
    86  					require.NoError(err)
    87  					require.Equal(txid, txid1)
    88  					require.Equal(uuid, uuid1)
    89  					require.Equal(blkHt, blkHt1)
    90  				})
    91  			}
    92  		}
    93  	}
    94  }
    95  
    96  func TestRWSetKeyCodingEncoding(t *testing.T) {
    97  	require := require.New(t)
    98  	blkHts := []uint64{0, 10, 20000}
    99  	txids := []string{"txid", ""}
   100  	uuids := []string{"uuid", ""}
   101  	for _, blkHt := range blkHts {
   102  		for _, txid := range txids {
   103  			for _, uuid := range uuids {
   104  				testCase := fmt.Sprintf("blkHt=%d,txid=%s,uuid=%s", blkHt, txid, uuid)
   105  				t.Run(testCase, func(t *testing.T) {
   106  					t.Logf("Running test case [%s]", testCase)
   107  					rwsetKey := createCompositeKeyForPvtRWSet(txid, uuid, blkHt)
   108  					uuid1, blkHt1, err := splitCompositeKeyOfPvtRWSet(rwsetKey)
   109  					require.NoError(err)
   110  					require.Equal(uuid, uuid1)
   111  					require.Equal(blkHt, blkHt1)
   112  				})
   113  			}
   114  		}
   115  	}
   116  }
   117  
   118  func TestTransientStorePersistAndRetrieve(t *testing.T) {
   119  	env := initTestEnv(t)
   120  	defer env.cleanup()
   121  	testStore := env.store
   122  	require := require.New(t)
   123  	txid := "txid-1"
   124  	samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t)
   125  
   126  	// Create private simulation results for txid-1
   127  	var endorsersResults []*EndorserPvtSimulationResults
   128  
   129  	// Results produced by endorser 1
   130  	endorser0SimulationResults := &EndorserPvtSimulationResults{
   131  		ReceivedAtBlockHeight:          10,
   132  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   133  	}
   134  	endorsersResults = append(endorsersResults, endorser0SimulationResults)
   135  
   136  	// Results produced by endorser 2
   137  	endorser1SimulationResults := &EndorserPvtSimulationResults{
   138  		ReceivedAtBlockHeight:          10,
   139  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   140  	}
   141  	endorsersResults = append(endorsersResults, endorser1SimulationResults)
   142  
   143  	// Persist simulation results into  store
   144  	var err error
   145  	for i := 0; i < len(endorsersResults); i++ {
   146  		err = testStore.Persist(txid, endorsersResults[i].ReceivedAtBlockHeight,
   147  			endorsersResults[i].PvtSimulationResultsWithConfig)
   148  		require.NoError(err)
   149  	}
   150  
   151  	// Retrieve simulation results of txid-1 from  store
   152  	iter, err := testStore.GetTxPvtRWSetByTxid(txid, nil)
   153  	require.NoError(err)
   154  
   155  	var actualEndorsersResults []*EndorserPvtSimulationResults
   156  	for {
   157  		result, err := iter.Next()
   158  		require.NoError(err)
   159  		if result == nil {
   160  			break
   161  		}
   162  		actualEndorsersResults = append(actualEndorsersResults, result)
   163  	}
   164  	iter.Close()
   165  	sortResults(endorsersResults)
   166  	sortResults(actualEndorsersResults)
   167  	require.Equal(endorsersResults, actualEndorsersResults)
   168  }
   169  
   170  func TestTransientStorePersistAndRetrieveBothOldAndNewProto(t *testing.T) {
   171  	env := initTestEnv(t)
   172  	defer env.cleanup()
   173  	testStore := env.store
   174  	require := require.New(t)
   175  	txid := "txid-1"
   176  	var receivedAtBlockHeight uint64 = 10
   177  	var err error
   178  
   179  	// Create and persist private simulation results with old proto for txid-1
   180  	samplePvtRWSet := samplePvtData(t)
   181  	err = testStore.persistOldProto(txid, receivedAtBlockHeight, samplePvtRWSet)
   182  	require.NoError(err)
   183  
   184  	// Create and persist private simulation results with new proto for txid-1
   185  	samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t)
   186  	err = testStore.Persist(txid, receivedAtBlockHeight, samplePvtRWSetWithConfig)
   187  	require.NoError(err)
   188  
   189  	// Construct the expected results
   190  	var expectedEndorsersResults []*EndorserPvtSimulationResults
   191  
   192  	pvtRWSetWithConfigInfo := &transientstore.TxPvtReadWriteSetWithConfigInfo{
   193  		PvtRwset: samplePvtRWSet,
   194  	}
   195  
   196  	endorser0SimulationResults := &EndorserPvtSimulationResults{
   197  		ReceivedAtBlockHeight:          receivedAtBlockHeight,
   198  		PvtSimulationResultsWithConfig: pvtRWSetWithConfigInfo,
   199  	}
   200  	expectedEndorsersResults = append(expectedEndorsersResults, endorser0SimulationResults)
   201  
   202  	endorser1SimulationResults := &EndorserPvtSimulationResults{
   203  		ReceivedAtBlockHeight:          receivedAtBlockHeight,
   204  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   205  	}
   206  	expectedEndorsersResults = append(expectedEndorsersResults, endorser1SimulationResults)
   207  
   208  	// Retrieve simulation results of txid-1 from  store
   209  	iter, err := testStore.GetTxPvtRWSetByTxid(txid, nil)
   210  	require.NoError(err)
   211  
   212  	var actualEndorsersResults []*EndorserPvtSimulationResults
   213  	for {
   214  		result, err := iter.Next()
   215  		require.NoError(err)
   216  		if result == nil {
   217  			break
   218  		}
   219  		actualEndorsersResults = append(actualEndorsersResults, result)
   220  	}
   221  	iter.Close()
   222  	sortResults(expectedEndorsersResults)
   223  	sortResults(actualEndorsersResults)
   224  	require.Equal(expectedEndorsersResults, actualEndorsersResults)
   225  }
   226  
   227  func TestTransientStorePurgeByTxids(t *testing.T) {
   228  	env := initTestEnv(t)
   229  	defer env.cleanup()
   230  	testStore := env.store
   231  	require := require.New(t)
   232  
   233  	var txids []string
   234  	var endorsersResults []*EndorserPvtSimulationResults
   235  
   236  	samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t)
   237  
   238  	// Create two private write set entry for txid-1
   239  	txids = append(txids, "txid-1")
   240  	endorser0SimulationResults := &EndorserPvtSimulationResults{
   241  		ReceivedAtBlockHeight:          10,
   242  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   243  	}
   244  	endorsersResults = append(endorsersResults, endorser0SimulationResults)
   245  
   246  	txids = append(txids, "txid-1")
   247  	endorser1SimulationResults := &EndorserPvtSimulationResults{
   248  		ReceivedAtBlockHeight:          11,
   249  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   250  	}
   251  	endorsersResults = append(endorsersResults, endorser1SimulationResults)
   252  
   253  	// Create one private write set entry for txid-2
   254  	txids = append(txids, "txid-2")
   255  	endorser2SimulationResults := &EndorserPvtSimulationResults{
   256  		ReceivedAtBlockHeight:          11,
   257  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   258  	}
   259  	endorsersResults = append(endorsersResults, endorser2SimulationResults)
   260  
   261  	// Create three private write set entry for txid-3
   262  	txids = append(txids, "txid-3")
   263  	endorser3SimulationResults := &EndorserPvtSimulationResults{
   264  		ReceivedAtBlockHeight:          12,
   265  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   266  	}
   267  	endorsersResults = append(endorsersResults, endorser3SimulationResults)
   268  
   269  	txids = append(txids, "txid-3")
   270  	endorser4SimulationResults := &EndorserPvtSimulationResults{
   271  		ReceivedAtBlockHeight:          12,
   272  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   273  	}
   274  	endorsersResults = append(endorsersResults, endorser4SimulationResults)
   275  
   276  	txids = append(txids, "txid-3")
   277  	endorser5SimulationResults := &EndorserPvtSimulationResults{
   278  		ReceivedAtBlockHeight:          13,
   279  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   280  	}
   281  	endorsersResults = append(endorsersResults, endorser5SimulationResults)
   282  
   283  	var err error
   284  	for i := 0; i < len(txids); i++ {
   285  		err = testStore.Persist(txids[i], endorsersResults[i].ReceivedAtBlockHeight,
   286  			endorsersResults[i].PvtSimulationResultsWithConfig)
   287  		require.NoError(err)
   288  	}
   289  
   290  	// Retrieve simulation results of txid-2 from  store
   291  	iter, err := testStore.GetTxPvtRWSetByTxid("txid-2", nil)
   292  	require.NoError(err)
   293  
   294  	// Expected results for txid-2
   295  	var expectedEndorsersResults []*EndorserPvtSimulationResults
   296  	expectedEndorsersResults = append(expectedEndorsersResults, endorser2SimulationResults)
   297  
   298  	// Check whether actual results and expected results are same
   299  	var actualEndorsersResults []*EndorserPvtSimulationResults
   300  	for {
   301  		result, err := iter.Next()
   302  		require.NoError(err)
   303  		if result == nil {
   304  			break
   305  		}
   306  		actualEndorsersResults = append(actualEndorsersResults, result)
   307  	}
   308  	iter.Close()
   309  
   310  	// Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting
   311  	// expectedRes and actualRes.
   312  	sortResults(expectedEndorsersResults)
   313  	sortResults(actualEndorsersResults)
   314  
   315  	require.Equal(len(expectedEndorsersResults), len(actualEndorsersResults))
   316  	for i, expected := range expectedEndorsersResults {
   317  		require.Equal(expected.ReceivedAtBlockHeight, actualEndorsersResults[i].ReceivedAtBlockHeight)
   318  		require.True(proto.Equal(expected.PvtSimulationResultsWithConfig, actualEndorsersResults[i].PvtSimulationResultsWithConfig))
   319  	}
   320  
   321  	// Remove all private write set of txid-2 and txid-3
   322  	toRemoveTxids := []string{"txid-2", "txid-3"}
   323  	err = testStore.PurgeByTxids(toRemoveTxids)
   324  	require.NoError(err)
   325  
   326  	for _, txid := range toRemoveTxids {
   327  
   328  		// Check whether private write sets of txid-2 are removed
   329  		var expectedEndorsersResults *EndorserPvtSimulationResults = nil
   330  		iter, err = testStore.GetTxPvtRWSetByTxid(txid, nil)
   331  		require.NoError(err)
   332  		// Should return nil, nil
   333  		result, err := iter.Next()
   334  		require.NoError(err)
   335  		require.Equal(expectedEndorsersResults, result)
   336  	}
   337  
   338  	// Retrieve simulation results of txid-1 from store
   339  	iter, err = testStore.GetTxPvtRWSetByTxid("txid-1", nil)
   340  	require.NoError(err)
   341  
   342  	// Expected results for txid-1
   343  	expectedEndorsersResults = nil
   344  	expectedEndorsersResults = append(expectedEndorsersResults, endorser0SimulationResults)
   345  	expectedEndorsersResults = append(expectedEndorsersResults, endorser1SimulationResults)
   346  
   347  	// Check whether actual results and expected results are same
   348  	actualEndorsersResults = nil
   349  	for {
   350  		result, err := iter.Next()
   351  		require.NoError(err)
   352  		if result == nil {
   353  			break
   354  		}
   355  		actualEndorsersResults = append(actualEndorsersResults, result)
   356  	}
   357  	iter.Close()
   358  
   359  	// Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting
   360  	// expectedRes and actualRes.
   361  	sortResults(expectedEndorsersResults)
   362  	sortResults(actualEndorsersResults)
   363  
   364  	require.Equal(len(expectedEndorsersResults), len(actualEndorsersResults))
   365  	for i, expected := range expectedEndorsersResults {
   366  		require.Equal(expected.ReceivedAtBlockHeight, actualEndorsersResults[i].ReceivedAtBlockHeight)
   367  		require.True(proto.Equal(expected.PvtSimulationResultsWithConfig, actualEndorsersResults[i].PvtSimulationResultsWithConfig))
   368  	}
   369  
   370  	toRemoveTxids = []string{"txid-1"}
   371  	err = testStore.PurgeByTxids(toRemoveTxids)
   372  	require.NoError(err)
   373  
   374  	for _, txid := range toRemoveTxids {
   375  
   376  		// Check whether private write sets of txid-1 are removed
   377  		var expectedEndorsersResults *EndorserPvtSimulationResults = nil
   378  		iter, err = testStore.GetTxPvtRWSetByTxid(txid, nil)
   379  		require.NoError(err)
   380  		// Should return nil, nil
   381  		result, err := iter.Next()
   382  		require.NoError(err)
   383  		require.Equal(expectedEndorsersResults, result)
   384  	}
   385  
   386  	// There should be no entries in the  store
   387  	_, err = testStore.GetMinTransientBlkHt()
   388  	require.Equal(err, ErrStoreEmpty)
   389  }
   390  
   391  func TestTransientStorePurgeBelowHeight(t *testing.T) {
   392  	env := initTestEnv(t)
   393  	defer env.cleanup()
   394  	testStore := env.store
   395  	require := require.New(t)
   396  
   397  	txid := "txid-1"
   398  	samplePvtRWSetWithConfig := samplePvtDataWithConfigInfo(t)
   399  
   400  	// Create private simulation results for txid-1
   401  	var endorsersResults []*EndorserPvtSimulationResults
   402  
   403  	// Results produced by endorser 1
   404  	endorser0SimulationResults := &EndorserPvtSimulationResults{
   405  		ReceivedAtBlockHeight:          10,
   406  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   407  	}
   408  	endorsersResults = append(endorsersResults, endorser0SimulationResults)
   409  
   410  	// Results produced by endorser 2
   411  	endorser1SimulationResults := &EndorserPvtSimulationResults{
   412  		ReceivedAtBlockHeight:          11,
   413  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   414  	}
   415  	endorsersResults = append(endorsersResults, endorser1SimulationResults)
   416  
   417  	// Results produced by endorser 3
   418  	endorser2SimulationResults := &EndorserPvtSimulationResults{
   419  		ReceivedAtBlockHeight:          12,
   420  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   421  	}
   422  	endorsersResults = append(endorsersResults, endorser2SimulationResults)
   423  
   424  	// Results produced by endorser 4
   425  	endorser3SimulationResults := &EndorserPvtSimulationResults{
   426  		ReceivedAtBlockHeight:          12,
   427  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   428  	}
   429  	endorsersResults = append(endorsersResults, endorser3SimulationResults)
   430  
   431  	// Results produced by endorser 5
   432  	endorser4SimulationResults := &EndorserPvtSimulationResults{
   433  		ReceivedAtBlockHeight:          13,
   434  		PvtSimulationResultsWithConfig: samplePvtRWSetWithConfig,
   435  	}
   436  	endorsersResults = append(endorsersResults, endorser4SimulationResults)
   437  
   438  	// Persist simulation results into  store
   439  	var err error
   440  	for i := 0; i < 5; i++ {
   441  		err = testStore.Persist(txid, endorsersResults[i].ReceivedAtBlockHeight,
   442  			endorsersResults[i].PvtSimulationResultsWithConfig)
   443  		require.NoError(err)
   444  	}
   445  
   446  	// Retain results generate at block height greater than or equal to 12
   447  	minTransientBlkHtToRetain := uint64(12)
   448  	err = testStore.PurgeBelowHeight(minTransientBlkHtToRetain)
   449  	require.NoError(err)
   450  
   451  	// Retrieve simulation results of txid-1 from  store
   452  	iter, err := testStore.GetTxPvtRWSetByTxid(txid, nil)
   453  	require.NoError(err)
   454  
   455  	// Expected results for txid-1
   456  	var expectedEndorsersResults []*EndorserPvtSimulationResults
   457  	expectedEndorsersResults = append(expectedEndorsersResults, endorser2SimulationResults) // endorsed at height 12
   458  	expectedEndorsersResults = append(expectedEndorsersResults, endorser3SimulationResults) // endorsed at height 12
   459  	expectedEndorsersResults = append(expectedEndorsersResults, endorser4SimulationResults) // endorsed at height 13
   460  
   461  	// Check whether actual results and expected results are same
   462  	var actualEndorsersResults []*EndorserPvtSimulationResults
   463  	for {
   464  		result, err := iter.Next()
   465  		require.NoError(err)
   466  		if result == nil {
   467  			break
   468  		}
   469  		actualEndorsersResults = append(actualEndorsersResults, result)
   470  	}
   471  	iter.Close()
   472  
   473  	// Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting
   474  	// expectedRes and actualRes.
   475  	sortResults(expectedEndorsersResults)
   476  	sortResults(actualEndorsersResults)
   477  
   478  	require.Equal(len(expectedEndorsersResults), len(actualEndorsersResults))
   479  	for i, expected := range expectedEndorsersResults {
   480  		require.Equal(expected.ReceivedAtBlockHeight, actualEndorsersResults[i].ReceivedAtBlockHeight)
   481  		require.True(proto.Equal(expected.PvtSimulationResultsWithConfig, actualEndorsersResults[i].PvtSimulationResultsWithConfig))
   482  	}
   483  
   484  	// Get the minimum block height remaining in transient store
   485  	var actualMinTransientBlkHt uint64
   486  	actualMinTransientBlkHt, err = testStore.GetMinTransientBlkHt()
   487  	require.NoError(err)
   488  	require.Equal(minTransientBlkHtToRetain, actualMinTransientBlkHt)
   489  
   490  	// Retain results at block height greater than or equal to 15
   491  	minTransientBlkHtToRetain = uint64(15)
   492  	err = testStore.PurgeBelowHeight(minTransientBlkHtToRetain)
   493  	require.NoError(err)
   494  
   495  	// There should be no entries in the  store
   496  	actualMinTransientBlkHt, err = testStore.GetMinTransientBlkHt()
   497  	require.Equal(err, ErrStoreEmpty)
   498  	require.Equal(uint64(0), actualMinTransientBlkHt)
   499  
   500  	// Retain results at block height greater than or equal to 15
   501  	minTransientBlkHtToRetain = uint64(15)
   502  	err = testStore.PurgeBelowHeight(minTransientBlkHtToRetain)
   503  	// Should not return any error
   504  	require.NoError(err)
   505  }
   506  
   507  func TestTransientStoreRetrievalWithFilter(t *testing.T) {
   508  	env := initTestEnv(t)
   509  	defer env.cleanup()
   510  	testStore := env.store
   511  
   512  	samplePvtSimResWithConfig := samplePvtDataWithConfigInfo(t)
   513  
   514  	testTxid := "testTxid"
   515  	numEntries := 5
   516  	for i := 0; i < numEntries; i++ {
   517  		testStore.Persist(testTxid, uint64(i), samplePvtSimResWithConfig)
   518  	}
   519  
   520  	filter := ledger.NewPvtNsCollFilter()
   521  	filter.Add("ns-1", "coll-1")
   522  	filter.Add("ns-2", "coll-2")
   523  
   524  	itr, err := testStore.GetTxPvtRWSetByTxid(testTxid, filter)
   525  	require.NoError(t, err)
   526  
   527  	var actualRes []*EndorserPvtSimulationResults
   528  	for {
   529  		res, err := itr.Next()
   530  		if res == nil || err != nil {
   531  			require.NoError(t, err)
   532  			break
   533  		}
   534  		actualRes = append(actualRes, res)
   535  	}
   536  
   537  	// prepare the trimmed pvtrwset manually - retain only "ns-1/coll-1" and "ns-2/coll-2"
   538  	expectedSimulationRes := samplePvtSimResWithConfig
   539  	expectedSimulationRes.GetPvtRwset().NsPvtRwset[0].CollectionPvtRwset = expectedSimulationRes.GetPvtRwset().NsPvtRwset[0].CollectionPvtRwset[0:1]
   540  	expectedSimulationRes.GetPvtRwset().NsPvtRwset[1].CollectionPvtRwset = expectedSimulationRes.GetPvtRwset().NsPvtRwset[1].CollectionPvtRwset[1:]
   541  	expectedSimulationRes.CollectionConfigs, err = trimPvtCollectionConfigs(expectedSimulationRes.CollectionConfigs, filter)
   542  	require.NoError(t, err)
   543  	for ns, colName := range map[string]string{"ns-1": "coll-1", "ns-2": "coll-2"} {
   544  		config := expectedSimulationRes.CollectionConfigs[ns]
   545  		require.NotNil(t, config)
   546  		ns1Config := config.Config
   547  		require.Equal(t, len(ns1Config), 1)
   548  		ns1ColConfig := ns1Config[0].GetStaticCollectionConfig()
   549  		require.NotNil(t, ns1ColConfig.Name, colName)
   550  	}
   551  
   552  	var expectedRes []*EndorserPvtSimulationResults
   553  	for i := 0; i < numEntries; i++ {
   554  		expectedRes = append(expectedRes, &EndorserPvtSimulationResults{uint64(i), expectedSimulationRes})
   555  	}
   556  
   557  	// Note that the ordering of actualRes and expectedRes is dependent on the uuid. Hence, we are sorting
   558  	// expectedRes and actualRes.
   559  	sortResults(expectedRes)
   560  	sortResults(actualRes)
   561  	require.Equal(t, len(expectedRes), len(actualRes))
   562  	for i, expected := range expectedRes {
   563  		require.Equal(t, expected.ReceivedAtBlockHeight, actualRes[i].ReceivedAtBlockHeight)
   564  		require.True(t, proto.Equal(expected.PvtSimulationResultsWithConfig, actualRes[i].PvtSimulationResultsWithConfig))
   565  	}
   566  }
   567  
   568  func sortResults(res []*EndorserPvtSimulationResults) {
   569  	// Results are sorted by ascending order of received at block height. When the block
   570  	// heights are same, we sort by comparing the hash of private write set.
   571  	sortCondition := func(i, j int) bool {
   572  		if res[i].ReceivedAtBlockHeight == res[j].ReceivedAtBlockHeight {
   573  			resI, _ := proto.Marshal(res[i].PvtSimulationResultsWithConfig)
   574  			resJ, _ := proto.Marshal(res[j].PvtSimulationResultsWithConfig)
   575  			// if hashes are same, any order would work.
   576  			return string(util.ComputeHash(resI)) < string(util.ComputeHash(resJ))
   577  		}
   578  		return res[i].ReceivedAtBlockHeight < res[j].ReceivedAtBlockHeight
   579  	}
   580  	sort.SliceStable(res, sortCondition)
   581  }
   582  
   583  func samplePvtData(t *testing.T) *rwset.TxPvtReadWriteSet {
   584  	pvtWriteSet := &rwset.TxPvtReadWriteSet{DataModel: rwset.TxReadWriteSet_KV}
   585  	pvtWriteSet.NsPvtRwset = []*rwset.NsPvtReadWriteSet{
   586  		{
   587  			Namespace: "ns-1",
   588  			CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   589  				{
   590  					CollectionName: "coll-1",
   591  					Rwset:          []byte("RandomBytes-PvtRWSet-ns1-coll1"),
   592  				},
   593  				{
   594  					CollectionName: "coll-2",
   595  					Rwset:          []byte("RandomBytes-PvtRWSet-ns1-coll2"),
   596  				},
   597  			},
   598  		},
   599  
   600  		{
   601  			Namespace: "ns-2",
   602  			CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   603  				{
   604  					CollectionName: "coll-1",
   605  					Rwset:          []byte("RandomBytes-PvtRWSet-ns2-coll1"),
   606  				},
   607  				{
   608  					CollectionName: "coll-2",
   609  					Rwset:          []byte("RandomBytes-PvtRWSet-ns2-coll2"),
   610  				},
   611  			},
   612  		},
   613  	}
   614  	return pvtWriteSet
   615  }
   616  
   617  func samplePvtDataWithConfigInfo(t *testing.T) *transientstore.TxPvtReadWriteSetWithConfigInfo {
   618  	pvtWriteSet := samplePvtData(t)
   619  	pvtRWSetWithConfigInfo := &transientstore.TxPvtReadWriteSetWithConfigInfo{
   620  		PvtRwset: pvtWriteSet,
   621  		CollectionConfigs: map[string]*peer.CollectionConfigPackage{
   622  			"ns-1": {
   623  				Config: []*peer.CollectionConfig{
   624  					sampleCollectionConfigPackage("coll-1"),
   625  					sampleCollectionConfigPackage("coll-2"),
   626  				},
   627  			},
   628  			"ns-2": {
   629  				Config: []*peer.CollectionConfig{
   630  					sampleCollectionConfigPackage("coll-1"),
   631  					sampleCollectionConfigPackage("coll-2"),
   632  				},
   633  			},
   634  		},
   635  	}
   636  	return pvtRWSetWithConfigInfo
   637  }
   638  
   639  func createCollectionConfig(collectionName string, signaturePolicyEnvelope *common.SignaturePolicyEnvelope,
   640  	requiredPeerCount int32, maximumPeerCount int32,
   641  ) *peer.CollectionConfig {
   642  	signaturePolicy := &peer.CollectionPolicyConfig_SignaturePolicy{
   643  		SignaturePolicy: signaturePolicyEnvelope,
   644  	}
   645  	accessPolicy := &peer.CollectionPolicyConfig{
   646  		Payload: signaturePolicy,
   647  	}
   648  
   649  	return &peer.CollectionConfig{
   650  		Payload: &peer.CollectionConfig_StaticCollectionConfig{
   651  			StaticCollectionConfig: &peer.StaticCollectionConfig{
   652  				Name:              collectionName,
   653  				MemberOrgsPolicy:  accessPolicy,
   654  				RequiredPeerCount: requiredPeerCount,
   655  				MaximumPeerCount:  maximumPeerCount,
   656  			},
   657  		},
   658  	}
   659  }
   660  
   661  func sampleCollectionConfigPackage(colName string) *peer.CollectionConfig {
   662  	signers := [][]byte{[]byte("signer0"), []byte("signer1")}
   663  	policyEnvelope := policydsl.Envelope(policydsl.Or(policydsl.SignedBy(0), policydsl.SignedBy(1)), signers)
   664  
   665  	var requiredPeerCount, maximumPeerCount int32
   666  	requiredPeerCount = 1
   667  	maximumPeerCount = 2
   668  
   669  	return createCollectionConfig(colName, policyEnvelope, requiredPeerCount, maximumPeerCount)
   670  }
   671  
   672  // persistOldProto is the code from 1.1 to populate stores with old proto message
   673  // this is used only for testing
   674  func (s *Store) persistOldProto(txid string, blockHeight uint64,
   675  	privateSimulationResults *rwset.TxPvtReadWriteSet) error {
   676  	logger.Debugf("Persisting private data to transient store for txid [%s] at block height [%d]", txid, blockHeight)
   677  
   678  	dbBatch := s.db.NewUpdateBatch()
   679  
   680  	// Create compositeKey with appropriate prefix, txid, uuid and blockHeight
   681  	// Due to the fact that the txid may have multiple private write sets persisted from different
   682  	// endorsers (via Gossip), we postfix an uuid with the txid to avoid collision.
   683  	uuid := commonutil.GenerateUUID()
   684  	compositeKeyPvtRWSet := createCompositeKeyForPvtRWSet(txid, uuid, blockHeight)
   685  	privateSimulationResultsBytes, err := proto.Marshal(privateSimulationResults)
   686  	if err != nil {
   687  		return err
   688  	}
   689  	dbBatch.Put(compositeKeyPvtRWSet, privateSimulationResultsBytes)
   690  
   691  	// Create two index: (i) by txid, and (ii) by height
   692  
   693  	// Create compositeKey for purge index by height with appropriate prefix, blockHeight,
   694  	// txid, uuid and store the compositeKey (purge index) with a nil byte as value. Note that
   695  	// the purge index is used to remove orphan entries in the transient store (which are not removed
   696  	// by PurgeTxids()) using BTL policy by PurgeBelowHeight(). Note that orphan entries are due to transaction
   697  	// that gets endorsed but not submitted by the client for commit)
   698  	compositeKeyPurgeIndexByHeight := createCompositeKeyForPurgeIndexByHeight(blockHeight, txid, uuid)
   699  	dbBatch.Put(compositeKeyPurgeIndexByHeight, emptyValue)
   700  
   701  	// Create compositeKey for purge index by txid with appropriate prefix, txid, uuid,
   702  	// blockHeight and store the compositeKey (purge index) with a nil byte as value.
   703  	// Though compositeKeyPvtRWSet itself can be used to purge private write set by txid,
   704  	// we create a separate composite key with a nil byte as value. The reason is that
   705  	// if we use compositeKeyPvtRWSet, we unnecessarily read (potentially large) private write
   706  	// set associated with the key from db. Note that this purge index is used to remove non-orphan
   707  	// entries in the transient store and is used by PurgeTxids()
   708  	// Note: We can create compositeKeyPurgeIndexByTxid by just replacing the prefix of compositeKeyPvtRWSet
   709  	// with purgeIndexByTxidPrefix. For code readability and to be expressive, we use a
   710  	// createCompositeKeyForPurgeIndexByTxid() instead.
   711  	compositeKeyPurgeIndexByTxid := createCompositeKeyForPurgeIndexByTxid(txid, uuid, blockHeight)
   712  	dbBatch.Put(compositeKeyPurgeIndexByTxid, emptyValue)
   713  
   714  	return s.db.WriteBatch(dbBatch, true)
   715  }
   716  
   717  func TestIteratorErrorCases(t *testing.T) {
   718  	env := initTestEnv(t)
   719  	defer env.cleanup()
   720  	testStore := env.store
   721  	env.storeProvider.Close()
   722  
   723  	errStr := "internal leveldb error while obtaining db iterator: leveldb: closed"
   724  	itr, err := testStore.GetTxPvtRWSetByTxid("tx1", nil)
   725  	require.EqualError(t, err, errStr)
   726  	require.Nil(t, itr)
   727  
   728  	minHt, err := testStore.GetMinTransientBlkHt()
   729  	require.EqualError(t, err, errStr)
   730  	require.Equal(t, uint64(0), minHt)
   731  
   732  	require.EqualError(t, testStore.PurgeBelowHeight(0), errStr)
   733  	require.EqualError(t, testStore.PurgeByTxids([]string{"tx1"}), errStr)
   734  }
   735  
   736  func TestDeleteTransientStore(t *testing.T) {
   737  	env := initTestEnv(t)
   738  	defer env.cleanup()
   739  
   740  	ledgerID := "test-deleted-tx-count"
   741  	store, err := env.storeProvider.OpenStore(ledgerID)
   742  	require.NoError(t, err)
   743  	require.NotNil(t, store)
   744  
   745  	// Write some transactions into the transient storage.
   746  	samplePvtSimResWithConfig := samplePvtDataWithConfigInfo(t)
   747  	testTxid := "testTxid"
   748  	numEntries := 5
   749  	for i := 0; i < numEntries; i++ {
   750  		store.Persist(testTxid, uint64(i), samplePvtSimResWithConfig)
   751  	}
   752  
   753  	height, err := store.GetMinTransientBlkHt()
   754  	require.NoError(t, err)
   755  	require.Equal(t, uint64(0), height)
   756  
   757  	// undercut a few blocks, and we should still have a lower tx bound.
   758  	require.NoError(t, store.PurgeBelowHeight(3))
   759  	height, err = store.GetMinTransientBlkHt()
   760  	require.NoError(t, err)
   761  	require.Equal(t, uint64(3), height)
   762  
   763  	// Delete the store
   764  	sp := env.storeProvider.(*storeProvider)
   765  	require.NoError(t, sp.deleteStore(ledgerID))
   766  
   767  	// After delete the storage should be empty.
   768  	height, err = store.GetMinTransientBlkHt()
   769  	require.EqualError(t, err, "Transient store is empty")
   770  	require.Equal(t, uint64(0), height)
   771  
   772  	isEmpty, err := store.db.IsEmpty()
   773  	require.NoError(t, err)
   774  	require.True(t, isEmpty)
   775  }
   776  
   777  func TestDeleteMissingTransientStoreIsOK(t *testing.T) {
   778  	env := initTestEnv(t)
   779  	defer env.cleanup()
   780  
   781  	sp := env.storeProvider.(*storeProvider)
   782  	require.NoError(t, sp.deleteStore("_not_a_valid_store"))
   783  }