github.com/yous1230/fabric@v2.0.0-beta.0.20191224111736-74345bee6ac2+incompatible/core/chaincode/executetransaction_pvtdata_test.go (about) 1 /* 2 Copyright IBM Corp. All Rights Reserved. 3 4 SPDX-License-Identifier: Apache-2.0 5 */ 6 7 package chaincode 8 9 import ( 10 "encoding/json" 11 "fmt" 12 "testing" 13 "time" 14 15 pb "github.com/hyperledger/fabric-protos-go/peer" 16 "github.com/hyperledger/fabric/common/util" 17 "github.com/hyperledger/fabric/core/peer" 18 "github.com/spf13/viper" 19 "github.com/stretchr/testify/assert" 20 ) 21 22 // Test the invocation of a transaction for private data. 23 func TestQueriesPrivateData(t *testing.T) { 24 // Skipping this tests as this test requires the application configuration to be set such that the private data capability is set to 'true' 25 // However, with the latest restructuring of some of the packages, it is not possible to register system chaincodes with desired configurations for test. 26 // see function RegisterSysCCs in file 'fabric/core/scc/register.go'. In absence of this lscc returns error while deploying a chaincode with collection configurations. 27 // This test should be moved as an integration test outside of chaincode package. 28 t.Skip() 29 channelID := "testchannelid" 30 _, _, chaincodeSupport, cleanup, err := initPeer(channelID) 31 if err != nil { 32 t.Fail() 33 t.Logf("Error creating peer: %s", err) 34 } 35 36 defer cleanup() 37 38 peer.CreateMockChannel(chaincodeSupport.Peer, channelID, nil) 39 40 url := "github.com/hyperledger/fabric/core/chaincode/testdata/src/chaincodes/map" 41 cID := &pb.ChaincodeID{Name: "tmap", Path: url, Version: "0"} 42 43 f := "init" 44 args := util.ToChaincodeArgs(f) 45 46 spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 47 48 ccContext := &CCContext{ 49 Name: "tmap", 50 Version: "0", 51 } 52 53 var nextBlockNumber uint64 = 1 54 // this test assumes four collections 55 collectionConfig := []*pb.StaticCollectionConfig{{Name: "c1"}, {Name: "c2"}, {Name: "c3"}, {Name: "c4"}} 56 collectionConfigPkg := constructCollectionConfigPkg(collectionConfig) 57 defer chaincodeSupport.Runtime.Stop(cID.Name + ":" + cID.Version) 58 _, err = deployWithCollectionConfigs(channelID, ccContext, spec, collectionConfigPkg, nextBlockNumber, chaincodeSupport) 59 nextBlockNumber++ 60 ccID := spec.ChaincodeId.Name 61 if err != nil { 62 t.Fail() 63 t.Logf("Error initializing chaincode %s(%s)", ccID, err) 64 return 65 } 66 67 // Add 101 marbles for testing range queries and rich queries (for capable ledgers) 68 // on both public and private data. The tests will test both range and rich queries 69 // and queries with query limits 70 for i := 1; i <= 101; i++ { 71 f = "put" 72 73 // 51 owned by tom, 50 by jerry 74 owner := "tom" 75 if i%2 == 0 { 76 owner = "jerry" 77 } 78 79 // one marble color is red, 100 are blue 80 color := "blue" 81 if i == 12 { 82 color = "red" 83 } 84 85 key := fmt.Sprintf("marble%03d", i) 86 argsString := fmt.Sprintf("{\"docType\":\"marble\",\"name\":\"%s\",\"color\":\"%s\",\"size\":35,\"owner\":\"%s\"}", key, color, owner) 87 args = util.ToChaincodeArgs(f, key, argsString) 88 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 89 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 90 nextBlockNumber++ 91 92 if err != nil { 93 t.Fail() 94 t.Logf("Error invoking <%s>: %s", ccID, err) 95 return 96 } 97 98 f = "putPrivate" 99 100 key = fmt.Sprintf("pmarble%03d", i) 101 args = util.ToChaincodeArgs(f, "c1", key, argsString) 102 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 103 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 104 nextBlockNumber++ 105 106 if err != nil { 107 t.Fail() 108 t.Logf("Error invoking <%s>: %s", ccID, err) 109 return 110 } 111 112 } 113 114 // Insert a marble in 3 private collections 115 for i := 2; i <= 4; i++ { 116 collection := fmt.Sprintf("c%d", i) 117 value := fmt.Sprintf("value_c%d", i) 118 119 f = "putPrivate" 120 t.Logf("invoking PutPrivateData with collection:<%s> key:%s", collection, "marble001") 121 args = util.ToChaincodeArgs(f, collection, "pmarble001", value) 122 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 123 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 124 nextBlockNumber++ 125 126 if err != nil { 127 t.Fail() 128 t.Logf("Error invoking <%s>: %s", ccID, err) 129 return 130 } 131 } 132 133 // read a marble from collection c3 134 f = "getPrivate" 135 args = util.ToChaincodeArgs(f, "c3", "pmarble001") 136 137 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 138 _, _, retval, err := invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 139 nextBlockNumber++ 140 141 if err != nil { 142 t.Fail() 143 t.Logf("Error invoking <%s>: %s", ccID, err) 144 return 145 } 146 147 var val string 148 err = json.Unmarshal(retval, &val) 149 assert.NoError(t, err) 150 expectedValue := fmt.Sprintf("value_c%d", 3) 151 if val != expectedValue { 152 t.Fail() 153 t.Logf("Error detected with the GetPrivateData: expected '%s' but got '%s'", expectedValue, val) 154 return 155 } 156 157 // delete a marble from collection c3 158 f = "removePrivate" 159 args = util.ToChaincodeArgs(f, "c3", "pmarble001") 160 161 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 162 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 163 nextBlockNumber++ 164 165 if err != nil { 166 t.Fail() 167 t.Logf("Error invoking <%s>: %s", ccID, err) 168 return 169 } 170 171 // delete a marble from collection c4 172 f = "removePrivate" 173 args = util.ToChaincodeArgs(f, "c4", "pmarble001") 174 175 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 176 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 177 nextBlockNumber++ 178 179 if err != nil { 180 t.Fail() 181 t.Logf("Error invoking <%s>: %s", ccID, err) 182 return 183 } 184 185 // read deleted marble from collection c3 to verify whether delete executed correctly 186 f = "getPrivate" 187 args = util.ToChaincodeArgs(f, "c3", "pmarble001") 188 189 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 190 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 191 nextBlockNumber++ 192 193 if err != nil { 194 t.Fail() 195 t.Logf("Error invoking <%s>: %s", ccID, err) 196 return 197 } 198 199 err = json.Unmarshal(retval, &val) 200 assert.NoError(t, err) 201 if val != "" { 202 t.Fail() 203 t.Logf("Error detected with the GetPrivateData") 204 return 205 } 206 207 // try to read the marble inserted in collection c2 from public state to check 208 // whether it returns the marble (for correct operation, it should not return) 209 f = "get" 210 args = util.ToChaincodeArgs(f, "pmarble001") 211 212 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 213 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 214 nextBlockNumber++ 215 216 if err != nil { 217 t.Fail() 218 t.Logf("Error invoking <%s>: %s", ccID, err) 219 return 220 } 221 222 err = json.Unmarshal(retval, &val) 223 assert.NoError(t, err) 224 if val != "" { 225 t.Fail() 226 t.Logf("Error detected with the GetState: %s", val) 227 return 228 } 229 //The following range query for "marble001" to "marble011" should return 10 marbles 230 f = "keysPrivate" 231 args = util.ToChaincodeArgs(f, "c1", "pmarble001", "pmarble011") 232 233 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 234 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 235 nextBlockNumber++ 236 if err != nil { 237 t.Fail() 238 t.Logf("Error invoking <%s>: %s", ccID, err) 239 return 240 } 241 var keys []interface{} 242 err = json.Unmarshal(retval, &keys) 243 assert.NoError(t, err) 244 if len(keys) != 10 { 245 t.Fail() 246 t.Logf("Error detected with the range query, should have returned 10 but returned %v", len(keys)) 247 return 248 } 249 250 //The following range query for "marble001" to "marble011" should return 10 marbles 251 f = "keys" 252 args = util.ToChaincodeArgs(f, "marble001", "marble011") 253 254 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 255 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 256 nextBlockNumber++ 257 if err != nil { 258 t.Fail() 259 t.Logf("Error invoking <%s>: %s", ccID, err) 260 return 261 } 262 263 err = json.Unmarshal(retval, &keys) 264 assert.NoError(t, err) 265 if len(keys) != 10 { 266 t.Fail() 267 t.Logf("Error detected with the range query, should have returned 10 but returned %v", len(keys)) 268 return 269 } 270 271 //FAB-1163- The following range query should timeout and produce an error 272 //the peer should handle this gracefully and not die 273 274 //save the original timeout and set a new timeout of 1 sec 275 origTimeout := chaincodeSupport.ExecuteTimeout 276 chaincodeSupport.ExecuteTimeout = time.Duration(1) * time.Second 277 278 //chaincode to sleep for 2 secs with timeout 1 279 args = util.ToChaincodeArgs(f, "marble001", "marble002", "2000") 280 281 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 282 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 283 if err == nil { 284 t.Fail() 285 t.Logf("expected timeout error but succeeded") 286 return 287 } 288 289 //restore timeout 290 chaincodeSupport.ExecuteTimeout = origTimeout 291 292 // querying for all marbles will return 101 marbles 293 // this query should return exactly 101 results (one call to Next()) 294 //The following range query for "marble001" to "marble102" should return 101 marbles 295 f = "keys" 296 args = util.ToChaincodeArgs(f, "marble001", "marble102") 297 298 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 299 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 300 nextBlockNumber++ 301 if err != nil { 302 t.Fail() 303 t.Logf("Error invoking <%s>: %s", ccID, err) 304 return 305 } 306 307 //unmarshal the results 308 err = json.Unmarshal(retval, &keys) 309 assert.NoError(t, err) 310 311 //check to see if there are 101 values 312 //default query limit of 10000 is used, this query is effectively unlimited 313 if len(keys) != 101 { 314 t.Fail() 315 t.Logf("Error detected with the range query, should have returned 101 but returned %v", len(keys)) 316 return 317 } 318 319 // querying for all simple key. This query should return exactly 101 simple keys (one 320 // call to Next()) no composite keys. 321 //The following open ended range query for "" to "" should return 101 marbles 322 f = "keys" 323 args = util.ToChaincodeArgs(f, "", "") 324 325 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 326 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 327 nextBlockNumber++ 328 if err != nil { 329 t.Fail() 330 t.Logf("Error invoking <%s>: %s", ccID, err) 331 return 332 } 333 334 //unmarshal the results 335 err = json.Unmarshal(retval, &keys) 336 assert.NoError(t, err) 337 338 //check to see if there are 101 values 339 //default query limit of 10000 is used, this query is effectively unlimited 340 if len(keys) != 101 { 341 t.Fail() 342 t.Logf("Error detected with the range query, should have returned 101 but returned %v", len(keys)) 343 return 344 } 345 346 // ExecuteQuery supported only for CouchDB and 347 // query limits apply for CouchDB range and rich queries only 348 // corner cases for shim batching. currnt shim batch size is 100 349 // this query should return exactly 100 results (no call to Next()) 350 f = "query" 351 args = util.ToChaincodeArgs(f, "{\"selector\":{\"color\":\"blue\"}}") 352 353 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 354 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 355 nextBlockNumber++ 356 357 if err != nil { 358 t.Fail() 359 t.Logf("Error invoking <%s>: %s", ccID, err) 360 return 361 } 362 363 //unmarshal the results 364 err = json.Unmarshal(retval, &keys) 365 assert.NoError(t, err) 366 367 //check to see if there are 100 values 368 if len(keys) != 100 { 369 t.Fail() 370 t.Logf("Error detected with the rich query, should have returned 100 but returned %v %s", len(keys), keys) 371 return 372 } 373 f = "queryPrivate" 374 args = util.ToChaincodeArgs(f, "c1", "{\"selector\":{\"color\":\"blue\"}}") 375 376 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 377 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 378 nextBlockNumber++ 379 if err != nil { 380 t.Fail() 381 t.Logf("Error invoking <%s>: %s", ccID, err) 382 return 383 } 384 385 //unmarshal the results 386 err = json.Unmarshal(retval, &keys) 387 assert.NoError(t, err) 388 389 //check to see if there are 100 values 390 if len(keys) != 100 { 391 t.Fail() 392 t.Logf("Error detected with the rich query, should have returned 100 but returned %v %s", len(keys), keys) 393 return 394 } 395 //Reset the query limit to 5 396 viper.Set("ledger.state.queryLimit", 5) 397 398 //The following range query for "marble01" to "marble11" should return 5 marbles due to the queryLimit 399 f = "keys" 400 args = util.ToChaincodeArgs(f, "marble001", "marble011") 401 402 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 403 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 404 nextBlockNumber++ 405 if err != nil { 406 t.Fail() 407 t.Logf("Error invoking <%s>: %s", ccID, err) 408 return 409 } 410 411 //unmarshal the results 412 err = json.Unmarshal(retval, &keys) 413 assert.NoError(t, err) 414 //check to see if there are 5 values 415 if len(keys) != 5 { 416 t.Fail() 417 t.Logf("Error detected with the range query, should have returned 5 but returned %v", len(keys)) 418 return 419 } 420 421 //Reset the query limit to 10000 422 viper.Set("ledger.state.queryLimit", 10000) 423 424 //The following rich query for should return 50 marbles 425 f = "query" 426 args = util.ToChaincodeArgs(f, "{\"selector\":{\"owner\":\"jerry\"}}") 427 428 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 429 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 430 nextBlockNumber++ 431 432 if err != nil { 433 t.Fail() 434 t.Logf("Error invoking <%s>: %s", ccID, err) 435 return 436 } 437 438 //unmarshal the results 439 err = json.Unmarshal(retval, &keys) 440 assert.NoError(t, err) 441 442 //check to see if there are 50 values 443 //default query limit of 10000 is used, this query is effectively unlimited 444 if len(keys) != 50 { 445 t.Fail() 446 t.Logf("Error detected with the rich query, should have returned 50 but returned %v", len(keys)) 447 return 448 } 449 450 //Reset the query limit to 5 451 viper.Set("ledger.state.queryLimit", 5) 452 453 //The following rich query should return 5 marbles due to the queryLimit 454 f = "query" 455 args = util.ToChaincodeArgs(f, "{\"selector\":{\"owner\":\"jerry\"}}") 456 457 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 458 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 459 nextBlockNumber++ 460 if err != nil { 461 t.Fail() 462 t.Logf("Error invoking <%s>: %s", ccID, err) 463 return 464 } 465 466 //unmarshal the results 467 err = json.Unmarshal(retval, &keys) 468 assert.NoError(t, err) 469 470 //check to see if there are 5 values 471 if len(keys) != 5 { 472 t.Fail() 473 t.Logf("Error detected with the rich query, should have returned 5 but returned %v", len(keys)) 474 return 475 } 476 477 // modifications for history query 478 f = "put" 479 args = util.ToChaincodeArgs(f, "marble012", "{\"docType\":\"marble\",\"name\":\"marble012\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}") 480 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 481 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 482 nextBlockNumber++ 483 if err != nil { 484 t.Fail() 485 t.Logf("Error invoking <%s>: %s", ccID, err) 486 return 487 } 488 489 f = "put" 490 args = util.ToChaincodeArgs(f, "marble012", "{\"docType\":\"marble\",\"name\":\"marble012\",\"color\":\"red\",\"size\":30,\"owner\":\"jerry\"}") 491 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 492 _, _, _, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 493 nextBlockNumber++ 494 if err != nil { 495 t.Fail() 496 t.Logf("Error invoking <%s>: %s", ccID, err) 497 return 498 } 499 500 //The following history query for "marble12" should return 3 records 501 f = "history" 502 args = util.ToChaincodeArgs(f, "marble012") 503 spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} 504 _, _, retval, err = invoke(channelID, spec, nextBlockNumber, nil, chaincodeSupport) 505 nextBlockNumber++ 506 if err != nil { 507 t.Fail() 508 t.Logf("Error invoking <%s>: %s", ccID, err) 509 return 510 } 511 512 var history []interface{} 513 err = json.Unmarshal(retval, &history) 514 assert.NoError(t, err) 515 if len(history) != 3 { 516 t.Fail() 517 t.Logf("Error detected with the history query, should have returned 3 but returned %v", len(history)) 518 return 519 } 520 } 521 522 func constructCollectionConfigPkg(staticCollectionConfigs []*pb.StaticCollectionConfig) *pb.CollectionConfigPackage { 523 var cc []*pb.CollectionConfig 524 for _, sc := range staticCollectionConfigs { 525 cc = append(cc, &pb.CollectionConfig{ 526 Payload: &pb.CollectionConfig_StaticCollectionConfig{ 527 StaticCollectionConfig: sc}}) 528 } 529 return &pb.CollectionConfigPackage{Config: cc} 530 }