github.com/kaituanwang/hyperledger@v2.0.1+incompatible/core/ledger/ledgerstorage/store_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package ledgerstorage
     8  
     9  import (
    10  	"io/ioutil"
    11  	"os"
    12  	"path/filepath"
    13  	"testing"
    14  
    15  	"github.com/golang/protobuf/proto"
    16  	"github.com/hyperledger/fabric-protos-go/common"
    17  	"github.com/hyperledger/fabric-protos-go/ledger/rwset"
    18  	pb "github.com/hyperledger/fabric-protos-go/peer"
    19  	"github.com/hyperledger/fabric/common/flogging"
    20  	"github.com/hyperledger/fabric/common/ledger/blkstorage"
    21  	"github.com/hyperledger/fabric/common/ledger/blkstorage/fsblkstorage"
    22  	"github.com/hyperledger/fabric/common/ledger/testutil"
    23  	"github.com/hyperledger/fabric/common/metrics/disabled"
    24  	"github.com/hyperledger/fabric/core/ledger"
    25  	"github.com/hyperledger/fabric/core/ledger/pvtdatapolicy"
    26  	btltestutil "github.com/hyperledger/fabric/core/ledger/pvtdatapolicy/testutil"
    27  	"github.com/hyperledger/fabric/core/ledger/pvtdatastorage"
    28  	lutil "github.com/hyperledger/fabric/core/ledger/util"
    29  	"github.com/stretchr/testify/assert"
    30  )
    31  
    32  var metricsProvider = &disabled.Provider{}
    33  
    34  func TestMain(m *testing.M) {
    35  	flogging.ActivateSpec("ledgerstorage,pvtdatastorage=debug")
    36  	os.Exit(m.Run())
    37  }
    38  
    39  func TestStore(t *testing.T) {
    40  	storeDir, err := ioutil.TempDir("", "lstore")
    41  	if err != nil {
    42  		t.Fatalf("Failed to create ledger storage directory: %s", err)
    43  	}
    44  	defer os.RemoveAll(storeDir)
    45  	conf := buildPrivateDataConfig(storeDir)
    46  	blockStoreDir := filepath.Join(storeDir, "chains")
    47  	provider, err := NewProvider(blockStoreDir, conf, metricsProvider)
    48  	assert.NoError(t, err)
    49  	defer provider.Close()
    50  	store, err := provider.Open("testLedger")
    51  	store.Init(btlPolicyForSampleData())
    52  	defer store.Shutdown()
    53  
    54  	assert.NoError(t, err)
    55  	sampleData := sampleDataWithPvtdataForSelectiveTx(t)
    56  	for _, sampleDatum := range sampleData {
    57  		assert.NoError(t, store.CommitWithPvtData(sampleDatum))
    58  	}
    59  
    60  	// block 1 has no pvt data
    61  	pvtdata, err := store.GetPvtDataByNum(1, nil)
    62  	assert.NoError(t, err)
    63  	assert.Nil(t, pvtdata)
    64  
    65  	// block 4 has no pvt data
    66  	pvtdata, err = store.GetPvtDataByNum(4, nil)
    67  	assert.NoError(t, err)
    68  	assert.Nil(t, pvtdata)
    69  
    70  	// block 2 has pvt data for tx 3, 5 and 6. Though the tx 6
    71  	// is marked as invalid in the block, the pvtData should
    72  	// have been stored
    73  	pvtdata, err = store.GetPvtDataByNum(2, nil)
    74  	assert.NoError(t, err)
    75  	assert.Equal(t, 3, len(pvtdata))
    76  	assert.Equal(t, uint64(3), pvtdata[0].SeqInBlock)
    77  	assert.Equal(t, uint64(5), pvtdata[1].SeqInBlock)
    78  	assert.Equal(t, uint64(6), pvtdata[2].SeqInBlock)
    79  
    80  	// block 3 has pvt data for tx 4 and 6 only
    81  	pvtdata, err = store.GetPvtDataByNum(3, nil)
    82  	assert.NoError(t, err)
    83  	assert.Equal(t, 2, len(pvtdata))
    84  	assert.Equal(t, uint64(4), pvtdata[0].SeqInBlock)
    85  	assert.Equal(t, uint64(6), pvtdata[1].SeqInBlock)
    86  
    87  	blockAndPvtdata, err := store.GetPvtDataAndBlockByNum(2, nil)
    88  	assert.NoError(t, err)
    89  	assert.True(t, proto.Equal(sampleData[2].Block, blockAndPvtdata.Block))
    90  
    91  	blockAndPvtdata, err = store.GetPvtDataAndBlockByNum(3, nil)
    92  	assert.NoError(t, err)
    93  	assert.True(t, proto.Equal(sampleData[3].Block, blockAndPvtdata.Block))
    94  
    95  	// pvt data retrieval for block 3 with filter should return filtered pvtdata
    96  	filter := ledger.NewPvtNsCollFilter()
    97  	filter.Add("ns-1", "coll-1")
    98  	blockAndPvtdata, err = store.GetPvtDataAndBlockByNum(3, filter)
    99  	assert.NoError(t, err)
   100  	assert.Equal(t, sampleData[3].Block, blockAndPvtdata.Block)
   101  	// two transactions should be present
   102  	assert.Equal(t, 2, len(blockAndPvtdata.PvtData))
   103  	// both tran number 4 and 6 should have only one collection because of filter
   104  	assert.Equal(t, 1, len(blockAndPvtdata.PvtData[4].WriteSet.NsPvtRwset))
   105  	assert.Equal(t, 1, len(blockAndPvtdata.PvtData[6].WriteSet.NsPvtRwset))
   106  	// any other transaction entry should be nil
   107  	assert.Nil(t, blockAndPvtdata.PvtData[2])
   108  
   109  	// test missing data retrieval in the presence of invalid tx. Block 5 had
   110  	// missing data (for tx4 and tx5). Though tx5 was marked as invalid tx,
   111  	// both tx4 and tx5 missing data should be returned
   112  	expectedMissingDataInfo := make(ledger.MissingPvtDataInfo)
   113  	expectedMissingDataInfo.Add(5, 4, "ns-4", "coll-4")
   114  	expectedMissingDataInfo.Add(5, 5, "ns-5", "coll-5")
   115  	missingDataInfo, err := store.GetMissingPvtDataInfoForMostRecentBlocks(1)
   116  	assert.NoError(t, err)
   117  	assert.Equal(t, expectedMissingDataInfo, missingDataInfo)
   118  }
   119  
   120  func TestStoreWithExistingBlockchain(t *testing.T) {
   121  	testLedgerid := "test-ledger"
   122  	storeDir, err := ioutil.TempDir("", "lstore")
   123  	if err != nil {
   124  		t.Fatalf("Failed to create ledger storage directory: %s", err)
   125  	}
   126  	defer os.RemoveAll(storeDir)
   127  
   128  	// Construct a block storage
   129  	attrsToIndex := []blkstorage.IndexableAttr{
   130  		blkstorage.IndexableAttrBlockHash,
   131  		blkstorage.IndexableAttrBlockNum,
   132  		blkstorage.IndexableAttrTxID,
   133  		blkstorage.IndexableAttrBlockNumTranNum,
   134  	}
   135  	indexConfig := &blkstorage.IndexConfig{AttrsToIndex: attrsToIndex}
   136  	blockStoreProvider, err := fsblkstorage.NewProvider(
   137  		fsblkstorage.NewConf(filepath.Join(storeDir, "chains"), maxBlockFileSize),
   138  		indexConfig,
   139  		metricsProvider,
   140  	)
   141  	assert.NoError(t, err)
   142  	blkStore, err := blockStoreProvider.OpenBlockStore(testLedgerid)
   143  	assert.NoError(t, err)
   144  	testBlocks := testutil.ConstructTestBlocks(t, 10)
   145  
   146  	existingBlocks := testBlocks[0:9]
   147  	blockToAdd := testBlocks[9:][0]
   148  
   149  	// Add existingBlocks to the block storage directly without involving pvtdata store and close the block storage
   150  	for _, blk := range existingBlocks {
   151  		assert.NoError(t, blkStore.AddBlock(blk))
   152  	}
   153  	blockStoreProvider.Close()
   154  
   155  	// Simulating the upgrade from 1.0 situation:
   156  	// Open the ledger storage - pvtdata store is opened for the first time with an existing block storage
   157  	conf := buildPrivateDataConfig(storeDir)
   158  	blockStoreDir := filepath.Join(storeDir, "chains")
   159  	provider, err := NewProvider(blockStoreDir, conf, metricsProvider)
   160  	assert.NoError(t, err)
   161  	defer provider.Close()
   162  	store, err := provider.Open(testLedgerid)
   163  	assert.NoError(t, err)
   164  	store.Init(btlPolicyForSampleData())
   165  	defer store.Shutdown()
   166  
   167  	// test that pvtdata store is updated with info from existing block storage
   168  	pvtdataBlockHt, err := store.pvtdataStore.LastCommittedBlockHeight()
   169  	assert.NoError(t, err)
   170  	assert.Equal(t, uint64(9), pvtdataBlockHt)
   171  
   172  	// Add one more block with ovtdata associated with one of the trans and commit in the normal course
   173  	pvtdata := samplePvtData(t, []uint64{0})
   174  	assert.NoError(t, store.CommitWithPvtData(&ledger.BlockAndPvtData{Block: blockToAdd, PvtData: pvtdata}))
   175  	pvtdataBlockHt, err = store.pvtdataStore.LastCommittedBlockHeight()
   176  	assert.NoError(t, err)
   177  	assert.Equal(t, uint64(10), pvtdataBlockHt)
   178  }
   179  
   180  func TestCrashAfterPvtdataStoreCommit(t *testing.T) {
   181  	storeDir, err := ioutil.TempDir("", "lstore")
   182  	if err != nil {
   183  		t.Fatalf("Failed to create ledger storage directory: %s", err)
   184  	}
   185  	defer os.RemoveAll(storeDir)
   186  	conf := buildPrivateDataConfig(storeDir)
   187  	blockStoreDir := filepath.Join(storeDir, "chains")
   188  	provider, err := NewProvider(blockStoreDir, conf, metricsProvider)
   189  	assert.NoError(t, err)
   190  	defer provider.Close()
   191  	store, err := provider.Open("testLedger")
   192  	store.Init(btlPolicyForSampleData())
   193  	defer store.Shutdown()
   194  	assert.NoError(t, err)
   195  
   196  	sampleData := sampleDataWithPvtdataForAllTxs(t)
   197  	dataBeforeCrash := sampleData[0:3]
   198  	dataAtCrash := sampleData[3]
   199  
   200  	for _, sampleDatum := range dataBeforeCrash {
   201  		assert.NoError(t, store.CommitWithPvtData(sampleDatum))
   202  	}
   203  	blockNumAtCrash := dataAtCrash.Block.Header.Number
   204  	var pvtdataAtCrash []*ledger.TxPvtData
   205  	for _, p := range dataAtCrash.PvtData {
   206  		pvtdataAtCrash = append(pvtdataAtCrash, p)
   207  	}
   208  	// call Commit on pvt data store and mimic a crash before committing the block to block store
   209  	store.pvtdataStore.Commit(blockNumAtCrash, pvtdataAtCrash, nil)
   210  	store.Shutdown()
   211  	provider.Close()
   212  	provider, err = NewProvider(blockStoreDir, conf, metricsProvider)
   213  	assert.NoError(t, err)
   214  	store, err = provider.Open("testLedger")
   215  	assert.NoError(t, err)
   216  	store.Init(btlPolicyForSampleData())
   217  
   218  	// When starting the storage after a crash, we should be able to fetch the pvtData from pvtStore
   219  	testVerifyPvtData(t, store, blockNumAtCrash, dataAtCrash.PvtData)
   220  	bcInfo, err := store.GetBlockchainInfo()
   221  	assert.NoError(t, err)
   222  	assert.Equal(t, blockNumAtCrash, bcInfo.Height)
   223  
   224  	// we should be able to write the last block again
   225  	// to ensure that the pvtdataStore is not updated, we send a different pvtData for
   226  	// the same block such that we can retrieve the pvtData and compare.
   227  	expectedPvtData := dataAtCrash.PvtData
   228  	dataAtCrash.PvtData = make(ledger.TxPvtDataMap)
   229  	dataAtCrash.PvtData[0] = &ledger.TxPvtData{
   230  		SeqInBlock: 0,
   231  		WriteSet: &rwset.TxPvtReadWriteSet{
   232  			NsPvtRwset: []*rwset.NsPvtReadWriteSet{
   233  				{
   234  					Namespace: "ns-1",
   235  					CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   236  						{
   237  							CollectionName: "coll-1",
   238  							Rwset:          []byte("pvtdata"),
   239  						},
   240  					},
   241  				},
   242  			},
   243  		},
   244  	}
   245  	assert.NoError(t, store.CommitWithPvtData(dataAtCrash))
   246  	testVerifyPvtData(t, store, blockNumAtCrash, expectedPvtData)
   247  	bcInfo, err = store.GetBlockchainInfo()
   248  	assert.NoError(t, err)
   249  	assert.Equal(t, blockNumAtCrash+1, bcInfo.Height)
   250  
   251  }
   252  
   253  func testVerifyPvtData(t *testing.T, store *Store, blockNum uint64, expectedPvtData ledger.TxPvtDataMap) {
   254  	pvtdata, err := store.GetPvtDataByNum(blockNum, nil)
   255  	assert.NoError(t, err)
   256  	constructed := constructPvtdataMap(pvtdata)
   257  	assert.Equal(t, len(expectedPvtData), len(constructed))
   258  	for k, v := range expectedPvtData {
   259  		ov, ok := constructed[k]
   260  		assert.True(t, ok)
   261  		assert.Equal(t, v.SeqInBlock, ov.SeqInBlock)
   262  		assert.True(t, proto.Equal(v.WriteSet, ov.WriteSet))
   263  	}
   264  }
   265  
   266  func TestAddAfterPvtdataStoreError(t *testing.T) {
   267  	storeDir, err := ioutil.TempDir("", "lstore")
   268  	if err != nil {
   269  		t.Fatalf("Failed to create ledger storage directory: %s", err)
   270  	}
   271  	defer os.RemoveAll(storeDir)
   272  	conf := buildPrivateDataConfig(storeDir)
   273  	blockStoreDir := filepath.Join(storeDir, "chains")
   274  	provider, err := NewProvider(blockStoreDir, conf, metricsProvider)
   275  	assert.NoError(t, err)
   276  	defer provider.Close()
   277  	store, err := provider.Open("testLedger")
   278  	store.Init(btlPolicyForSampleData())
   279  	defer store.Shutdown()
   280  	assert.NoError(t, err)
   281  
   282  	sampleData := sampleDataWithPvtdataForAllTxs(t)
   283  	for _, d := range sampleData[0:9] {
   284  		assert.NoError(t, store.CommitWithPvtData(d))
   285  	}
   286  	// try to write the last block again. The function should skip adding block to the private store
   287  	// as the pvt store but the block storage should return error
   288  	assert.Error(t, store.CommitWithPvtData(sampleData[8]))
   289  
   290  	// At the end, the pvt store status should not have changed
   291  	pvtStoreCommitHt, err := store.pvtdataStore.LastCommittedBlockHeight()
   292  	assert.NoError(t, err)
   293  	assert.Equal(t, uint64(9), pvtStoreCommitHt)
   294  
   295  	// commit the rightful next block
   296  	assert.NoError(t, store.CommitWithPvtData(sampleData[9]))
   297  	pvtStoreCommitHt, err = store.pvtdataStore.LastCommittedBlockHeight()
   298  	assert.NoError(t, err)
   299  	assert.Equal(t, uint64(10), pvtStoreCommitHt)
   300  }
   301  
   302  func TestAddAfterBlkStoreError(t *testing.T) {
   303  	storeDir, err := ioutil.TempDir("", "lstore")
   304  	if err != nil {
   305  		t.Fatalf("Failed to create ledger storage directory: %s", err)
   306  	}
   307  	defer os.RemoveAll(storeDir)
   308  	conf := buildPrivateDataConfig(storeDir)
   309  	blockStoreDir := filepath.Join(storeDir, "chains")
   310  	provider, err := NewProvider(blockStoreDir, conf, metricsProvider)
   311  	assert.NoError(t, err)
   312  	defer provider.Close()
   313  	store, err := provider.Open("testLedger")
   314  	store.Init(btlPolicyForSampleData())
   315  	defer store.Shutdown()
   316  	assert.NoError(t, err)
   317  
   318  	sampleData := sampleDataWithPvtdataForAllTxs(t)
   319  	for _, d := range sampleData[0:9] {
   320  		assert.NoError(t, store.CommitWithPvtData(d))
   321  	}
   322  	lastBlkAndPvtData := sampleData[9]
   323  	// Add the block directly to blockstore
   324  	store.BlockStore.AddBlock(lastBlkAndPvtData.Block)
   325  	// Adding the same block should cause passing on the error caused by the block storgae
   326  	assert.Error(t, store.CommitWithPvtData(lastBlkAndPvtData))
   327  	// At the end, the pvt store status should be changed
   328  	pvtStoreCommitHt, err := store.pvtdataStore.LastCommittedBlockHeight()
   329  	assert.NoError(t, err)
   330  	assert.Equal(t, uint64(10), pvtStoreCommitHt)
   331  }
   332  
   333  func TestPvtStoreAheadOfBlockStore(t *testing.T) {
   334  	storeDir, err := ioutil.TempDir("", "lstore")
   335  	if err != nil {
   336  		t.Fatalf("Failed to create ledger storage directory: %s", err)
   337  	}
   338  	defer os.RemoveAll(storeDir)
   339  	conf := buildPrivateDataConfig(storeDir)
   340  	blockStoreDir := filepath.Join(storeDir, "chains")
   341  	provider, err := NewProvider(blockStoreDir, conf, metricsProvider)
   342  	assert.NoError(t, err)
   343  	defer provider.Close()
   344  	store, err := provider.Open("testLedger")
   345  	store.Init(btlPolicyForSampleData())
   346  	defer store.Shutdown()
   347  	assert.NoError(t, err)
   348  
   349  	// when both stores are empty, isPvtstoreAheadOfBlockstore should be false
   350  	assert.False(t, store.IsPvtStoreAheadOfBlockStore())
   351  
   352  	sampleData := sampleDataWithPvtdataForSelectiveTx(t)
   353  	for _, d := range sampleData[0:9] { // commit block number 0 to 8
   354  		assert.NoError(t, store.CommitWithPvtData(d))
   355  	}
   356  	assert.False(t, store.IsPvtStoreAheadOfBlockStore())
   357  
   358  	// close and reopen
   359  	store.Shutdown()
   360  	provider.Close()
   361  	provider, err = NewProvider(blockStoreDir, conf, metricsProvider)
   362  	assert.NoError(t, err)
   363  	store, err = provider.Open("testLedger")
   364  	assert.NoError(t, err)
   365  	store.Init(btlPolicyForSampleData())
   366  
   367  	// as both stores are at the same block height, isPvtstoreAheadOfBlockstore should be false
   368  	info, err := store.GetBlockchainInfo()
   369  	assert.NoError(t, err)
   370  	assert.Equal(t, uint64(9), info.Height)
   371  	pvtStoreHt, err := store.pvtdataStore.LastCommittedBlockHeight()
   372  	assert.NoError(t, err)
   373  	assert.Equal(t, uint64(9), pvtStoreHt)
   374  	assert.False(t, store.IsPvtStoreAheadOfBlockStore())
   375  
   376  	lastBlkAndPvtData := sampleData[9]
   377  	// Add the last block directly to the pvtdataStore but not to blockstore. This would make
   378  	// the pvtdatastore height greater than the block store height.
   379  	validTxPvtData, validTxMissingPvtData := constructPvtDataAndMissingData(lastBlkAndPvtData)
   380  	err = store.pvtdataStore.Commit(lastBlkAndPvtData.Block.Header.Number, validTxPvtData, validTxMissingPvtData)
   381  	assert.NoError(t, err)
   382  
   383  	// close and reopen
   384  	store.Shutdown()
   385  	provider.Close()
   386  	provider, err = NewProvider(blockStoreDir, conf, metricsProvider)
   387  	assert.NoError(t, err)
   388  	store, err = provider.Open("testLedger")
   389  	assert.NoError(t, err)
   390  	store.Init(btlPolicyForSampleData())
   391  
   392  	// pvtdataStore should be ahead of blockstore
   393  	info, err = store.GetBlockchainInfo()
   394  	assert.NoError(t, err)
   395  	assert.Equal(t, uint64(9), info.Height)
   396  	pvtStoreHt, err = store.pvtdataStore.LastCommittedBlockHeight()
   397  	assert.NoError(t, err)
   398  	assert.Equal(t, uint64(10), pvtStoreHt)
   399  	assert.True(t, store.IsPvtStoreAheadOfBlockStore())
   400  
   401  	// bring the height of BlockStore equal to pvtdataStore
   402  	assert.NoError(t, store.CommitWithPvtData(lastBlkAndPvtData))
   403  	info, err = store.GetBlockchainInfo()
   404  	assert.NoError(t, err)
   405  	assert.Equal(t, uint64(10), info.Height)
   406  	pvtStoreHt, err = store.pvtdataStore.LastCommittedBlockHeight()
   407  	assert.NoError(t, err)
   408  	assert.Equal(t, uint64(10), pvtStoreHt)
   409  	assert.False(t, store.IsPvtStoreAheadOfBlockStore())
   410  }
   411  
   412  func TestConstructPvtdataMap(t *testing.T) {
   413  	assert.Nil(t, constructPvtdataMap(nil))
   414  }
   415  
   416  func sampleDataWithPvtdataForSelectiveTx(t *testing.T) []*ledger.BlockAndPvtData {
   417  	var blockAndpvtdata []*ledger.BlockAndPvtData
   418  	blocks := testutil.ConstructTestBlocks(t, 10)
   419  	for i := 0; i < 10; i++ {
   420  		blockAndpvtdata = append(blockAndpvtdata, &ledger.BlockAndPvtData{Block: blocks[i]})
   421  	}
   422  
   423  	// txNum 3, 5, 6 in block 2 has pvtdata but txNum 6 is invalid
   424  	blockAndpvtdata[2].PvtData = samplePvtData(t, []uint64{3, 5, 6})
   425  	txFilter := lutil.TxValidationFlags(blockAndpvtdata[2].Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   426  	txFilter.SetFlag(6, pb.TxValidationCode_INVALID_WRITESET)
   427  	blockAndpvtdata[2].Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txFilter
   428  
   429  	// txNum 4, 6 in block 3 has pvtdata
   430  	blockAndpvtdata[3].PvtData = samplePvtData(t, []uint64{4, 6})
   431  
   432  	// txNum 4, 5 in block 5 has missing pvt data but txNum 5 is invalid
   433  	missingData := make(ledger.TxMissingPvtDataMap)
   434  	missingData.Add(4, "ns-4", "coll-4", true)
   435  	missingData.Add(5, "ns-5", "coll-5", true)
   436  	blockAndpvtdata[5].MissingPvtData = missingData
   437  	txFilter = lutil.TxValidationFlags(blockAndpvtdata[5].Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER])
   438  	txFilter.SetFlag(5, pb.TxValidationCode_INVALID_WRITESET)
   439  	blockAndpvtdata[5].Block.Metadata.Metadata[common.BlockMetadataIndex_TRANSACTIONS_FILTER] = txFilter
   440  
   441  	return blockAndpvtdata
   442  }
   443  
   444  func sampleDataWithPvtdataForAllTxs(t *testing.T) []*ledger.BlockAndPvtData {
   445  	var blockAndpvtdata []*ledger.BlockAndPvtData
   446  	blocks := testutil.ConstructTestBlocks(t, 10)
   447  	for i := 0; i < 10; i++ {
   448  		blockAndpvtdata = append(blockAndpvtdata,
   449  			&ledger.BlockAndPvtData{
   450  				Block:   blocks[i],
   451  				PvtData: samplePvtData(t, []uint64{uint64(i), uint64(i + 1)}),
   452  			},
   453  		)
   454  	}
   455  	return blockAndpvtdata
   456  }
   457  
   458  func samplePvtData(t *testing.T, txNums []uint64) map[uint64]*ledger.TxPvtData {
   459  	pvtWriteSet := &rwset.TxPvtReadWriteSet{DataModel: rwset.TxReadWriteSet_KV}
   460  	pvtWriteSet.NsPvtRwset = []*rwset.NsPvtReadWriteSet{
   461  		{
   462  			Namespace: "ns-1",
   463  			CollectionPvtRwset: []*rwset.CollectionPvtReadWriteSet{
   464  				{
   465  					CollectionName: "coll-1",
   466  					Rwset:          []byte("RandomBytes-PvtRWSet-ns1-coll1"),
   467  				},
   468  				{
   469  					CollectionName: "coll-2",
   470  					Rwset:          []byte("RandomBytes-PvtRWSet-ns1-coll2"),
   471  				},
   472  			},
   473  		},
   474  	}
   475  	var pvtData []*ledger.TxPvtData
   476  	for _, txNum := range txNums {
   477  		pvtData = append(pvtData, &ledger.TxPvtData{SeqInBlock: txNum, WriteSet: pvtWriteSet})
   478  	}
   479  	return constructPvtdataMap(pvtData)
   480  }
   481  
   482  func btlPolicyForSampleData() pvtdatapolicy.BTLPolicy {
   483  	return btltestutil.SampleBTLPolicy(
   484  		map[[2]string]uint64{
   485  			{"ns-1", "coll-1"}: 0,
   486  			{"ns-1", "coll-2"}: 0,
   487  		},
   488  	)
   489  }
   490  
   491  func buildPrivateDataConfig(rootFSPath string) *pvtdatastorage.PrivateDataConfig {
   492  	return &pvtdatastorage.PrivateDataConfig{
   493  		PrivateDataConfig: &ledger.PrivateDataConfig{
   494  			PurgeInterval: 1,
   495  		},
   496  		StorePath: filepath.Join(rootFSPath, "pvtdataStore"),
   497  	}
   498  }