github.com/sykesm/fabric@v1.1.0-preview.0.20200129034918-2aa12b1a0181/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
    36  	testEmpty(true, assert, store)
    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 TestInitLastCommittedBlock(t *testing.T) {
   595  	env := NewTestStoreEnv(t, "TestStoreState", nil, pvtDataConf())
   596  	defer env.Cleanup()
   597  	assert := assert.New(t)
   598  	store := env.TestStore
   599  	existingLastBlockNum := uint64(25)
   600  	assert.NoError(store.InitLastCommittedBlock(existingLastBlockNum))
   601  
   602  	testEmpty(false, assert, store)
   603  	testLastCommittedBlockHeight(existingLastBlockNum+1, assert, store)
   604  
   605  	env.CloseAndReopen()
   606  	testEmpty(false, assert, store)
   607  	testLastCommittedBlockHeight(existingLastBlockNum+1, assert, store)
   608  
   609  	err := store.InitLastCommittedBlock(30)
   610  	_, ok := err.(*ErrIllegalCall)
   611  	assert.True(ok)
   612  }
   613  
   614  func TestPendingBatch(t *testing.T) {
   615  	btlPolicy := btltestutil.SampleBTLPolicy(
   616  		map[[2]string]uint64{
   617  			{"ns-1", "coll-1"}: 0,
   618  			{"ns-1", "coll-2"}: 0,
   619  		},
   620  	)
   621  	env := NewTestStoreEnv(t, "TestPendingBatch", btlPolicy, pvtDataConf())
   622  	defer env.Cleanup()
   623  	assert := assert.New(t)
   624  	s := env.TestStore
   625  	existingLastBlockNum := uint64(25)
   626  	assert.NoError(s.InitLastCommittedBlock(existingLastBlockNum))
   627  	testLastCommittedBlockHeight(existingLastBlockNum+1, assert, s)
   628  
   629  	// assume that a block has been prepared in v142 and the peer was
   630  	// killed for upgrade. When the pvtdataStore is opened again with
   631  	// v2.0 peer, the pendingBatch should be marked as committed.
   632  	batch := leveldbhelper.NewUpdateBatch()
   633  
   634  	// store pvtData entries
   635  	dataKey := &dataKey{nsCollBlk{"ns-1", "coll-1", 26}, 1}
   636  	dataValue := &rwset.CollectionPvtReadWriteSet{CollectionName: "coll-1", Rwset: []byte("pvtdata")}
   637  	keyBytes := encodeDataKey(dataKey)
   638  	valueBytes, err := encodeDataValue(dataValue)
   639  	assert.NoError(err)
   640  	batch.Put(keyBytes, valueBytes)
   641  
   642  	// store pendingBatch marker
   643  	batch.Put(pendingCommitKey, emptyValue)
   644  
   645  	// write to the store
   646  	assert.NoError(s.(*store).db.WriteBatch(batch, true))
   647  	testLastCommittedBlockHeight(existingLastBlockNum+1, assert, s)
   648  
   649  	// as the block commit is pending, we cannot read the pvtData
   650  	hasPendingBatch, err := s.(*store).hasPendingCommit()
   651  	assert.NoError(err)
   652  	assert.Equal(true, hasPendingBatch)
   653  	pvtData, err := s.GetPvtDataByBlockNum(26, nil)
   654  	_, ok := err.(*ErrOutOfRange)
   655  	assert.True(ok)
   656  	assert.Nil(pvtData)
   657  
   658  	// emulate a version upgrade
   659  	env.CloseAndReopen()
   660  
   661  	s = env.TestStore
   662  	testLastCommittedBlockHeight(existingLastBlockNum+2, assert, s)
   663  	hasPendingBatch, err = s.(*store).hasPendingCommit()
   664  	assert.NoError(err)
   665  	assert.Equal(false, hasPendingBatch)
   666  	testDataKeyExists(t, s, dataKey)
   667  
   668  	expectedPvtData := &rwset.TxPvtReadWriteSet{
   669  		NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   670  			{
   671  				Namespace: "ns-1",
   672  				CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   673  					dataValue,
   674  				},
   675  			},
   676  		},
   677  	}
   678  	pvtData, err = s.GetPvtDataByBlockNum(26, nil)
   679  	assert.NoError(err)
   680  	assert.Equal(1, len(pvtData))
   681  	assert.Equal(uint64(1), pvtData[0].SeqInBlock)
   682  	assert.True(proto.Equal(expectedPvtData, pvtData[0].WriteSet))
   683  }
   684  
   685  func TestCollElgEnabled(t *testing.T) {
   686  	conf := pvtDataConf()
   687  	testCollElgEnabled(t, conf)
   688  	conf.BatchesInterval = 1
   689  	conf.MaxBatchSize = 1
   690  	testCollElgEnabled(t, conf)
   691  }
   692  
   693  func testCollElgEnabled(t *testing.T, conf *PrivateDataConfig) {
   694  	ledgerid := "TestCollElgEnabled"
   695  	btlPolicy := btltestutil.SampleBTLPolicy(
   696  		map[[2]string]uint64{
   697  			{"ns-1", "coll-1"}: 0,
   698  			{"ns-1", "coll-2"}: 0,
   699  			{"ns-2", "coll-1"}: 0,
   700  			{"ns-2", "coll-2"}: 0,
   701  		},
   702  	)
   703  	env := NewTestStoreEnv(t, ledgerid, btlPolicy, conf)
   704  	defer env.Cleanup()
   705  	assert := assert.New(t)
   706  	testStore := env.TestStore
   707  
   708  	// Initial state: eligible for {ns-1:coll-1 and ns-2:coll-1 }
   709  
   710  	// no pvt data with block 0
   711  	assert.NoError(testStore.Commit(0, nil, nil))
   712  
   713  	// construct and commit block 1
   714  	blk1MissingData := make(ledger.TxMissingPvtDataMap)
   715  	blk1MissingData.Add(1, "ns-1", "coll-1", true)
   716  	blk1MissingData.Add(1, "ns-2", "coll-1", true)
   717  	blk1MissingData.Add(4, "ns-1", "coll-2", false)
   718  	blk1MissingData.Add(4, "ns-2", "coll-2", false)
   719  	testDataForBlk1 := []*ledger.TxPvtData{
   720  		produceSamplePvtdata(t, 2, []string{"ns-1:coll-1"}),
   721  	}
   722  	assert.NoError(testStore.Commit(1, testDataForBlk1, blk1MissingData))
   723  
   724  	// construct and commit block 2
   725  	blk2MissingData := make(ledger.TxMissingPvtDataMap)
   726  	// ineligible missing data in tx1
   727  	blk2MissingData.Add(1, "ns-1", "coll-2", false)
   728  	blk2MissingData.Add(1, "ns-2", "coll-2", false)
   729  	testDataForBlk2 := []*ledger.TxPvtData{
   730  		produceSamplePvtdata(t, 3, []string{"ns-1:coll-1"}),
   731  	}
   732  	assert.NoError(testStore.Commit(2, testDataForBlk2, blk2MissingData))
   733  
   734  	// Retrieve and verify missing data reported
   735  	// Expected missing data should be only blk1-tx1 (because, the other missing data is marked as ineliigible)
   736  	expectedMissingPvtDataInfo := make(ledger.MissingPvtDataInfo)
   737  	expectedMissingPvtDataInfo.Add(1, 1, "ns-1", "coll-1")
   738  	expectedMissingPvtDataInfo.Add(1, 1, "ns-2", "coll-1")
   739  	missingPvtDataInfo, err := testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   740  	assert.NoError(err)
   741  	assert.Equal(expectedMissingPvtDataInfo, missingPvtDataInfo)
   742  
   743  	// Enable eligibility for {ns-1:coll2}
   744  	testStore.ProcessCollsEligibilityEnabled(
   745  		5,
   746  		map[string][]string{
   747  			"ns-1": {"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-1", "coll-2")
   755  	expectedMissingPvtDataInfo.Add(2, 1, "ns-1", "coll-2")
   756  	missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   757  	assert.NoError(err)
   758  	assert.Equal(expectedMissingPvtDataInfo, missingPvtDataInfo)
   759  
   760  	// Enable eligibility for {ns-2:coll2}
   761  	testStore.ProcessCollsEligibilityEnabled(6,
   762  		map[string][]string{
   763  			"ns-2": {"coll-2"},
   764  		},
   765  	)
   766  	testutilWaitForCollElgProcToFinish(testStore)
   767  
   768  	// Retrieve and verify missing data reported
   769  	// Expected missing data should include newly eiligible collections
   770  	expectedMissingPvtDataInfo.Add(1, 4, "ns-2", "coll-2")
   771  	expectedMissingPvtDataInfo.Add(2, 1, "ns-2", "coll-2")
   772  	missingPvtDataInfo, err = testStore.GetMissingPvtDataInfoForMostRecentBlocks(10)
   773  	assert.Equal(expectedMissingPvtDataInfo, missingPvtDataInfo)
   774  }
   775  
   776  func testEmpty(expectedEmpty bool, assert *assert.Assertions, store Store) {
   777  	isEmpty, err := store.IsEmpty()
   778  	assert.NoError(err)
   779  	assert.Equal(expectedEmpty, isEmpty)
   780  }
   781  
   782  func testLastCommittedBlockHeight(expectedBlockHt uint64, assert *assert.Assertions, store Store) {
   783  	blkHt, err := store.LastCommittedBlockHeight()
   784  	assert.NoError(err)
   785  	assert.Equal(expectedBlockHt, blkHt)
   786  }
   787  
   788  func testDataKeyExists(t *testing.T, s Store, dataKey *dataKey) bool {
   789  	dataKeyBytes := encodeDataKey(dataKey)
   790  	val, err := s.(*store).db.Get(dataKeyBytes)
   791  	assert.NoError(t, err)
   792  	return len(val) != 0
   793  }
   794  
   795  func testMissingDataKeyExists(t *testing.T, s Store, missingDataKey *missingDataKey) bool {
   796  	dataKeyBytes := encodeMissingDataKey(missingDataKey)
   797  	val, err := s.(*store).db.Get(dataKeyBytes)
   798  	assert.NoError(t, err)
   799  	return len(val) != 0
   800  }
   801  
   802  func testWaitForPurgerRoutineToFinish(s Store) {
   803  	time.Sleep(1 * time.Second)
   804  	s.(*store).purgerLock.Lock()
   805  	s.(*store).purgerLock.Unlock()
   806  }
   807  
   808  func testutilWaitForCollElgProcToFinish(s Store) {
   809  	s.(*store).collElgProcSync.waitForDone()
   810  }
   811  
   812  func produceSamplePvtdata(t *testing.T, txNum uint64, nsColls []string) *ledger.TxPvtData {
   813  	builder := rwsetutil.NewRWSetBuilder()
   814  	for _, nsColl := range nsColls {
   815  		nsCollSplit := strings.Split(nsColl, ":")
   816  		ns := nsCollSplit[0]
   817  		coll := nsCollSplit[1]
   818  		builder.AddToPvtAndHashedWriteSet(ns, coll, fmt.Sprintf("key-%s-%s", ns, coll), []byte(fmt.Sprintf("value-%s-%s", ns, coll)))
   819  	}
   820  	simRes, err := builder.GetTxSimulationResults()
   821  	assert.NoError(t, err)
   822  	return &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: simRes.PvtSimulationResults}
   823  }