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