github.com/osdi23p228/fabric@v0.0.0-20221218062954-77808885f5db/core/ledger/pvtdatastorage/store_test.go (about)

     1  /*
     2  Copyright IBM Corp. 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/hyperledger/fabric-protos-go/ledger/rwset"
    19  	"github.com/osdi23p228/fabric/common/ledger/util/leveldbhelper"
    20  	"github.com/osdi23p228/fabric/core/ledger"
    21  	"github.com/osdi23p228/fabric/core/ledger/kvledger/txmgmt/rwsetutil"
    22  	btltestutil "github.com/osdi23p228/fabric/core/ledger/pvtdatapolicy/testutil"
    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.TxMissingPvtDataMap)
    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.TxMissingPvtDataMap)
    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  	_, ok := err.(*ErrOutOfRange)
   118  	require.True(t, ok)
   119  	require.Nil(t, retrievedData)
   120  
   121  	// pvt data with block 2 - commit
   122  	require.NoError(t, store.Commit(2, testData, blk2MissingData))
   123  
   124  	// retrieve the stored missing entries using GetMissingPvtDataInfoForMostRecentBlocks
   125  	// Only the code path of eligible entries would be covered in this unit-test. For
   126  	// ineligible entries, the code path will be covered in FAB-11437
   127  
   128  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   129  	// missing data in block2, tx1
   130  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1")
   131  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   132  	expectedMissingPvtDataInfo.Add(2, 3, "ns-1", "coll-1")
   133  
   134  	missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(1)
   135  	require.NoError(t, err)
   136  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   137  
   138  	// missing data in block1, tx1
   139  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   140  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   141  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1")
   142  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-2")
   143  
   144  	// missing data in block1, tx2
   145  	expectedMissingPvtDataInfo.Add(1, 2, "ns-3", "coll-1")
   146  
   147  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(2)
   148  	require.NoError(t, err)
   149  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   150  
   151  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   152  	require.NoError(t, err)
   153  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   154  }
   155  
   156  func TestStoreIteratorError(t *testing.T) {
   157  	env := NewTestStoreEnv(t, "TestStoreIteratorError", nil, pvtDataConf())
   158  	defer env.Cleanup()
   159  	store := env.TestStore
   160  	require.NoError(t, store.Commit(0, nil, nil))
   161  	env.TestStoreProvider.Close()
   162  	errStr := "internal leveldb error while obtaining db iterator: leveldb: closed"
   163  
   164  	t.Run("GetPvtDataByBlockNum", func(t *testing.T) {
   165  		block, err := store.GetPvtDataByBlockNum(0, nil)
   166  		require.EqualError(t, err, errStr)
   167  		require.Nil(t, block)
   168  	})
   169  
   170  	t.Run("GetMissingPvtDataInfoForMostRecentBlocks", func(t *testing.T) {
   171  		missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   172  		require.EqualError(t, err, errStr)
   173  		require.Nil(t, missingPvtDataInfo)
   174  	})
   175  
   176  	t.Run("retrieveExpiryEntries", func(t *testing.T) {
   177  		expiryEntries, err := store.retrieveExpiryEntries(0, 1)
   178  		require.EqualError(t, err, errStr)
   179  		require.Nil(t, expiryEntries)
   180  	})
   181  
   182  	t.Run("processCollElgEvents", func(t *testing.T) {
   183  		storeDir, err := ioutil.TempDir("", "pdstore")
   184  		require.NoError(t, err)
   185  		s := &Store{}
   186  		dbProvider, err := leveldbhelper.NewProvider(&leveldbhelper.Conf{DBPath: storeDir})
   187  		require.NoError(t, err)
   188  		s.db = dbProvider.GetDBHandle("test-ledger")
   189  		dbProvider.Close()
   190  		require.EqualError(t, s.processCollElgEvents(), errStr)
   191  	})
   192  }
   193  
   194  func TestGetMissingDataInfo(t *testing.T) {
   195  	setup := func(ledgerid string, c *PrivateDataConfig) *Store {
   196  		btlPolicy := btltestutil.SampleBTLPolicy(
   197  			map[[2]string]uint64{
   198  				{"ns-1", "coll-1"}: 0,
   199  				{"ns-1", "coll-2"}: 0,
   200  			},
   201  		)
   202  
   203  		env := NewTestStoreEnv(t, ledgerid, btlPolicy, c)
   204  		t.Cleanup(
   205  			func() {
   206  				defer env.Cleanup()
   207  			},
   208  		)
   209  		store := env.TestStore
   210  
   211  		// construct missing data for block 1
   212  		blk1MissingData := make(ledger.TxMissingPvtDataMap)
   213  		blk1MissingData.Add(1, "ns-1", "coll-1", true)
   214  		blk1MissingData.Add(1, "ns-1", "coll-2", true)
   215  
   216  		require.NoError(t, store.Commit(0, nil, nil))
   217  		require.NoError(t, store.Commit(1, nil, blk1MissingData))
   218  
   219  		deprioritizedList := ledger.MissingPvtDataInfo{
   220  			1: ledger.MissingBlockPvtdataInfo{
   221  				1: {
   222  					{
   223  						Namespace:  "ns-1",
   224  						Collection: "coll-2",
   225  					},
   226  				},
   227  			},
   228  		}
   229  		require.NoError(t, store.CommitPvtDataOfOldBlocks(nil, deprioritizedList))
   230  
   231  		return env.TestStore
   232  	}
   233  
   234  	t.Run("always access deprioritized missing data", func(t *testing.T) {
   235  		conf := pvtDataConf()
   236  		conf.DeprioritizedDataReconcilerInterval = 0
   237  		store := setup("testGetMissingDataInfoFromDeprioList", conf)
   238  
   239  		expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{
   240  			1: ledger.MissingBlockPvtdataInfo{
   241  				1: {
   242  					{
   243  						Namespace:  "ns-1",
   244  						Collection: "coll-2",
   245  					},
   246  				},
   247  			},
   248  		}
   249  
   250  		for i := 0; i < 2; i++ {
   251  			assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2)
   252  		}
   253  	})
   254  
   255  	t.Run("change the deprioritized missing data access time", func(t *testing.T) {
   256  		conf := pvtDataConf()
   257  		conf.DeprioritizedDataReconcilerInterval = 300 * time.Minute
   258  		store := setup("testGetMissingDataInfoFromPrioAndDeprioList", conf)
   259  
   260  		expectedPrioMissingDataInfo := ledger.MissingPvtDataInfo{
   261  			1: ledger.MissingBlockPvtdataInfo{
   262  				1: {
   263  					{
   264  						Namespace:  "ns-1",
   265  						Collection: "coll-1",
   266  					},
   267  				},
   268  			},
   269  		}
   270  
   271  		expectedDeprioMissingDataInfo := ledger.MissingPvtDataInfo{
   272  			1: ledger.MissingBlockPvtdataInfo{
   273  				1: {
   274  					{
   275  						Namespace:  "ns-1",
   276  						Collection: "coll-2",
   277  					},
   278  				},
   279  			},
   280  		}
   281  
   282  		for i := 0; i < 3; i++ {
   283  			assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2)
   284  		}
   285  
   286  		store.accessDeprioMissingDataAfter = time.Now().Add(-time.Second)
   287  		lesserThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(-2 * time.Second)
   288  		greaterThanNextAccessTime := time.Now().Add(store.deprioritizedDataReconcilerInterval).Add(2 * time.Second)
   289  		assertMissingDataInfo(t, store, expectedDeprioMissingDataInfo, 2)
   290  
   291  		require.True(t, store.accessDeprioMissingDataAfter.After(lesserThanNextAccessTime))
   292  		require.False(t, store.accessDeprioMissingDataAfter.After(greaterThanNextAccessTime))
   293  		for i := 0; i < 3; i++ {
   294  			assertMissingDataInfo(t, store, expectedPrioMissingDataInfo, 2)
   295  		}
   296  	})
   297  
   298  }
   299  
   300  func TestExpiryDataNotIncluded(t *testing.T) {
   301  	ledgerid := "TestExpiryDataNotIncluded"
   302  	btlPolicy := btltestutil.SampleBTLPolicy(
   303  		map[[2]string]uint64{
   304  			{"ns-1", "coll-1"}: 1,
   305  			{"ns-1", "coll-2"}: 0,
   306  			{"ns-2", "coll-1"}: 0,
   307  			{"ns-2", "coll-2"}: 2,
   308  			{"ns-3", "coll-1"}: 1,
   309  			{"ns-3", "coll-2"}: 0,
   310  		},
   311  	)
   312  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf())
   313  	defer env.Cleanup()
   314  	store := env.TestStore
   315  
   316  	// construct missing data for block 1
   317  	blk1MissingData := make(ledger.TxMissingPvtDataMap)
   318  	// eligible missing data in tx1
   319  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   320  	blk1MissingData.Add(1, "ns-1", "coll-2", true)
   321  	// ineligible missing data in tx4
   322  	blk1MissingData.Add(4, "ns-3", "coll-1", false)
   323  	blk1MissingData.Add(4, "ns-3", "coll-2", false)
   324  
   325  	// construct missing data for block 2
   326  	blk2MissingData := make(ledger.TxMissingPvtDataMap)
   327  	// eligible missing data in tx1
   328  	blk2MissingData.Add(1, "ns-1", "coll-1", true)
   329  	blk2MissingData.Add(1, "ns-1", "coll-2", true)
   330  
   331  	// no pvt data with block 0
   332  	require.NoError(t, store.Commit(0, nil, nil))
   333  
   334  	// write pvt data for block 1
   335  	testDataForBlk1 := []*ledger.TxPvtData{
   336  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   337  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   338  	}
   339  	require.NoError(t, store.Commit(1, testDataForBlk1, blk1MissingData))
   340  
   341  	// write pvt data for block 2
   342  	testDataForBlk2 := []*ledger.TxPvtData{
   343  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   344  		produceSamplePvtdata(t, 5, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   345  	}
   346  	require.NoError(t, store.Commit(2, testDataForBlk2, blk2MissingData))
   347  
   348  	retrievedData, _ := store.GetPvtDataByBlockNum(1, nil)
   349  	// block 1 data should still be not expired
   350  	for i, data := range retrievedData {
   351  		require.Equal(t, data.SeqInBlock, testDataForBlk1[i].SeqInBlock)
   352  		require.True(t, proto.Equal(data.WriteSet, testDataForBlk1[i].WriteSet))
   353  	}
   354  
   355  	// none of the missing data entries would have expired
   356  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   357  	// missing data in block2, tx1
   358  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1")
   359  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   360  
   361  	// missing data in block1, tx1
   362  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   363  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   364  
   365  	missingPvtDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   366  	require.NoError(t, err)
   367  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   368  
   369  	// Commit block 3 with no pvtdata
   370  	require.NoError(t, store.Commit(3, nil, nil))
   371  
   372  	// After committing block 3, the data for "ns-1:coll1" of block 1 should have expired and should not be returned by the store
   373  	expectedPvtdataFromBlock1 := []*ledger.TxPvtData{
   374  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   375  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   376  	}
   377  	retrievedData, _ = store.GetPvtDataByBlockNum(1, nil)
   378  	require.Equal(t, expectedPvtdataFromBlock1, retrievedData)
   379  
   380  	// After committing block 3, the missing data of "ns1-coll1" in block1-tx1 should have expired
   381  	expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo)
   382  	// missing data in block2, tx1
   383  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-1")
   384  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   385  	// missing data in block1, tx1
   386  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   387  
   388  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   389  	require.NoError(t, err)
   390  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   391  
   392  	// Commit block 4 with no pvtdata
   393  	require.NoError(t, store.Commit(4, nil, nil))
   394  
   395  	// 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
   396  	expectedPvtdataFromBlock1 = []*ledger.TxPvtData{
   397  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-2", "ns-2:coll-1"}),
   398  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-2", "ns-2:coll-1"}),
   399  	}
   400  	retrievedData, _ = store.GetPvtDataByBlockNum(1, nil)
   401  	require.Equal(t, expectedPvtdataFromBlock1, retrievedData)
   402  
   403  	// Now, for block 2, "ns-1:coll1" should also have expired
   404  	expectedPvtdataFromBlock2 := []*ledger.TxPvtData{
   405  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   406  		produceSamplePvtdata(t, 5, []string{"ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   407  	}
   408  	retrievedData, _ = store.GetPvtDataByBlockNum(2, nil)
   409  	require.Equal(t, expectedPvtdataFromBlock2, retrievedData)
   410  
   411  	// After committing block 4, the missing data of "ns1-coll1" in block2-tx1 should have expired
   412  	expectedMissingPvtDataInfo = make(ledger.MissingPvtDataInfo)
   413  	// missing data in block2, tx1
   414  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   415  
   416  	// missing data in block1, tx1
   417  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-2")
   418  
   419  	missingPvtDataInfo, err = store.GetMissingPvtDataInfoForMostRecentBlocks(10)
   420  	require.NoError(t, err)
   421  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   422  }
   423  
   424  func TestStorePurge(t *testing.T) {
   425  	ledgerid := "TestStorePurge"
   426  	btlPolicy := btltestutil.SampleBTLPolicy(
   427  		map[[2]string]uint64{
   428  			{"ns-1", "coll-1"}: 1,
   429  			{"ns-1", "coll-2"}: 0,
   430  			{"ns-2", "coll-1"}: 0,
   431  			{"ns-2", "coll-2"}: 4,
   432  			{"ns-3", "coll-1"}: 1,
   433  			{"ns-3", "coll-2"}: 0,
   434  		},
   435  	)
   436  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, pvtDataConf())
   437  	defer env.Cleanup()
   438  	s := env.TestStore
   439  
   440  	// no pvt data with block 0
   441  	require.NoError(t, s.Commit(0, nil, nil))
   442  
   443  	// construct missing data for block 1
   444  	blk1MissingData := make(ledger.TxMissingPvtDataMap)
   445  	// eligible missing data in tx1
   446  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   447  	blk1MissingData.Add(1, "ns-1", "coll-2", true)
   448  	// eligible missing data in tx3
   449  	blk1MissingData.Add(3, "ns-1", "coll-1", true)
   450  	blk1MissingData.Add(3, "ns-1", "coll-2", true)
   451  	// ineligible missing data in tx4
   452  	blk1MissingData.Add(4, "ns-3", "coll-1", false)
   453  	blk1MissingData.Add(4, "ns-3", "coll-2", false)
   454  
   455  	// write pvt data for block 1
   456  	testDataForBlk1 := []*ledger.TxPvtData{
   457  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   458  		produceSamplePvtdata(t, 4, []string{"ns-1:coll-1", "ns-1:coll-2", "ns-2:coll-1", "ns-2:coll-2"}),
   459  	}
   460  	require.NoError(t, s.Commit(1, testDataForBlk1, blk1MissingData))
   461  
   462  	// write pvt data for block 2
   463  	require.NoError(t, s.Commit(2, nil, nil))
   464  	// data for ns-1:coll-1 and ns-2:coll-2 should exist in store
   465  	ns1Coll1 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}, txNum: 2}
   466  	ns2Coll2 := &dataKey{nsCollBlk: nsCollBlk{ns: "ns-2", coll: "coll-2", blkNum: 1}, txNum: 2}
   467  
   468  	// eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store
   469  	ns1Coll1elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-1", blkNum: 1}}
   470  	ns1Coll2elgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}}
   471  
   472  	// ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store
   473  	ns3Coll1inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-1", blkNum: 1}}
   474  	ns3Coll2inelgMD := &missingDataKey{nsCollBlk: nsCollBlk{ns: "ns-3", coll: "coll-2", blkNum: 1}}
   475  
   476  	testWaitForPurgerRoutineToFinish(s)
   477  	require.True(t, testDataKeyExists(t, s, ns1Coll1))
   478  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   479  
   480  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   481  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   482  
   483  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD))
   484  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD))
   485  
   486  	deprioritizedList := ledger.MissingPvtDataInfo{
   487  		1: ledger.MissingBlockPvtdataInfo{
   488  			3: {
   489  				{
   490  					Namespace:  "ns-1",
   491  					Collection: "coll-1",
   492  				},
   493  				{
   494  					Namespace:  "ns-1",
   495  					Collection: "coll-2",
   496  				},
   497  			},
   498  		},
   499  	}
   500  	require.NoError(t, s.CommitPvtDataOfOldBlocks(nil, deprioritizedList))
   501  
   502  	// write pvt data for block 3
   503  	require.NoError(t, s.Commit(3, nil, nil))
   504  	// data for ns-1:coll-1 and ns-2:coll-2 should exist in store (because purger should not be launched at block 3)
   505  	testWaitForPurgerRoutineToFinish(s)
   506  	require.True(t, testDataKeyExists(t, s, ns1Coll1))
   507  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   508  	// eligible missingData entries for ns-1:coll-1, ns-1:coll-2 (neverExpires) should exist in store
   509  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   510  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   511  	// some transactions which miss ns-1:coll-1 and ns-1:coll-2 has be moved to deprioritizedList list
   512  	require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   513  	require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   514  	// ineligible missingData entries for ns-3:col-1, ns-3:coll-2 (neverExpires) should exist in store
   515  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD))
   516  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD))
   517  
   518  	// write pvt data for block 4
   519  	require.NoError(t, s.Commit(4, nil, nil))
   520  	// data for ns-1:coll-1 should not exist in store (because purger should be launched at block 4)
   521  	// but ns-2:coll-2 should exist because it expires at block 5
   522  	testWaitForPurgerRoutineToFinish(s)
   523  	require.False(t, testDataKeyExists(t, s, ns1Coll1))
   524  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   525  	// eligible missingData entries for ns-1:coll-1 should have expired and ns-1:coll-2 (neverExpires) should exist in store
   526  	require.False(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   527  	require.True(t, testElgPrioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   528  	require.False(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll1elgMD))
   529  	require.True(t, testElgDeprioMissingDataKeyExists(t, s, ns1Coll2elgMD))
   530  	// ineligible missingData entries for ns-3:col-1 should have expired and ns-3:coll-2 (neverExpires) should exist in store
   531  	require.False(t, testInelgMissingDataKeyExists(t, s, ns3Coll1inelgMD))
   532  	require.True(t, testInelgMissingDataKeyExists(t, s, ns3Coll2inelgMD))
   533  
   534  	// write pvt data for block 5
   535  	require.NoError(t, s.Commit(5, nil, nil))
   536  	// ns-2:coll-2 should exist because though the data expires at block 5 but purger is launched every second block
   537  	testWaitForPurgerRoutineToFinish(s)
   538  	require.False(t, testDataKeyExists(t, s, ns1Coll1))
   539  	require.True(t, testDataKeyExists(t, s, ns2Coll2))
   540  
   541  	// write pvt data for block 6
   542  	require.NoError(t, s.Commit(6, nil, nil))
   543  	// ns-2:coll-2 should not exists now (because purger should be launched at block 6)
   544  	testWaitForPurgerRoutineToFinish(s)
   545  	require.False(t, testDataKeyExists(t, s, ns1Coll1))
   546  	require.False(t, testDataKeyExists(t, s, ns2Coll2))
   547  
   548  	// "ns-2:coll-1" should never have been purged (because, it was no btl was declared for this)
   549  	require.True(t, testDataKeyExists(t, s, &dataKey{nsCollBlk: nsCollBlk{ns: "ns-1", coll: "coll-2", blkNum: 1}, txNum: 2}))
   550  }
   551  
   552  func TestStoreState(t *testing.T) {
   553  	btlPolicy := btltestutil.SampleBTLPolicy(
   554  		map[[2]string]uint64{
   555  			{"ns-1", "coll-1"}: 0,
   556  			{"ns-1", "coll-2"}: 0,
   557  		},
   558  	)
   559  	env := NewTestStoreEnv(t, "TestStoreState", btlPolicy, pvtDataConf())
   560  	defer env.Cleanup()
   561  	store := env.TestStore
   562  	testData := []*ledger.TxPvtData{
   563  		produceSamplePvtdata(t, 0, []string{"ns-1:coll-1", "ns-1:coll-2"}),
   564  	}
   565  	_, ok := store.Commit(1, testData, nil).(*ErrIllegalArgs)
   566  	require.True(t, ok)
   567  }
   568  
   569  func TestPendingBatch(t *testing.T) {
   570  	btlPolicy := btltestutil.SampleBTLPolicy(
   571  		map[[2]string]uint64{
   572  			{"ns-1", "coll-1"}: 0,
   573  			{"ns-1", "coll-2"}: 0,
   574  		},
   575  	)
   576  	env := NewTestStoreEnv(t, "TestPendingBatch", btlPolicy, pvtDataConf())
   577  	defer env.Cleanup()
   578  	s := env.TestStore
   579  	existingLastBlockNum := uint64(25)
   580  	batch := s.db.NewUpdateBatch()
   581  	batch.Put(lastCommittedBlkkey, encodeLastCommittedBlockVal(existingLastBlockNum))
   582  	require.NoError(t, s.db.WriteBatch(batch, true))
   583  	s.lastCommittedBlock = existingLastBlockNum
   584  	s.isEmpty = false
   585  	testLastCommittedBlockHeight(t, existingLastBlockNum+1, s)
   586  
   587  	// assume that a block has been prepared in v142 and the peer was
   588  	// killed for upgrade. When the pvtdataStore is opened again with
   589  	// v2.0 peer, the pendingBatch should be marked as committed.
   590  	batch = s.db.NewUpdateBatch()
   591  
   592  	// store pvtData entries
   593  	dataKey := &dataKey{nsCollBlk{"ns-1", "coll-1", 26}, 1}
   594  	dataValue := &rwset.CollectionPvtReadWriteSet{CollectionName: "coll-1", Rwset: []byte("pvtdata")}
   595  	keyBytes := encodeDataKey(dataKey)
   596  	valueBytes, err := encodeDataValue(dataValue)
   597  	require.NoError(t, err)
   598  	batch.Put(keyBytes, valueBytes)
   599  
   600  	// store pendingBatch marker
   601  	batch.Put(pendingCommitKey, emptyValue)
   602  
   603  	// write to the store
   604  	require.NoError(t, s.db.WriteBatch(batch, true))
   605  	testLastCommittedBlockHeight(t, existingLastBlockNum+1, s)
   606  
   607  	// as the block commit is pending, we cannot read the pvtData
   608  	hasPendingBatch, err := s.hasPendingCommit()
   609  	require.NoError(t, err)
   610  	require.Equal(t, true, hasPendingBatch)
   611  	pvtData, err := s.GetPvtDataByBlockNum(26, nil)
   612  	_, ok := err.(*ErrOutOfRange)
   613  	require.True(t, ok)
   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 testCollElgEnabled(t *testing.T, conf *PrivateDataConfig) {
   652  	ledgerid := "TestCollElgEnabled"
   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  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, conf)
   662  	defer env.Cleanup()
   663  	testStore := env.TestStore
   664  
   665  	// Initial state: eligible for {ns-1:coll-1 and ns-2:coll-1 }
   666  
   667  	// no pvt data with block 0
   668  	require.NoError(t, testStore.Commit(0, nil, nil))
   669  
   670  	// construct and commit block 1
   671  	blk1MissingData := make(ledger.TxMissingPvtDataMap)
   672  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   673  	blk1MissingData.Add(1, "ns-2", "coll-1", true)
   674  	blk1MissingData.Add(4, "ns-1", "coll-2", false)
   675  	blk1MissingData.Add(4, "ns-2", "coll-2", false)
   676  	testDataForBlk1 := []*ledger.TxPvtData{
   677  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1"}),
   678  	}
   679  	require.NoError(t, testStore.Commit(1, testDataForBlk1, blk1MissingData))
   680  
   681  	// construct and commit block 2
   682  	blk2MissingData := make(ledger.TxMissingPvtDataMap)
   683  	// ineligible missing data in tx1
   684  	blk2MissingData.Add(1, "ns-1", "coll-2", false)
   685  	blk2MissingData.Add(1, "ns-2", "coll-2", false)
   686  	testDataForBlk2 := []*ledger.TxPvtData{
   687  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-1"}),
   688  	}
   689  	require.NoError(t, testStore.Commit(2, testDataForBlk2, blk2MissingData))
   690  
   691  	// Retrieve and verify missing data reported
   692  	// Expected missing data should be only blk1-tx1 (because, the other missing data is marked as ineliigible)
   693  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   694  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   695  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1")
   696  	missingPvtDataInfo, err := testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   697  	require.NoError(t, err)
   698  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   699  
   700  	// Enable eligibility for {ns-1:coll2}
   701  	require.NoError(t,
   702  		testStore.ProcessCollsEligibilityEnabled(
   703  			5,
   704  			map[string][]string{
   705  				"ns-1": {"coll-2"},
   706  			},
   707  		))
   708  	testutilWaitForCollElgProcToFinish(testStore)
   709  
   710  	// Retrieve and verify missing data reported
   711  	// Expected missing data should include newly eiligible collections
   712  	expectedMissingPvtDataInfo.Add(1, 4, "ns-1", "coll-2")
   713  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   714  	missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   715  	require.NoError(t, err)
   716  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   717  
   718  	// Enable eligibility for {ns-2:coll2}
   719  	require.NoError(t,
   720  		testStore.ProcessCollsEligibilityEnabled(6,
   721  			map[string][]string{
   722  				"ns-2": {"coll-2"},
   723  			},
   724  		))
   725  	testutilWaitForCollElgProcToFinish(testStore)
   726  
   727  	// Retrieve and verify missing data reported
   728  	// Expected missing data should include newly eiligible collections
   729  	expectedMissingPvtDataInfo.Add(1, 4, "ns-2", "coll-2")
   730  	expectedMissingPvtDataInfo.Add(2, 1, "ns-2", "coll-2")
   731  	missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   732  	require.NoError(t, err)
   733  	require.Equal(t, expectedMissingPvtDataInfo, missingPvtDataInfo)
   734  }
   735  
   736  func testLastCommittedBlockHeight(t *testing.T, expectedBlockHt uint64, store *Store) {
   737  	blkHt, err := store.LastCommittedBlockHeight()
   738  	require.NoError(t, err)
   739  	require.Equal(t, expectedBlockHt, blkHt)
   740  }
   741  
   742  func testDataKeyExists(t *testing.T, s *Store, dataKey *dataKey) bool {
   743  	dataKeyBytes := encodeDataKey(dataKey)
   744  	val, err := s.db.Get(dataKeyBytes)
   745  	require.NoError(t, err)
   746  	return len(val) != 0
   747  }
   748  
   749  func testElgPrioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool {
   750  	key := encodeElgPrioMissingDataKey(missingDataKey)
   751  
   752  	val, err := s.db.Get(key)
   753  	require.NoError(t, err)
   754  	return len(val) != 0
   755  }
   756  
   757  func testElgDeprioMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool {
   758  	key := encodeElgDeprioMissingDataKey(missingDataKey)
   759  
   760  	val, err := s.db.Get(key)
   761  	require.NoError(t, err)
   762  	return len(val) != 0
   763  }
   764  func testInelgMissingDataKeyExists(t *testing.T, s *Store, missingDataKey *missingDataKey) bool {
   765  	key := encodeInelgMissingDataKey(missingDataKey)
   766  
   767  	val, err := s.db.Get(key)
   768  	require.NoError(t, err)
   769  	return len(val) != 0
   770  }
   771  
   772  func testWaitForPurgerRoutineToFinish(s *Store) {
   773  	time.Sleep(1 * time.Second)
   774  	s.purgerLock.Lock()
   775  	s.purgerLock.Unlock()
   776  }
   777  
   778  func testutilWaitForCollElgProcToFinish(s *Store) {
   779  	s.collElgProcSync.waitForDone()
   780  }
   781  
   782  func produceSamplePvtdata(t *testing.T, txNum uint64, nsColls []string) *ledger.TxPvtData {
   783  	builder := rwsetutil.NewRWSetBuilder()
   784  	for _, nsColl := range nsColls {
   785  		nsCollSplit := strings.Split(nsColl, ":")
   786  		ns := nsCollSplit[0]
   787  		coll := nsCollSplit[1]
   788  		builder.AddToPvtAndHashedWriteSet(ns, coll, fmt.Sprintf("key-%s-%s", ns, coll), []byte(fmt.Sprintf("value-%s-%s", ns, coll)))
   789  	}
   790  	simRes, err := builder.GetTxSimulationResults()
   791  	require.NoError(t, err)
   792  	return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults}
   793  }