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