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