github.com/true-sqn/fabric@v2.1.1+incompatible/core/ledger/kvledger/txmgmt/privacyenabledstate/db_test.go (about)

     1  /*
     2  Copyright IBM Corp. All Rights Reserved.
     3  
     4  SPDX-License-Identifier: Apache-2.0
     5  */
     6  
     7  package privacyenabledstate
     8  
     9  import (
    10  	"crypto/rand"
    11  	"encoding/hex"
    12  	"fmt"
    13  	"io"
    14  	"os"
    15  	"testing"
    16  
    17  	"github.com/hyperledger/fabric-protos-go/peer"
    18  	"github.com/hyperledger/fabric/common/ledger/testutil"
    19  	"github.com/hyperledger/fabric/core/common/ccprovider"
    20  	"github.com/hyperledger/fabric/core/ledger/cceventmgmt"
    21  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/statedb"
    22  	"github.com/hyperledger/fabric/core/ledger/kvledger/txmgmt/version"
    23  	"github.com/hyperledger/fabric/core/ledger/util"
    24  	"github.com/stretchr/testify/assert"
    25  )
    26  
    27  func TestMain(m *testing.M) {
    28  	exitCode := m.Run()
    29  	for _, testEnv := range testEnvs {
    30  		testEnv.StopExternalResource()
    31  	}
    32  	os.Exit(exitCode)
    33  }
    34  
    35  func TestBatch(t *testing.T) {
    36  	batch := UpdateMap(make(map[string]nsBatch))
    37  	v := version.NewHeight(1, 1)
    38  	for i := 0; i < 5; i++ {
    39  		for j := 0; j < 5; j++ {
    40  			for k := 0; k < 5; k++ {
    41  				batch.Put(fmt.Sprintf("ns-%d", i), fmt.Sprintf("collection-%d", j), fmt.Sprintf("key-%d", k),
    42  					[]byte(fmt.Sprintf("value-%d-%d-%d", i, j, k)), v)
    43  			}
    44  		}
    45  	}
    46  	for i := 0; i < 5; i++ {
    47  		for j := 0; j < 5; j++ {
    48  			for k := 0; k < 5; k++ {
    49  				vv := batch.Get(fmt.Sprintf("ns-%d", i), fmt.Sprintf("collection-%d", j), fmt.Sprintf("key-%d", k))
    50  				assert.NotNil(t, vv)
    51  				assert.Equal(t,
    52  					&statedb.VersionedValue{Value: []byte(fmt.Sprintf("value-%d-%d-%d", i, j, k)), Version: v},
    53  					vv)
    54  			}
    55  		}
    56  	}
    57  	assert.Nil(t, batch.Get("ns-1", "collection-1", "key-5"))
    58  	assert.Nil(t, batch.Get("ns-1", "collection-5", "key-1"))
    59  	assert.Nil(t, batch.Get("ns-5", "collection-1", "key-1"))
    60  }
    61  
    62  func TestHashBatchContains(t *testing.T) {
    63  	batch := NewHashedUpdateBatch()
    64  	batch.Put("ns1", "coll1", []byte("key1"), []byte("val1"), version.NewHeight(1, 1))
    65  	assert.True(t, batch.Contains("ns1", "coll1", []byte("key1")))
    66  	assert.False(t, batch.Contains("ns1", "coll1", []byte("key2")))
    67  	assert.False(t, batch.Contains("ns1", "coll2", []byte("key1")))
    68  	assert.False(t, batch.Contains("ns2", "coll1", []byte("key1")))
    69  
    70  	batch.Delete("ns1", "coll1", []byte("deleteKey"), version.NewHeight(1, 1))
    71  	assert.True(t, batch.Contains("ns1", "coll1", []byte("deleteKey")))
    72  	assert.False(t, batch.Contains("ns1", "coll1", []byte("deleteKey1")))
    73  	assert.False(t, batch.Contains("ns1", "coll2", []byte("deleteKey")))
    74  	assert.False(t, batch.Contains("ns2", "coll1", []byte("deleteKey")))
    75  }
    76  
    77  func TestDB(t *testing.T) {
    78  	for _, env := range testEnvs {
    79  		t.Run(env.GetName(), func(t *testing.T) {
    80  			testDB(t, env)
    81  		})
    82  	}
    83  }
    84  
    85  func testDB(t *testing.T, env TestEnv) {
    86  	env.Init(t)
    87  	defer env.Cleanup()
    88  	db := env.GetDBHandle(generateLedgerID(t))
    89  
    90  	updates := NewUpdateBatch()
    91  
    92  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
    93  	updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
    94  	updates.PubUpdates.Put("ns2", "key3", []byte("value3"), version.NewHeight(1, 3))
    95  
    96  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 4))
    97  	putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 5))
    98  	putPvtUpdates(t, updates, "ns2", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 6))
    99  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))
   100  	commonStorageDB := db.(*CommonStorageDB)
   101  	bulkOptimizable, ok := commonStorageDB.VersionedDB.(statedb.BulkOptimizable)
   102  	if ok {
   103  		bulkOptimizable.ClearCachedVersions()
   104  	}
   105  
   106  	vv, err := db.GetState("ns1", "key1")
   107  	assert.NoError(t, err)
   108  	assert.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv)
   109  
   110  	vv, err = db.GetPrivateData("ns1", "coll1", "key1")
   111  	assert.NoError(t, err)
   112  	assert.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 4)}, vv)
   113  
   114  	vv, err = db.GetPrivateDataHash("ns1", "coll1", "key1")
   115  	assert.NoError(t, err)
   116  	assert.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 4)}, vv)
   117  
   118  	vv, err = db.GetValueHash("ns1", "coll1", util.ComputeStringHash("key1"))
   119  	assert.NoError(t, err)
   120  	assert.Equal(t, &statedb.VersionedValue{Value: util.ComputeStringHash("pvt_value1"), Version: version.NewHeight(1, 4)}, vv)
   121  
   122  	committedVersion, err := db.GetKeyHashVersion("ns1", "coll1", util.ComputeStringHash("key1"))
   123  	assert.NoError(t, err)
   124  	assert.Equal(t, version.NewHeight(1, 4), committedVersion)
   125  
   126  	updates = NewUpdateBatch()
   127  	updates.PubUpdates.Delete("ns1", "key1", version.NewHeight(2, 7))
   128  	deletePvtUpdates(t, updates, "ns1", "coll1", "key1", version.NewHeight(2, 7))
   129  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 7))
   130  
   131  	vv, err = db.GetState("ns1", "key1")
   132  	assert.NoError(t, err)
   133  	assert.Nil(t, vv)
   134  
   135  	vv, err = db.GetPrivateData("ns1", "coll1", "key1")
   136  	assert.NoError(t, err)
   137  	assert.Nil(t, vv)
   138  
   139  	vv, err = db.GetValueHash("ns1", "coll1", util.ComputeStringHash("key1"))
   140  	assert.Nil(t, vv)
   141  }
   142  
   143  func TestGetStateMultipleKeys(t *testing.T) {
   144  	for _, env := range testEnvs {
   145  		t.Run(env.GetName(), func(t *testing.T) {
   146  			testGetStateMultipleKeys(t, env)
   147  		})
   148  	}
   149  }
   150  
   151  func testGetStateMultipleKeys(t *testing.T, env TestEnv) {
   152  	env.Init(t)
   153  	defer env.Cleanup()
   154  	db := env.GetDBHandle(generateLedgerID(t))
   155  
   156  	updates := NewUpdateBatch()
   157  
   158  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   159  	updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
   160  	updates.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3))
   161  
   162  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 4))
   163  	putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 5))
   164  	putPvtUpdates(t, updates, "ns1", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 6))
   165  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))
   166  
   167  	versionedVals, err := db.GetStateMultipleKeys("ns1", []string{"key1", "key3"})
   168  	assert.NoError(t, err)
   169  	assert.Equal(t,
   170  		[]*statedb.VersionedValue{
   171  			{Value: []byte("value1"), Version: version.NewHeight(1, 1)},
   172  			{Value: []byte("value3"), Version: version.NewHeight(1, 3)},
   173  		},
   174  		versionedVals)
   175  
   176  	pvtVersionedVals, err := db.GetPrivateDataMultipleKeys("ns1", "coll1", []string{"key1", "key3"})
   177  	assert.NoError(t, err)
   178  	assert.Equal(t,
   179  		[]*statedb.VersionedValue{
   180  			{Value: []byte("pvt_value1"), Version: version.NewHeight(1, 4)},
   181  			{Value: []byte("pvt_value3"), Version: version.NewHeight(1, 6)},
   182  		},
   183  		pvtVersionedVals)
   184  }
   185  
   186  func TestGetStateRangeScanIterator(t *testing.T) {
   187  	for _, env := range testEnvs {
   188  		t.Run(env.GetName(), func(t *testing.T) {
   189  			testGetStateRangeScanIterator(t, env)
   190  		})
   191  	}
   192  }
   193  
   194  func testGetStateRangeScanIterator(t *testing.T, env TestEnv) {
   195  	env.Init(t)
   196  	defer env.Cleanup()
   197  	db := env.GetDBHandle(generateLedgerID(t))
   198  
   199  	updates := NewUpdateBatch()
   200  
   201  	updates.PubUpdates.Put("ns1", "key1", []byte("value1"), version.NewHeight(1, 1))
   202  	updates.PubUpdates.Put("ns1", "key2", []byte("value2"), version.NewHeight(1, 2))
   203  	updates.PubUpdates.Put("ns1", "key3", []byte("value3"), version.NewHeight(1, 3))
   204  	updates.PubUpdates.Put("ns1", "key4", []byte("value4"), version.NewHeight(1, 4))
   205  	updates.PubUpdates.Put("ns2", "key5", []byte("value5"), version.NewHeight(1, 5))
   206  	updates.PubUpdates.Put("ns2", "key6", []byte("value6"), version.NewHeight(1, 6))
   207  	updates.PubUpdates.Put("ns3", "key7", []byte("value7"), version.NewHeight(1, 7))
   208  
   209  	putPvtUpdates(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), version.NewHeight(1, 1))
   210  	putPvtUpdates(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), version.NewHeight(1, 2))
   211  	putPvtUpdates(t, updates, "ns1", "coll1", "key3", []byte("pvt_value3"), version.NewHeight(1, 3))
   212  	putPvtUpdates(t, updates, "ns1", "coll1", "key4", []byte("pvt_value4"), version.NewHeight(1, 4))
   213  	putPvtUpdates(t, updates, "ns2", "coll1", "key5", []byte("pvt_value5"), version.NewHeight(1, 5))
   214  	putPvtUpdates(t, updates, "ns2", "coll1", "key6", []byte("pvt_value6"), version.NewHeight(1, 6))
   215  	putPvtUpdates(t, updates, "ns3", "coll1", "key7", []byte("pvt_value7"), version.NewHeight(1, 7))
   216  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 7))
   217  
   218  	itr1, _ := db.GetStateRangeScanIterator("ns1", "key1", "")
   219  	testItr(t, itr1, []string{"key1", "key2", "key3", "key4"})
   220  
   221  	itr2, _ := db.GetStateRangeScanIterator("ns1", "key2", "key3")
   222  	testItr(t, itr2, []string{"key2"})
   223  
   224  	itr3, _ := db.GetStateRangeScanIterator("ns1", "", "")
   225  	testItr(t, itr3, []string{"key1", "key2", "key3", "key4"})
   226  
   227  	itr4, _ := db.GetStateRangeScanIterator("ns2", "", "")
   228  	testItr(t, itr4, []string{"key5", "key6"})
   229  
   230  	pvtItr1, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "key1", "")
   231  	testItr(t, pvtItr1, []string{"key1", "key2", "key3", "key4"})
   232  
   233  	pvtItr2, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "key2", "key3")
   234  	testItr(t, pvtItr2, []string{"key2"})
   235  
   236  	pvtItr3, _ := db.GetPrivateDataRangeScanIterator("ns1", "coll1", "", "")
   237  	testItr(t, pvtItr3, []string{"key1", "key2", "key3", "key4"})
   238  
   239  	pvtItr4, _ := db.GetPrivateDataRangeScanIterator("ns2", "coll1", "", "")
   240  	testItr(t, pvtItr4, []string{"key5", "key6"})
   241  }
   242  
   243  func TestQueryOnCouchDB(t *testing.T) {
   244  	for _, env := range testEnvs {
   245  		_, ok := env.(*CouchDBCommonStorageTestEnv)
   246  		if !ok {
   247  			continue
   248  		}
   249  		t.Run(env.GetName(), func(t *testing.T) {
   250  			testQueryOnCouchDB(t, env)
   251  		})
   252  	}
   253  }
   254  
   255  func testQueryOnCouchDB(t *testing.T, env TestEnv) {
   256  	env.Init(t)
   257  	defer env.Cleanup()
   258  	db := env.GetDBHandle(generateLedgerID(t))
   259  	updates := NewUpdateBatch()
   260  
   261  	jsonValues := []string{
   262  		`{"asset_name": "marble1", "color": "blue", "size": 1, "owner": "tom"}`,
   263  		`{"asset_name": "marble2","color": "blue","size": 2,"owner": "jerry"}`,
   264  		`{"asset_name": "marble3","color": "blue","size": 3,"owner": "fred"}`,
   265  		`{"asset_name": "marble4","color": "blue","size": 4,"owner": "martha"}`,
   266  		`{"asset_name": "marble5","color": "blue","size": 5,"owner": "fred"}`,
   267  		`{"asset_name": "marble6","color": "blue","size": 6,"owner": "elaine"}`,
   268  		`{"asset_name": "marble7","color": "blue","size": 7,"owner": "fred"}`,
   269  		`{"asset_name": "marble8","color": "blue","size": 8,"owner": "elaine"}`,
   270  		`{"asset_name": "marble9","color": "green","size": 9,"owner": "fred"}`,
   271  		`{"asset_name": "marble10","color": "green","size": 10,"owner": "mary"}`,
   272  		`{"asset_name": "marble11","color": "cyan","size": 1000007,"owner": "joe"}`,
   273  	}
   274  
   275  	for i, jsonValue := range jsonValues {
   276  		updates.PubUpdates.Put("ns1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   277  		updates.PubUpdates.Put("ns2", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   278  		putPvtUpdates(t, updates, "ns1", "coll1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   279  		putPvtUpdates(t, updates, "ns2", "coll1", testKey(i), []byte(jsonValue), version.NewHeight(1, uint64(i)))
   280  	}
   281  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(1, 11))
   282  
   283  	// query for owner=jerry, use namespace "ns1"
   284  	itr, err := db.ExecuteQuery("ns1", `{"selector":{"owner":"jerry"}}`)
   285  	assert.NoError(t, err)
   286  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   287  
   288  	// query for owner=jerry, use namespace "ns2"
   289  	itr, err = db.ExecuteQuery("ns2", `{"selector":{"owner":"jerry"}}`)
   290  	assert.NoError(t, err)
   291  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   292  
   293  	// query for pvt data owner=jerry, use namespace "ns1"
   294  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"owner":"jerry"}}`)
   295  	assert.NoError(t, err)
   296  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   297  
   298  	// query for pvt data owner=jerry, use namespace "ns2"
   299  	itr, err = db.ExecuteQueryOnPrivateData("ns2", "coll1", `{"selector":{"owner":"jerry"}}`)
   300  	assert.NoError(t, err)
   301  	testQueryItr(t, itr, []string{testKey(1)}, []string{"jerry"})
   302  
   303  	// query using bad query string
   304  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", "this is an invalid query string")
   305  	assert.Error(t, err, "Should have received an error for invalid query string")
   306  
   307  	// query returns 0 records
   308  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"owner":"not_a_valid_name"}}`)
   309  	assert.NoError(t, err)
   310  	testQueryItr(t, itr, []string{}, []string{})
   311  
   312  	// query with embedded implicit "AND" and explicit "OR", namespace "ns1"
   313  	itr, err = db.ExecuteQueryOnPrivateData("ns1", "coll1", `{"selector":{"color":"green","$or":[{"owner":"fred"},{"owner":"mary"}]}}`)
   314  	assert.NoError(t, err)
   315  	testQueryItr(t, itr, []string{testKey(8), testKey(9)}, []string{"green"}, []string{"green"})
   316  
   317  	// query with integer with digit-count equals 7 and response received is also received
   318  	// with same digit-count and there is no float transformation
   319  	itr, err = db.ExecuteQueryOnPrivateData("ns2", "coll1", `{"selector":{"$and":[{"size":{"$eq": 1000007}}]}}`)
   320  	assert.NoError(t, err)
   321  	testQueryItr(t, itr, []string{testKey(10)}, []string{"joe", "1000007"})
   322  }
   323  
   324  func TestLongDBNameOnCouchDB(t *testing.T) {
   325  	for _, env := range testEnvs {
   326  		_, ok := env.(*CouchDBCommonStorageTestEnv)
   327  		if !ok {
   328  			continue
   329  		}
   330  		t.Run(env.GetName(), func(t *testing.T) {
   331  			testLongDBNameOnCouchDB(t, env)
   332  		})
   333  	}
   334  }
   335  
   336  func testLongDBNameOnCouchDB(t *testing.T, env TestEnv) {
   337  	env.Init(t)
   338  	defer env.Cleanup()
   339  
   340  	// Creates metadataDB (i.e., chainDB)
   341  	// Allowed pattern for chainName: [a-z][a-z0-9.-]
   342  	db := env.GetDBHandle("w1coaii9ck3l8red6a5cf3rwbe1b4wvbzcrrfl7samu7px8b9gf-4hft7wrgdmzzjj9ure4cbffucaj78nbj9ej.kvl3bus1iq1qir9xlhb8a1wipuksgs3g621elzy1prr658087exwrhp-y4j55o9cld242v--oeh3br1g7m8d6l8jobn.y42cgjt1.u1ik8qxnv4ohh9kr2w2zc8hqir5u4ev23s7jygrg....s7.ohp-5bcxari8nji")
   343  
   344  	updates := NewUpdateBatch()
   345  
   346  	// Allowed pattern for namespace and collection: [a-zA-Z0-9_-]
   347  	ns := "wMCnSXiV9YoIqNQyNvFVTdM8XnUtvrOFFIWsKelmP5NEszmNLl8YhtOKbFu3P_NgwgsYF8PsfwjYCD8f1XRpANQLoErDHwLlweryqXeJ6vzT2x0pS_GwSx0m6tBI0zOmHQOq_2De8A87x6zUOPwufC2T6dkidFxiuq8Sey2-5vUo_iNKCij3WTeCnKx78PUIg_U1gp4_0KTvYVtRBRvH0kz5usizBxPaiFu3TPhB9XLviScvdUVSbSYJ0Z"
   348  	coll := "vWjtfSTXVK8WJus5s6zWoMIciXd7qHRZIusF9SkOS6m8XuHCiJDE9cCRuVerq22Na8qBL2ywDGFpVMIuzfyEXLjeJb0mMuH4cwewT6r1INOTOSYwrikwOLlT_fl0V1L7IQEwUBB8WCvRqSdj6j5-E5aGul_pv_0UeCdwWiyA_GrZmP7ocLzfj2vP8btigrajqdH-irLO2ydEjQUAvf8fiuxru9la402KmKRy457GgI98UHoUdqV3f3FCdR"
   349  
   350  	updates.PubUpdates.Put(ns, "key1", []byte("value1"), version.NewHeight(1, 1))
   351  	updates.PvtUpdates.Put(ns, coll, "key1", []byte("pvt_value"), version.NewHeight(1, 2))
   352  	updates.HashUpdates.Put(ns, coll, util.ComputeStringHash("key1"), util.ComputeHash([]byte("pvt_value")), version.NewHeight(1, 2))
   353  
   354  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))
   355  
   356  	vv, err := db.GetState(ns, "key1")
   357  	assert.NoError(t, err)
   358  	assert.Equal(t, &statedb.VersionedValue{Value: []byte("value1"), Version: version.NewHeight(1, 1)}, vv)
   359  
   360  	vv, err = db.GetPrivateData(ns, coll, "key1")
   361  	assert.NoError(t, err)
   362  	assert.Equal(t, &statedb.VersionedValue{Value: []byte("pvt_value"), Version: version.NewHeight(1, 2)}, vv)
   363  }
   364  
   365  func testItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string) {
   366  	defer itr.Close()
   367  	for _, expectedKey := range expectedKeys {
   368  		queryResult, _ := itr.Next()
   369  		vkv := queryResult.(*statedb.VersionedKV)
   370  		key := vkv.Key
   371  		assert.Equal(t, expectedKey, key)
   372  	}
   373  	last, err := itr.Next()
   374  	assert.NoError(t, err)
   375  	assert.Nil(t, last)
   376  }
   377  
   378  func testQueryItr(t *testing.T, itr statedb.ResultsIterator, expectedKeys []string, expectedValStrs ...[]string) {
   379  	defer itr.Close()
   380  	for i, expectedKey := range expectedKeys {
   381  		queryResult, _ := itr.Next()
   382  		vkv := queryResult.(*statedb.VersionedKV)
   383  		key := vkv.Key
   384  		valStr := string(vkv.Value)
   385  		assert.Equal(t, expectedKey, key)
   386  		for _, expectedValStr := range expectedValStrs[i] {
   387  			assert.Contains(t, valStr, expectedValStr)
   388  		}
   389  	}
   390  	last, err := itr.Next()
   391  	assert.NoError(t, err)
   392  	assert.Nil(t, last)
   393  }
   394  
   395  func testKey(i int) string {
   396  	return fmt.Sprintf("key%d", i)
   397  }
   398  
   399  func TestCompositeKeyMap(t *testing.T) {
   400  	b := NewPvtUpdateBatch()
   401  	b.Put("ns1", "coll1", "key1", []byte("testVal1"), nil)
   402  	b.Delete("ns1", "coll2", "key2", nil)
   403  	b.Put("ns2", "coll1", "key1", []byte("testVal3"), nil)
   404  	b.Put("ns2", "coll2", "key2", []byte("testVal4"), nil)
   405  	m := b.ToCompositeKeyMap()
   406  	assert.Len(t, m, 4)
   407  	vv, ok := m[PvtdataCompositeKey{"ns1", "coll1", "key1"}]
   408  	assert.True(t, ok)
   409  	assert.Equal(t, []byte("testVal1"), vv.Value)
   410  	vv, ok = m[PvtdataCompositeKey{"ns1", "coll2", "key2"}]
   411  	assert.Nil(t, vv.Value)
   412  	assert.True(t, ok)
   413  	_, ok = m[PvtdataCompositeKey{"ns2", "coll1", "key1"}]
   414  	assert.True(t, ok)
   415  	_, ok = m[PvtdataCompositeKey{"ns2", "coll2", "key2"}]
   416  	assert.True(t, ok)
   417  	_, ok = m[PvtdataCompositeKey{"ns2", "coll1", "key8888"}]
   418  	assert.False(t, ok)
   419  }
   420  
   421  func TestHandleChainCodeDeployOnCouchDB(t *testing.T) {
   422  	for _, env := range testEnvs {
   423  		_, ok := env.(*CouchDBCommonStorageTestEnv)
   424  		if !ok {
   425  			continue
   426  		}
   427  		t.Run(env.GetName(), func(t *testing.T) {
   428  			testHandleChainCodeDeploy(t, env)
   429  		})
   430  	}
   431  }
   432  
   433  func createCollectionConfig(collectionName string) *peer.CollectionConfig {
   434  	return &peer.CollectionConfig{
   435  		Payload: &peer.CollectionConfig_StaticCollectionConfig{
   436  			StaticCollectionConfig: &peer.StaticCollectionConfig{
   437  				Name:              collectionName,
   438  				MemberOrgsPolicy:  nil,
   439  				RequiredPeerCount: 0,
   440  				MaximumPeerCount:  0,
   441  				BlockToLive:       0,
   442  			},
   443  		},
   444  	}
   445  }
   446  
   447  func testHandleChainCodeDeploy(t *testing.T, env TestEnv) {
   448  	env.Init(t)
   449  	defer env.Cleanup()
   450  	db := env.GetDBHandle(generateLedgerID(t))
   451  
   452  	coll1 := createCollectionConfig("collectionMarbles")
   453  	ccp := &peer.CollectionConfigPackage{Config: []*peer.CollectionConfig{coll1}}
   454  	chaincodeDef := &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: ccp}
   455  
   456  	commonStorageDB := db.(*CommonStorageDB)
   457  
   458  	// Test indexes for side databases
   459  	dbArtifactsTarBytes := testutil.CreateTarBytesForTest(
   460  		[]*testutil.TarFileEntry{
   461  			{Name: "META-INF/statedb/couchdb/indexes/indexColorSortName.json", Body: `{"index":{"fields":[{"color":"desc"}]},"ddoc":"indexColorSortName","name":"indexColorSortName","type":"json"}`},
   462  			{Name: "META-INF/statedb/couchdb/indexes/indexSizeSortName.json", Body: `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`},
   463  			{Name: "META-INF/statedb/couchdb/collections/collectionMarbles/indexes/indexCollMarbles.json", Body: `{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`},
   464  			{Name: "META-INF/statedb/couchdb/collections/collectionMarblesPrivateDetails/indexes/indexCollPrivDetails.json", Body: `{"index":{"fields":["docType","price"]},"ddoc":"indexPrivateDetails", "name":"indexPrivateDetails","type":"json"}`},
   465  		},
   466  	)
   467  
   468  	// Test the retrieveIndexArtifacts method
   469  	fileEntries, err := ccprovider.ExtractFileEntries(dbArtifactsTarBytes, "couchdb")
   470  	assert.NoError(t, err)
   471  
   472  	// There should be 3 entries
   473  	assert.Len(t, fileEntries, 3)
   474  
   475  	// There should be 2 entries for main
   476  	assert.Len(t, fileEntries["META-INF/statedb/couchdb/indexes"], 2)
   477  
   478  	// There should be 1 entry for collectionMarbles
   479  	assert.Len(t, fileEntries["META-INF/statedb/couchdb/collections/collectionMarbles/indexes"], 1)
   480  
   481  	// Verify the content of the array item
   482  	expectedJSON := []byte(`{"index":{"fields":["docType","owner"]},"ddoc":"indexCollectionMarbles", "name":"indexCollectionMarbles","type":"json"}`)
   483  	actualJSON := fileEntries["META-INF/statedb/couchdb/collections/collectionMarbles/indexes"][0].FileContent
   484  	assert.Equal(t, expectedJSON, actualJSON)
   485  
   486  	// The collection config is added to the chaincodeDef but missing collectionMarblesPrivateDetails.
   487  	// Hence, the index on collectionMarblesPrivateDetails cannot be created
   488  	err = commonStorageDB.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   489  	assert.NoError(t, err)
   490  
   491  	coll2 := createCollectionConfig("collectionMarblesPrivateDetails")
   492  	ccp = &peer.CollectionConfigPackage{Config: []*peer.CollectionConfig{coll1, coll2}}
   493  	chaincodeDef = &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: ccp}
   494  
   495  	// The collection config is added to the chaincodeDef and it contains all collections
   496  	// including collectionMarblesPrivateDetails which was missing earlier.
   497  	// Hence, the existing indexes must be updated and the new index must be created for
   498  	// collectionMarblesPrivateDetails
   499  	err = commonStorageDB.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   500  	assert.NoError(t, err)
   501  
   502  	chaincodeDef = &cceventmgmt.ChaincodeDefinition{Name: "ns1", Hash: nil, Version: "", CollectionConfigs: nil}
   503  
   504  	// The collection config is not added to the chaincodeDef. In this case, the index creation
   505  	// process reads the collection config from state db. However, the state db does not contain
   506  	// any collection config for this chaincode. Hence, index creation/update on all collections
   507  	// should fail
   508  	err = commonStorageDB.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   509  	assert.NoError(t, err)
   510  
   511  	//Test HandleChaincodeDefinition with a nil tar file
   512  	err = commonStorageDB.HandleChaincodeDeploy(chaincodeDef, nil)
   513  	assert.NoError(t, err)
   514  
   515  	//Test HandleChaincodeDefinition with a bad tar file
   516  	err = commonStorageDB.HandleChaincodeDeploy(chaincodeDef, []byte(`This is a really bad tar file`))
   517  	assert.NoError(t, err, "Error should not have been thrown for a bad tar file")
   518  
   519  	//Test HandleChaincodeDefinition with a nil chaincodeDef
   520  	err = commonStorageDB.HandleChaincodeDeploy(nil, dbArtifactsTarBytes)
   521  	assert.Error(t, err, "Error should have been thrown for a nil chaincodeDefinition")
   522  
   523  	// Create a tar file for test with 2 index definitions - one of them being errorneous
   524  	badSyntaxFileContent := `{"index":{"fields": This is a bad json}`
   525  	dbArtifactsTarBytes = testutil.CreateTarBytesForTest(
   526  		[]*testutil.TarFileEntry{
   527  			{Name: "META-INF/statedb/couchdb/indexes/indexSizeSortName.json", Body: `{"index":{"fields":[{"size":"desc"}]},"ddoc":"indexSizeSortName","name":"indexSizeSortName","type":"json"}`},
   528  			{Name: "META-INF/statedb/couchdb/indexes/badSyntax.json", Body: badSyntaxFileContent},
   529  		},
   530  	)
   531  
   532  	// Test the retrieveIndexArtifacts method
   533  	fileEntries, err = ccprovider.ExtractFileEntries(dbArtifactsTarBytes, "couchdb")
   534  	assert.NoError(t, err)
   535  
   536  	// There should be 1 entry
   537  	assert.Len(t, fileEntries, 1)
   538  
   539  	err = commonStorageDB.HandleChaincodeDeploy(chaincodeDef, dbArtifactsTarBytes)
   540  	assert.NoError(t, err)
   541  
   542  }
   543  
   544  func TestMetadataRetrieval(t *testing.T) {
   545  	for _, env := range testEnvs {
   546  		t.Run(env.GetName(), func(t *testing.T) {
   547  			testMetadataRetrieval(t, env)
   548  		})
   549  	}
   550  }
   551  
   552  func testMetadataRetrieval(t *testing.T, env TestEnv) {
   553  	env.Init(t)
   554  	defer env.Cleanup()
   555  	db := env.GetDBHandle(generateLedgerID(t))
   556  
   557  	updates := NewUpdateBatch()
   558  	updates.PubUpdates.PutValAndMetadata("ns1", "key1", []byte("value1"), []byte("metadata1"), version.NewHeight(1, 1))
   559  	updates.PubUpdates.PutValAndMetadata("ns1", "key2", []byte("value2"), nil, version.NewHeight(1, 2))
   560  	updates.PubUpdates.PutValAndMetadata("ns2", "key3", []byte("value3"), nil, version.NewHeight(1, 3))
   561  
   562  	putPvtUpdatesWithMetadata(t, updates, "ns1", "coll1", "key1", []byte("pvt_value1"), []byte("metadata1"), version.NewHeight(1, 4))
   563  	putPvtUpdatesWithMetadata(t, updates, "ns1", "coll1", "key2", []byte("pvt_value2"), nil, version.NewHeight(1, 5))
   564  	putPvtUpdatesWithMetadata(t, updates, "ns2", "coll1", "key3", []byte("pvt_value3"), nil, version.NewHeight(1, 6))
   565  	db.ApplyPrivacyAwareUpdates(updates, version.NewHeight(2, 6))
   566  
   567  	vm, _ := db.GetStateMetadata("ns1", "key1")
   568  	assert.Equal(t, vm, []byte("metadata1"))
   569  	vm, _ = db.GetStateMetadata("ns1", "key2")
   570  	assert.Nil(t, vm)
   571  	vm, _ = db.GetStateMetadata("ns2", "key3")
   572  	assert.Nil(t, vm)
   573  
   574  	vm, _ = db.GetPrivateDataMetadataByHash("ns1", "coll1", util.ComputeStringHash("key1"))
   575  	assert.Equal(t, vm, []byte("metadata1"))
   576  	vm, _ = db.GetPrivateDataMetadataByHash("ns1", "coll1", util.ComputeStringHash("key2"))
   577  	assert.Nil(t, vm)
   578  	vm, _ = db.GetPrivateDataMetadataByHash("ns2", "coll1", util.ComputeStringHash("key3"))
   579  	assert.Nil(t, vm)
   580  }
   581  
   582  func putPvtUpdates(t *testing.T, updates *UpdateBatch, ns, coll, key string, value []byte, ver *version.Height) {
   583  	updates.PvtUpdates.Put(ns, coll, key, value, ver)
   584  	updates.HashUpdates.Put(ns, coll, util.ComputeStringHash(key), util.ComputeHash(value), ver)
   585  }
   586  
   587  func putPvtUpdatesWithMetadata(t *testing.T, updates *UpdateBatch, ns, coll, key string, value []byte, metadata []byte, ver *version.Height) {
   588  	updates.PvtUpdates.Put(ns, coll, key, value, ver)
   589  	updates.HashUpdates.PutValHashAndMetadata(ns, coll, util.ComputeStringHash(key), util.ComputeHash(value), metadata, ver)
   590  }
   591  
   592  func deletePvtUpdates(t *testing.T, updates *UpdateBatch, ns, coll, key string, ver *version.Height) {
   593  	updates.PvtUpdates.Delete(ns, coll, key, ver)
   594  	updates.HashUpdates.Delete(ns, coll, util.ComputeStringHash(key), ver)
   595  }
   596  
   597  func generateLedgerID(t *testing.T) string {
   598  	bytes := make([]byte, 8)
   599  	_, err := io.ReadFull(rand.Reader, bytes)
   600  	assert.NoError(t, err)
   601  	return fmt.Sprintf("x%s", hex.EncodeToString(bytes))
   602  }