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

     1  /*
     2  Copyright hechain. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package pvtdatastorage
     8  
     9  import (
    10  	"fmt"
    11  	"io/ioutil"
    12  	"os"
    13  	"strings"
    14  	"testing"
    15  	"time"
    16  
    17  	"github.com/golang/protobuf/proto"
    18  	"github.com/hechain20/hechain/common/ledger/util/leveldbhelper"
    19  	"github.com/hechain20/hechain/core/ledger"
    20  	"github.com/hechain20/hechain/core/ledger/kvledger/txmgmt/rwsetutil"
    21  	btltestutil "github.com/hechain20/hechain/core/ledger/pvtdatapolicy/testutil"
    22  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    23  	"github.com/stretchr/testify/require"
    24  )
    25  
    26  func TestMain(m *testing.M) {
    27  	os.Exit(m.Run())
    28  }
    29  
    30  func TestEmptyStore(t *testing.T) {
    31  	env := NewTestStoreEnv(t, "TestEmptyStore", nil, pvtDataConf())
    32  	defer env.Cleanup()
    33  	store := env.TestStore
    34  	require.True(t, store.isEmpty)
    35  }
    36  
    37  func TestStoreBasicCommitAndRetrieval(t *testing.T) {
    38  	btlPolicy := btltestutil.SampleBTLPolicy(
    39  		map[[2]string]uint64{
    40  			{"ns-1", "coll-1"}: 0,
    41  			{"ns-1", "coll-2"}: 0,
    42  			{"ns-2", "coll-1"}: 0,
    43  			{"ns-2", "coll-2"}: 0,
    44  			{"ns-3", "coll-1"}: 0,
    45  			{"ns-4", "coll-1"}: 0,
    46  			{"ns-4", "coll-2"}: 0,
    47  		},
    48  	)
    49  
    50  	env := NewTestStoreEnv(t, "TestStoreBasicCommitAndRetrieval", btlPolicy, pvtDataConf())
    51  	defer env.Cleanup()
    52  	store := env.TestStore
    53  	testData := []*ledger.TxPvtData{
    54  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
    55  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
    56  	}
    57  
    58  	// construct missing data for block 1
    59  	blk1MissingData := make(ledger.TxMissingPvtData)
    60  
    61  	// eligible missing data in tx1
    62  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
    63  	blk1MissingData.Add(1, "ns-1", "coll-2", true)
    64  	blk1MissingData.Add(1, "ns-2", "coll-1", true)
    65  	blk1MissingData.Add(1, "ns-2", "coll-2", true)
    66  	// eligible missing data in tx2
    67  	blk1MissingData.Add(2, "ns-3", "coll-1", true)
    68  	// ineligible missing data in tx4
    69  	blk1MissingData.Add(4, "ns-4", "coll-1", false)
    70  	blk1MissingData.Add(4, "ns-4", "coll-2", false)
    71  
    72  	// construct missing data for block 2
    73  	blk2MissingData := make(ledger.TxMissingPvtData)
    74  	// eligible missing data in tx1
    75  	blk2MissingData.Add(1, "ns-1", "coll-1", true)
    76  	blk2MissingData.Add(1, "ns-1", "coll-2", true)
    77  	// eligible missing data in tx3
    78  	blk2MissingData.Add(3, "ns-1", "coll-1", true)
    79  
    80  	// no pvt data with block 0
    81  	require.NoError(t, store.Commit(0, nil, nil))
    82  
    83  	// pvt data with block 1 - commit
    84  	require.NoError(t, store.Commit(1, testData, blk1MissingData))
    85  
    86  	// pvt data retrieval for block 0 should return nil
    87  	var nilFilter ledger.PvtNsCollFilter
    88  	retrievedData, err := store.GetPvtDataByBlockNum(0, nilFilter)
    89  	require.NoError(t, err)
    90  	require.Nil(t, retrievedData)
    91  
    92  	// pvt data retrieval for block 1 should return full pvtdata
    93  	retrievedData, err = store.GetPvtDataByBlockNum(1, nilFilter)
    94  	require.NoError(t, err)
    95  	for i, data := range retrievedData {
    96  		require.Equal(t, data.SeqInBlock, testData[i].SeqInBlock)
    97  		require.True(t, proto.Equal(data.WriteSet, testData[i].WriteSet))
    98  	}
    99  
   100  	// pvt data retrieval for block 1 with filter should return filtered pvtdata
   101  	filter := ledger.NewPvtNsCollFilter()
   102  	filter.Add("ns-1", "coll-1")
   103  	filter.Add("ns-2", "coll-2")
   104  	retrievedData, err = store.GetPvtDataByBlockNum(1, filter)
   105  	require.NoError(t, err)
   106  	expectedRetrievedData := []*ledger.TxPvtData{
   107  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-2:coll-2"}),
   108  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-2:coll-2"}),
   109  	}
   110  	for i, data := range retrievedData {
   111  		require.Equal(t, data.SeqInBlock, expectedRetrievedData[i].SeqInBlock)
   112  		require.True(t, proto.Equal(data.WriteSet, expectedRetrievedData[i].WriteSet))
   113  	}
   114  
   115  	// pvt data retrieval for block 2 should return ErrOutOfRange
   116  	retrievedData, err = store.GetPvtDataByBlockNum(2, nilFilter)
   117  	require.EqualError(t, err, "last committed block number [1] smaller than the requested block number [2]")
   118  	require.Nil(t, retrievedData)
   119  
   120  	// pvt data with block 2 - commit
   121  	require.NoError(t, store.Commit(2, testData, blk2MissingData))
   122  
   123  	// retrieve the stored missing entries using GetMissingPvtDataInfoForMostRecentBlocks
   124  	// Only the code path of eligible entries would be covered in this unit-test. For
   125  	// ineligible entries, the code path will be covered in FAB-11437
   126  
   127  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   128  	// missing data in block2, tx1
   129  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1")
   130  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   131  	expectedMissingPvtDataInfo.Add(2, 3, "ns-1", "coll-1")
   132  
   133  	missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(1)
   134  	require.NoError(t, err)
   135  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   136  
   137  	// missing data in block1, tx1
   138  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   139  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   140  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1")
   141  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-2")
   142  
   143  	// missing data in block1, tx2
   144  	expectedMissingPvtDataInfo.Add(1, 2, "ns-3", "coll-1")
   145  
   146  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(2)
   147  	require.NoError(t, err)
   148  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   149  
   150  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   151  	require.NoError(t, err)
   152  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   153  }
   154  
   155  func TestStoreIteratorError(t *testing.T) {
   156  	env := NewTestStoreEnv(t, "TestStoreIteratorError", nil, pvtDataConf())
   157  	defer env.Cleanup()
   158  	store := env.TestStore
   159  	require.NoError(t, store.Commit(0, nil, nil))
   160  	env.TestStoreProvider.Close()
   161  	errStr := "internal leveldb error while obtaining db iterator: leveldb: closed"
   162  
   163  	t.Run("GetPvtDataByBlockNum", func(t *testing.T) {
   164  		block, err := store.GetPvtDataByBlockNum(0, nil)
   165  		require.EqualError(t, err, errStr)
   166  		require.Nil(t, block)
   167  	})
   168  
   169  	t.Run("GetMissingPvtDataInfoForMostRecentBlocks", func(t *testing.T) {
   170  		missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   171  		require.EqualError(t, err, errStr)
   172  		require.Nil(t, missingPvtDataInfo)
   173  	})
   174  
   175  	t.Run("retrieveExpiryEntries", func(t *testing.T) {
   176  		expiryEntries, err := store.retrieveExpiryEntries(0, 1)
   177  		require.EqualError(t, err, errStr)
   178  		require.Nil(t, expiryEntries)
   179  	})
   180  
   181  	t.Run("processCollElgEvents", func(t *testing.T) {
   182  		storeDir, err := ioutil.TempDir("", "pdstore")
   183  		require.NoError(t, err)
   184  		s := &Store{}
   185  		dbProvider, err := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: storeDir})
   186  		require.NoError(t, err)
   187  		s.db = dbProvider.GetDBHandle("test-ledger")
   188  		dbProvider.Close()
   189  		require.EqualError(t, s.processCollElgEvents(), errStr)
   190  	})
   191  }
   192  
   193  func TestGetMissingDataInfo(t *testing.T) {
   194  	setup := func(ledgerid string, c *PrivateDataConfig) *Store {
   195  		btlPolicy := btltestutil.SampleBTLPolicy(
   196  			map[[2]string]uint64{
   197  				{"ns-1", "coll-1"}: 0,
   198  				{"ns-1", "coll-2"}: 0,
   199  			},
   200  		)
   201  
   202  		env := NewTestStoreEnv(t, ledgerid, btlPolicy, c)
   203  		t.Cleanup(
   204  			func() {
   205  				defer env.Cleanup()
   206  			},
   207  		)
   208  		store := env.TestStore
   209  
   210  		// construct missing data for block 1
   211  		blk1MissingData := make(ledger.TxMissingPvtData)
   212  		blk1MissingData.Add(1, "ns-1", "coll-1", true)
   213  		blk1MissingData.Add(1, "ns-1", "coll-2", true)
   214  
   215  		require.NoError(t, store.Commit(0, nil, nil))
   216  		require.NoError(t, store.Commit(1, nil, blk1MissingData))
   217  
   218  		deprioritizedList := ledger.MissingPvtDataInfo{
   219  			1: ledger.MissingBlockPvtdataInfo{
   220  				1: {
   221  					{
   222  						Namespace:  "ns-1",
   223  						Collection: "coll-2",
   224  					},
   225  				},
   226  			},
   227  		}
   228  		require.NoError(t, store.CommitPvtDataOfOldBlocks(nil, deprioritizedList))
   229  
   230  		return env.TestStore
   231  	}
   232  
   233  	t.Run("always access deprioritized missing data", func(t *testing.T) {
   234  		conf := pvtDataConf()
   235  		conf.DeprioritizedDataReconcilerInterval = 0
   236  		store := setup("testGetMissingDataInfoFromDeprioList", conf)
   237  
   238  		expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{
   239  			1: ledger.MissingBlockPvtdataInfo{
   240  				1: {
   241  					{
   242  						Namespace:  "ns-1",
   243  						Collection: "coll-2",
   244  					},
   245  				},
   246  			},
   247  		}
   248  
   249  		for i := 0; i < 2; i++ {
   250  			assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2)
   251  		}
   252  	})
   253  
   254  	t.Run("change the deprioritized missing data access time", func(t *testing.T) {
   255  		conf := pvtDataConf()
   256  		conf.DeprioritizedDataReconcilerInterval = 300 * time.Minute
   257  		store := setup("testGetMissingDataInfoFromPrioAndDeprioList", conf)
   258  
   259  		expectedPrioMissingDataInfo := ledger.MissingPvtDataInfo{
   260  			1: ledger.MissingBlockPvtdataInfo{
   261  				1: {
   262  					{
   263  						Namespace:  "ns-1",
   264  						Collection: "coll-1",
   265  					},
   266  				},
   267  			},
   268  		}
   269  
   270  		expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{
   271  			1: ledger.MissingBlockPvtdataInfo{
   272  				1: {
   273  					{
   274  						Namespace:  "ns-1",
   275  						Collection: "coll-2",
   276  					},
   277  				},
   278  			},
   279  		}
   280  
   281  		for i := 0; i < 3; i++ {
   282  			assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2)
   283  		}
   284  
   285  		store.accessDeprioMissingDataAfter = time.Now().Add(-time.Second)
   286  		lesserThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(-2 * time.Second)
   287  		greaterThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(2 * time.Second)
   288  		assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2)
   289  
   290  		require.True(t, store.accessDeprioMissingDataAfter.After(lesserThanNextAccessTime))
   291  		require.False(t, store.accessDeprioMissingDataAfter.After(greaterThanNextAccessTime))
   292  		for i := 0; i < 3; i++ {
   293  			assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2)
   294  		}
   295  	})
   296  }
   297  
   298  func TestExpiryDataNotIncluded(t *testing.T) {
   299  	ledgerid := "TestExpiryDataNotIncluded"
   300  	btlPolicy := btltestutil.SampleBTLPolicy(
   301  		map[[2]string]uint64{
   302  			{"ns-1", "coll-1"}: 1,
   303  			{"ns-1", "coll-2"}: 0,
   304  			{"ns-2", "coll-1"}: 0,
   305  			{"ns-2", "coll-2"}: 2,
   306  			{"ns-3", "coll-1"}: 1,
   307  			{"ns-3", "coll-2"}: 0,
   308  		},
   309  	)
   310  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf())
   311  	defer env.Cleanup()
   312  	store := env.TestStore
   313  
   314  	// construct missing data for block 1
   315  	blk1MissingData := make(ledger.TxMissingPvtData)
   316  	// eligible missing data in tx1
   317  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   318  	blk1MissingData.Add(1, "ns-1", "coll-2", true)
   319  	// ineligible missing data in tx4
   320  	blk1MissingData.Add(4, "ns-3", "coll-1", false)
   321  	blk1MissingData.Add(4, "ns-3", "coll-2", false)
   322  
   323  	// construct missing data for block 2
   324  	blk2MissingData := make(ledger.TxMissingPvtData)
   325  	// eligible missing data in tx1
   326  	blk2MissingData.Add(1, "ns-1", "coll-1", true)
   327  	blk2MissingData.Add(1, "ns-1", "coll-2", true)
   328  
   329  	// no pvt data with block 0
   330  	require.NoError(t, store.Commit(0, nil, nil))
   331  
   332  	// write pvt data for block 1
   333  	testDataForBlk1 := []*ledger.TxPvtData{
   334  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   335  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   336  	}
   337  	require.NoError(t, store.Commit(1, testDataForBlk1, blk1MissingData))
   338  
   339  	// write pvt data for block 2
   340  	testDataForBlk2 := []*ledger.TxPvtData{
   341  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   342  		produceSamplePvtdata(t, 5, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   343  	}
   344  	require.NoError(t, store.Commit(2, testDataForBlk2, blk2MissingData))
   345  
   346  	retrievedData, _ := store.GetPvtDataByBlockNum(1, nil)
   347  	// block 1 data should still be not expired
   348  	for i, data := range retrievedData {
   349  		require.Equal(t, data.SeqInBlock, testDataForBlk1[i].SeqInBlock)
   350  		require.True(t, proto.Equal(data.WriteSet, testDataForBlk1[i].WriteSet))
   351  	}
   352  
   353  	// none of the missing data entries would have expired
   354  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   355  	// missing data in block2, tx1
   356  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1")
   357  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   358  
   359  	// missing data in block1, tx1
   360  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   361  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   362  
   363  	missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   364  	require.NoError(t, err)
   365  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   366  
   367  	// Commit block 3 with no pvtdata
   368  	require.NoError(t, store.Commit(3, nil, nil))
   369  
   370  	// After committing block 3, the data for "ns-1:coll1" of block 1 should have expired and should not be returned by the store
   371  	expectedPvtdataFromBlock1 := []*ledger.TxPvtData{
   372  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   373  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   374  	}
   375  	retrievedData, _ = store.GetPvtDataByBlockNum(1, nil)
   376  	require.Equal(t, expectedPvtdataFromBlock1, retrievedData)
   377  
   378  	// After committing block 3, the missing data of "ns1-coll1" in block1-tx1 should have expired
   379  	expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo)
   380  	// missing data in block2, tx1
   381  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1")
   382  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   383  	// missing data in block1, tx1
   384  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   385  
   386  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   387  	require.NoError(t, err)
   388  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   389  
   390  	// Commit block 4 with no pvtdata
   391  	require.NoError(t, store.Commit(4, nil, nil))
   392  
   393  	// After committing block 4, the data for "ns-2:coll2" of block 1 should also have expired and should not be returned by the store
   394  	expectedPvtdataFromBlock1 = []*ledger.TxPvtData{
   395  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1"}),
   396  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1"}),
   397  	}
   398  	retrievedData, _ = store.GetPvtDataByBlockNum(1, nil)
   399  	require.Equal(t, expectedPvtdataFromBlock1, retrievedData)
   400  
   401  	// Now, for block 2, "ns-1:coll1" should also have expired
   402  	expectedPvtdataFromBlock2 := []*ledger.TxPvtData{
   403  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   404  		produceSamplePvtdata(t, 5, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   405  	}
   406  	retrievedData, _ = store.GetPvtDataByBlockNum(2, nil)
   407  	require.Equal(t, expectedPvtdataFromBlock2, retrievedData)
   408  
   409  	// After committing block 4, the missing data of "ns1-coll1" in block2-tx1 should have expired
   410  	expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo)
   411  	// missing data in block2, tx1
   412  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   413  
   414  	// missing data in block1, tx1
   415  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   416  
   417  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   418  	require.NoError(t, err)
   419  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   420  }
   421  
   422  func TestStorePurge(t *testing.T) {
   423  	ledgerid := "TestStorePurge"
   424  	btlPolicy := btltestutil.SampleBTLPolicy(
   425  		map[[2]string]uint64{
   426  			{"ns-1", "coll-1"}: 1,
   427  			{"ns-1", "coll-2"}: 0,
   428  			{"ns-2", "coll-1"}: 0,
   429  			{"ns-2", "coll-2"}: 4,
   430  			{"ns-3", "coll-1"}: 1,
   431  			{"ns-3", "coll-2"}: 0,
   432  		},
   433  	)
   434  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf())
   435  	defer env.Cleanup()
   436  	s := env.TestStore
   437  
   438  	// no pvt data with block 0
   439  	require.NoError(t, s.Commit(0, nil, nil))
   440  
   441  	// construct missing data for block 1
   442  	blk1MissingData := make(ledger.TxMissingPvtData)
   443  	// eligible missing data in tx1
   444  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   445  	blk1MissingData.Add(1, "ns-1", "coll-2", true)
   446  	// eligible missing data in tx3
   447  	blk1MissingData.Add(3, "ns-1", "coll-1", true)
   448  	blk1MissingData.Add(3, "ns-1", "coll-2", true)
   449  	// ineligible missing data in tx4
   450  	blk1MissingData.Add(4, "ns-3", "coll-1", false)
   451  	blk1MissingData.Add(4, "ns-3", "coll-2", false)
   452  
   453  	// write pvt data for block 1
   454  	testDataForBlk1 := []*ledger.TxPvtData{
   455  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   456  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   457  	}
   458  	require.NoError(t, s.Commit(1, testDataForBlk1, blk1MissingData))
   459  
   460  	// write pvt data for block 2
   461  	require.NoError(t, s.Commit(2, nil, nil))
   462  	// data for ns-1:coll-1 and ns-2:coll-2 should exist in store
   463  	ns1Coll1 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}, txNum: 2}
   464  	ns2Coll2 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-2", coll: "coll-2", blkNum: 1}, txNum: 2}
   465  
   466  	// eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store
   467  	ns1Coll1elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}}
   468  	ns1Coll2elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}}
   469  
   470  	// ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store
   471  	ns3Coll1inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-1", blkNum: 1}}
   472  	ns3Coll2inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-2", blkNum: 1}}
   473  
   474  	testWaitForPurgerRoutineToFinish(s)
   475  	require.True(t, testDataKeyExists(t, s, ns1Coll1))
   476  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   477  
   478  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   479  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   480  
   481  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD))
   482  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD))
   483  
   484  	deprioritizedList := ledger.MissingPvtDataInfo{
   485  		1: ledger.MissingBlockPvtdataInfo{
   486  			3: {
   487  				{
   488  					Namespace:  "ns-1",
   489  					Collection: "coll-1",
   490  				},
   491  				{
   492  					Namespace:  "ns-1",
   493  					Collection: "coll-2",
   494  				},
   495  			},
   496  		},
   497  	}
   498  	require.NoError(t, s.CommitPvtDataOfOldBlocks(nil, deprioritizedList))
   499  
   500  	// write pvt data for block 3
   501  	require.NoError(t, s.Commit(3, nil, nil))
   502  	// data for ns-1:coll-1 and ns-2:coll-2 should exist in store (because purger should not be launched at block 3)
   503  	testWaitForPurgerRoutineToFinish(s)
   504  	require.True(t, testDataKeyExists(t, s, ns1Coll1))
   505  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   506  	// eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store
   507  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   508  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   509  	// some transactions which miss ns-1:coll-1 and ns-1:coll-2 has be moved to deprioritizedList list
   510  	require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   511  	require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   512  	// ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store
   513  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD))
   514  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD))
   515  
   516  	// write pvt data for block 4
   517  	require.NoError(t, s.Commit(4, nil, nil))
   518  	// data for ns-1:coll-1 should not exist in store (because purger should be launched at block 4)
   519  	// but ns-2:coll-2 should exist because it expires at block 5
   520  	testWaitForPurgerRoutineToFinish(s)
   521  	require.False(t, testDataKeyExists(t, s, ns1Coll1))
   522  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   523  	// eligible missingData entries for ns-1:coll-1 should have expired and ns-1:coll-2 (neverExpires) should exist in store
   524  	require.False(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   525  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   526  	require.False(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   527  	require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   528  	// ineligible missingData entries for ns-3:col-1 should have expired and ns-3:coll-2 (neverExpires) should exist in store
   529  	require.False(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD))
   530  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD))
   531  
   532  	// write pvt data for block 5
   533  	require.NoError(t, s.Commit(5, nil, nil))
   534  	// ns-2:coll-2 should exist because though the data expires at block 5 but purger is launched every second block
   535  	testWaitForPurgerRoutineToFinish(s)
   536  	require.False(t, testDataKeyExists(t, s, ns1Coll1))
   537  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   538  
   539  	// write pvt data for block 6
   540  	require.NoError(t, s.Commit(6, nil, nil))
   541  	// ns-2:coll-2 should not exists now (because purger should be launched at block 6)
   542  	testWaitForPurgerRoutineToFinish(s)
   543  	require.False(t, testDataKeyExists(t, s, ns1Coll1))
   544  	require.False(t, testDataKeyExists(t, s, ns2Coll2))
   545  
   546  	// "ns-2:coll-1" should never have been purged (because, it was no btl was declared for this)
   547  	require.True(t, testDataKeyExists(t, s, &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}, txNum: 2}))
   548  }
   549  
   550  func TestStoreState(t *testing.T) {
   551  	btlPolicy := btltestutil.SampleBTLPolicy(
   552  		map[[2]string]uint64{
   553  			{"ns-1", "coll-1"}: 0,
   554  			{"ns-1", "coll-2"}: 0,
   555  		},
   556  	)
   557  	env := NewTestStoreEnv(t, "TestStoreState", btlPolicy, pvtDataConf())
   558  	defer env.Cleanup()
   559  	store := env.TestStore
   560  	testData := []*ledger.TxPvtData{
   561  		produceSamplePvtdata(t, 0, []string{"ns-1:coll-1", "ns-1:coll-2"}),
   562  	}
   563  
   564  	require.EqualError(t,
   565  		store.Commit(1, testData, nil),
   566  		"expected block number=0, received block number=1",
   567  	)
   568  }
   569  
   570  func TestPendingBatch(t *testing.T) {
   571  	btlPolicy := btltestutil.SampleBTLPolicy(
   572  		map[[2]string]uint64{
   573  			{"ns-1", "coll-1"}: 0,
   574  			{"ns-1", "coll-2"}: 0,
   575  		},
   576  	)
   577  	env := NewTestStoreEnv(t, "TestPendingBatch", btlPolicy, pvtDataConf())
   578  	defer env.Cleanup()
   579  	s := env.TestStore
   580  	existingLastBlockNum := uint64(25)
   581  	batch := s.db.NewUpdateBatch()
   582  	batch.Put(lastCommittedBlkkey, encodeLastCommittedBlockVal(existingLastBlockNum))
   583  	require.NoError(t, s.db.WriteBatch(batch, true))
   584  	s.lastCommittedBlock = existingLastBlockNum
   585  	s.isEmpty = false
   586  	testLastCommittedBlockHeight(t, existingLastBlockNum+1, s)
   587  
   588  	// assume that a block has been prepared in v142 and the peer was
   589  	// killed for upgrade. When the pvtdataStore is opened again with
   590  	// v2.0 peer, the pendingBatch should be marked as committed.
   591  	batch = s.db.NewUpdateBatch()
   592  
   593  	// store pvtData entries
   594  	dataKey := &dataKey{nsCollBlk{"ns-1", "coll-1", 26}, 1}
   595  	dataValue := &rwset.CollectionPvtReadWriteSet{CollectionName: "coll-1", Rwset: []byte("pvtdata")}
   596  	keyBytes := encodeDataKey(dataKey)
   597  	valueBytes, err := encodeDataValue(dataValue)
   598  	require.NoError(t, err)
   599  	batch.Put(keyBytes, valueBytes)
   600  
   601  	// store pendingBatch marker
   602  	batch.Put(pendingCommitKey, emptyValue)
   603  
   604  	// write to the store
   605  	require.NoError(t, s.db.WriteBatch(batch, true))
   606  	testLastCommittedBlockHeight(t, existingLastBlockNum+1, s)
   607  
   608  	// as the block commit is pending, we cannot read the pvtData
   609  	hasPendingBatch, err := s.hasPendingCommit()
   610  	require.NoError(t, err)
   611  	require.Equal(t, true, hasPendingBatch)
   612  	pvtData, err := s.GetPvtDataByBlockNum(26, nil)
   613  	require.EqualError(t, err, "last committed block number [25] smaller than the requested block number [26]")
   614  	require.Nil(t, pvtData)
   615  
   616  	// emulate a version upgrade
   617  	env.CloseAndReopen()
   618  
   619  	s = env.TestStore
   620  	testLastCommittedBlockHeight(t, existingLastBlockNum+2, s)
   621  	hasPendingBatch, err = s.hasPendingCommit()
   622  	require.NoError(t, err)
   623  	require.Equal(t, false, hasPendingBatch)
   624  	testDataKeyExists(t, s, dataKey)
   625  
   626  	expectedPvtData := &rwset.TxPvtReadWriteSet{
   627  		NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   628  			{
   629  				Namespace: "ns-1",
   630  				CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   631  					dataValue,
   632  				},
   633  			},
   634  		},
   635  	}
   636  	pvtData, err = s.GetPvtDataByBlockNum(26, nil)
   637  	require.NoError(t, err)
   638  	require.Equal(t, 1, len(pvtData))
   639  	require.Equal(t, uint64(1), pvtData[0].SeqInBlock)
   640  	require.True(t, proto.Equal(expectedPvtData, pvtData[0].WriteSet))
   641  }
   642  
   643  func TestCollElgEnabled(t *testing.T) {
   644  	conf := pvtDataConf()
   645  	testCollElgEnabled(t, conf)
   646  	conf.BatchesInterval = 1
   647  	conf.MaxBatchSize = 1
   648  	testCollElgEnabled(t, conf)
   649  }
   650  
   651  func TestDrop(t *testing.T) {
   652  	ledgerid := "testremove"
   653  	btlPolicy := btltestutil.SampleBTLPolicy(
   654  		map[[2]string]uint64{
   655  			{"ns-1", "coll-1"}: 0,
   656  			{"ns-1", "coll-2"}: 0,
   657  			{"ns-2", "coll-1"}: 0,
   658  			{"ns-2", "coll-2"}: 0,
   659  		},
   660  	)
   661  
   662  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf())
   663  	defer env.Cleanup()
   664  	store := env.TestStore
   665  
   666  	testData := []*ledger.TxPvtData{
   667  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   668  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   669  	}
   670  
   671  	// construct missing data for block 1
   672  	blk1MissingData := make(ledger.TxMissingPvtData)
   673  
   674  	// eligible missing data in tx1
   675  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   676  	blk1MissingData.Add(1, "ns-1", "coll-2", true)
   677  	blk1MissingData.Add(1, "ns-2", "coll-1", true)
   678  	blk1MissingData.Add(1, "ns-2", "coll-2", true)
   679  
   680  	// no pvt data with block 0
   681  	require.NoError(t, store.Commit(0, nil, nil))
   682  
   683  	// pvt data with block 1 - commit
   684  	require.NoError(t, store.Commit(1, testData, blk1MissingData))
   685  
   686  	// pvt data retrieval for block 0 should return nil
   687  	var nilFilter ledger.PvtNsCollFilter
   688  	retrievedData, err := store.GetPvtDataByBlockNum(0, nilFilter)
   689  	require.NoError(t, err)
   690  	require.Nil(t, retrievedData)
   691  
   692  	// pvt data retrieval for block 1 should return full pvtdata
   693  	retrievedData, err = store.GetPvtDataByBlockNum(1, nilFilter)
   694  	require.NoError(t, err)
   695  	require.Equal(t, len(testData), len(retrievedData))
   696  	for i, data := range retrievedData {
   697  		require.Equal(t, data.SeqInBlock, testData[i].SeqInBlock)
   698  		require.True(t, proto.Equal(data.WriteSet, testData[i].WriteSet))
   699  	}
   700  
   701  	require.NoError(t, env.TestStoreProvider.Drop(ledgerid))
   702  
   703  	// pvt data should be removed
   704  	retrievedData, err = store.GetPvtDataByBlockNum(0, nilFilter)
   705  	require.NoError(t, err)
   706  	require.Nil(t, retrievedData)
   707  
   708  	retrievedData, err = store.GetPvtDataByBlockNum(1, nilFilter)
   709  	require.NoError(t, err)
   710  	require.Nil(t, retrievedData)
   711  
   712  	itr, err := env.TestStoreProvider.dbProvider.GetDBHandle(ledgerid).GetIterator(nil, nil)
   713  	require.NoError(t, err)
   714  	require.False(t, itr.Next())
   715  
   716  	// drop again is not an error
   717  	require.NoError(t, env.TestStoreProvider.Drop(ledgerid))
   718  
   719  	// negative test
   720  	env.TestStoreProvider.Close()
   721  	require.EqualError(t, env.TestStoreProvider.Drop(ledgerid), "internal leveldb error while obtaining db iterator: leveldb: closed")
   722  }
   723  
   724  func testCollElgEnabled(t *testing.T, conf *PrivateDataConfig) {
   725  	ledgerid := "TestCollElgEnabled"
   726  	btlPolicy := btltestutil.SampleBTLPolicy(
   727  		map[[2]string]uint64{
   728  			{"ns-1", "coll-1"}: 0,
   729  			{"ns-1", "coll-2"}: 0,
   730  			{"ns-2", "coll-1"}: 0,
   731  			{"ns-2", "coll-2"}: 0,
   732  		},
   733  	)
   734  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, conf)
   735  	defer env.Cleanup()
   736  	testStore := env.TestStore
   737  
   738  	// Initial state: eligible for {ns-1:coll-1 and ns-2:coll-1 }
   739  
   740  	// no pvt data with block 0
   741  	require.NoError(t, testStore.Commit(0, nil, nil))
   742  
   743  	// construct and commit block 1
   744  	blk1MissingData := make(ledger.TxMissingPvtData)
   745  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   746  	blk1MissingData.Add(1, "ns-2", "coll-1", true)
   747  	blk1MissingData.Add(4, "ns-1", "coll-2", false)
   748  	blk1MissingData.Add(4, "ns-2", "coll-2", false)
   749  	testDataForBlk1 := []*ledger.TxPvtData{
   750  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1"}),
   751  	}
   752  	require.NoError(t, testStore.Commit(1, testDataForBlk1, blk1MissingData))
   753  
   754  	// construct and commit block 2
   755  	blk2MissingData := make(ledger.TxMissingPvtData)
   756  	// ineligible missing data in tx1
   757  	blk2MissingData.Add(1, "ns-1", "coll-2", false)
   758  	blk2MissingData.Add(1, "ns-2", "coll-2", false)
   759  	testDataForBlk2 := []*ledger.TxPvtData{
   760  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-1"}),
   761  	}
   762  	require.NoError(t, testStore.Commit(2, testDataForBlk2, blk2MissingData))
   763  
   764  	// Retrieve and verify missing data reported
   765  	// Expected missing data should be only blk1-tx1 (because, the other missing data is marked as ineliigible)
   766  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   767  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   768  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1")
   769  	missingPvtDataInfo, err := testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   770  	require.NoError(t, err)
   771  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   772  
   773  	// Enable eligibility for {ns-1:coll2}
   774  	require.NoError(t,
   775  		testStore.ProcessCollsEligibilityEnabled(
   776  			5,
   777  			map[string][]string{
   778  				"ns-1": {"coll-2"},
   779  			},
   780  		))
   781  	testutilWaitForCollElgProcToFinish(testStore)
   782  
   783  	// Retrieve and verify missing data reported
   784  	// Expected missing data should include newly eiligible collections
   785  	expectedMissingPvtDataInfo.Add(1, 4, "ns-1", "coll-2")
   786  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   787  	missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   788  	require.NoError(t, err)
   789  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   790  
   791  	// Enable eligibility for {ns-2:coll2}
   792  	require.NoError(t,
   793  		testStore.ProcessCollsEligibilityEnabled(6,
   794  			map[string][]string{
   795  				"ns-2": {"coll-2"},
   796  			},
   797  		))
   798  	testutilWaitForCollElgProcToFinish(testStore)
   799  
   800  	// Retrieve and verify missing data reported
   801  	// Expected missing data should include newly eiligible collections
   802  	expectedMissingPvtDataInfo.Add(1, 4, "ns-2", "coll-2")
   803  	expectedMissingPvtDataInfo.Add(2, 1, "ns-2", "coll-2")
   804  	missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   805  	require.NoError(t, err)
   806  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   807  }
   808  
   809  func testLastCommittedBlockHeight(t *testing.T, expectedBlockHt uint64, store *Store) {
   810  	blkHt, err := store.LastCommittedBlockHeight()
   811  	require.NoError(t, err)
   812  	require.Equal(t, expectedBlockHt, blkHt)
   813  }
   814  
   815  func testDataKeyExists(t *testing.T, s *Store, dataKey *dataKey) bool {
   816  	dataKeyBytes := encodeDataKey(dataKey)
   817  	val, err := s.db.Get(dataKeyBytes)
   818  	require.NoError(t, err)
   819  	return len(val) != 0
   820  }
   821  
   822  func testElgPrioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool {
   823  	key := encodeElgPrioMissingDataKey(missingDataKey)
   824  
   825  	val, err := s.db.Get(key)
   826  	require.NoError(t, err)
   827  	return len(val) != 0
   828  }
   829  
   830  func testElgDeprioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool {
   831  	key := encodeElgDeprioMissingDataKey(missingDataKey)
   832  
   833  	val, err := s.db.Get(key)
   834  	require.NoError(t, err)
   835  	return len(val) != 0
   836  }
   837  
   838  func testInelgMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool {
   839  	key := encodeInelgMissingDataKey(missingDataKey)
   840  
   841  	val, err := s.db.Get(key)
   842  	require.NoError(t, err)
   843  	return len(val) != 0
   844  }
   845  
   846  func testWaitForPurgerRoutineToFinish(s *Store) {
   847  	time.Sleep(1 * time.Second)
   848  	s.purgerLock.Lock()
   849  	s.purgerLock.Unlock() //lint:ignore SA2001 syncpoint
   850  }
   851  
   852  func testutilWaitForCollElgProcToFinish(s *Store) {
   853  	s.collElgProcSync.waitForDone()
   854  }
   855  
   856  func produceSamplePvtdata(t *testing.T, txNum uint64, nsColls []string) *ledger.TxPvtData {
   857  	builder := rwsetutil.NewRWSetBuilder()
   858  	for _, nsColl := range nsColls {
   859  		nsCollSplit := strings.Split(nsColl, ":")
   860  		ns := nsCollSplit[0]
   861  		coll := nsCollSplit[1]
   862  		builder.AddToPvtAndHashedWriteSet(ns, coll, fmt.Sprintf("key-%s-%s", ns, coll), []byte(fmt.Sprintf("value-%s-%s", ns, coll)))
   863  	}
   864  	simRes, err := builder.GetTxSimulationResults()
   865  	require.NoError(t, err)
   866  	return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults}
   867  }