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 }