github.com/vijaypunugubati/fabric@v2.0.0-alpha.0.20200109185758-70466159f5b3+incompatible/core/chaincode/chaincode_support_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 "archive/tar" 11 "bytes" 12 "compress/gzip" 13 "errors" 14 "fmt" 15 "io/ioutil" 16 "os" 17 "path/filepath" 18 "testing" 19 "time" 20 21 "github.com/hyperledger/fabric/bccsp/sw" 22 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 23 "github.com/hyperledger/fabric/core/ledger/ledgermgmt/ledgermgmttest" 24 25 docker "github.com/fsouza/go-dockerclient" 26 "github.com/golang/protobuf/proto" 27 "github.com/hyperledger/fabric-chaincode-go/shim" 28 plgr "github.com/hyperledger/fabric-protos-go/ledger/queryresult" 29 pb "github.com/hyperledger/fabric-protos-go/peer" 30 "github.com/hyperledger/fabric/common/crypto/tlsgen" 31 commonledger "github.com/hyperledger/fabric/common/ledger" 32 "github.com/hyperledger/fabric/common/metrics/disabled" 33 "github.com/hyperledger/fabric/common/util" 34 "github.com/hyperledger/fabric/core/aclmgmt/resources" 35 "github.com/hyperledger/fabric/core/chaincode/accesscontrol" 36 "github.com/hyperledger/fabric/core/chaincode/lifecycle" 37 "github.com/hyperledger/fabric/core/chaincode/mock" 38 "github.com/hyperledger/fabric/core/chaincode/persistence" 39 "github.com/hyperledger/fabric/core/chaincode/platforms" 40 "github.com/hyperledger/fabric/core/chaincode/platforms/golang" 41 "github.com/hyperledger/fabric/core/common/ccprovider" 42 "github.com/hyperledger/fabric/core/config" 43 "github.com/hyperledger/fabric/core/container" 44 "github.com/hyperledger/fabric/core/container/ccintf" 45 "github.com/hyperledger/fabric/core/container/dockercontroller" 46 "github.com/hyperledger/fabric/core/ledger" 47 ledgermock "github.com/hyperledger/fabric/core/ledger/mock" 48 "github.com/hyperledger/fabric/core/peer" 49 "github.com/hyperledger/fabric/core/scc" 50 "github.com/hyperledger/fabric/core/scc/lscc" 51 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 52 "github.com/hyperledger/fabric/protoutil" 53 "github.com/stretchr/testify/assert" 54 ) 55 56 // CCContext is a legacy structure that was utilized heavily in the tests 57 // so it has been preserved, even though it basically passes a name/version pair 58 // alone. 59 type CCContext struct { 60 Name string 61 Version string 62 } 63 64 var globalBlockNum map[string]uint64 65 66 type mockResultsIterator struct { 67 current int 68 kvs []*plgr.KV 69 } 70 71 func (mri *mockResultsIterator) Next() (commonledger.QueryResult, error) { 72 if mri.current == len(mri.kvs) { 73 return nil, nil 74 } 75 kv := mri.kvs[mri.current] 76 mri.current = mri.current + 1 77 78 return kv, nil 79 } 80 81 func (mri *mockResultsIterator) Close() { 82 mri.current = len(mri.kvs) 83 } 84 85 type mockExecQuerySimulator struct { 86 txsim ledger.TxSimulator 87 resultsIter map[string]map[string]*mockResultsIterator 88 } 89 90 func (meqe *mockExecQuerySimulator) GetHistoryForKey(namespace, query string) (commonledger.ResultsIterator, error) { 91 return meqe.commonQuery(namespace, query) 92 } 93 94 func (meqe *mockExecQuerySimulator) ExecuteQuery(namespace, query string) (commonledger.ResultsIterator, error) { 95 return meqe.commonQuery(namespace, query) 96 } 97 98 func (meqe *mockExecQuerySimulator) commonQuery(namespace, query string) (commonledger.ResultsIterator, error) { 99 if meqe.resultsIter == nil { 100 return nil, fmt.Errorf("query executor not initialized") 101 } 102 nsiter := meqe.resultsIter[namespace] 103 if nsiter == nil { 104 return nil, fmt.Errorf("namespace %v not found for %s", namespace, query) 105 } 106 iter := nsiter[query] 107 if iter == nil { 108 fmt.Printf("iter not found for query %s\n", query) 109 } 110 return iter, nil 111 } 112 113 func (meqe *mockExecQuerySimulator) SetState(namespace string, key string, value []byte) error { 114 if meqe.txsim == nil { 115 return fmt.Errorf("SetState txsimulator not initialed") 116 } 117 return meqe.txsim.SetState(namespace, key, value) 118 } 119 120 func (meqe *mockExecQuerySimulator) DeleteState(namespace string, key string) error { 121 if meqe.txsim == nil { 122 return fmt.Errorf("SetState txsimulator not initialed") 123 } 124 return meqe.txsim.DeleteState(namespace, key) 125 } 126 127 func (meqe *mockExecQuerySimulator) SetStateMultipleKeys(namespace string, kvs map[string][]byte) error { 128 if meqe.txsim == nil { 129 return fmt.Errorf("SetState txsimulator not initialed") 130 } 131 return meqe.txsim.SetStateMultipleKeys(namespace, kvs) 132 } 133 134 func (meqe *mockExecQuerySimulator) ExecuteUpdate(query string) error { 135 if meqe.txsim == nil { 136 return fmt.Errorf("SetState txsimulator not initialed") 137 } 138 return meqe.txsim.ExecuteUpdate(query) 139 } 140 141 func (meqe *mockExecQuerySimulator) GetTxSimulationResults() ([]byte, error) { 142 if meqe.txsim == nil { 143 return nil, fmt.Errorf("SetState txsimulator not initialed") 144 } 145 simRes, err := meqe.txsim.GetTxSimulationResults() 146 if err != nil { 147 return nil, err 148 } 149 return simRes.GetPubSimulationBytes() 150 } 151 152 //initialize peer and start up. If security==enabled, login as vp 153 func initMockPeer(channelIDs ...string) (*peer.Peer, *ChaincodeSupport, func(), error) { 154 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 155 if err != nil { 156 panic(fmt.Sprintf("failed to create cryptoProvider: %s", err)) 157 } 158 159 peerInstance := &peer.Peer{CryptoProvider: cryptoProvider} 160 161 tempdir, err := ioutil.TempDir("", "cc-support-test") 162 if err != nil { 163 panic(fmt.Sprintf("failed to create temporary directory: %s", err)) 164 } 165 166 initializer := ledgermgmttest.NewInitializer(filepath.Join(tempdir, "ledgerData")) 167 peerInstance.LedgerMgr = ledgermgmt.NewLedgerMgr(initializer) 168 169 cleanup := func() { 170 peerInstance.LedgerMgr.Close() 171 os.RemoveAll(tempdir) 172 } 173 174 mockAclProvider := &mock.ACLProvider{} 175 ccprovider.SetChaincodesPath(tempdir) 176 ca, _ := tlsgen.NewCA() 177 certGenerator := accesscontrol.NewAuthenticator(ca) 178 globalConfig := GlobalConfig() 179 globalConfig.ExecuteTimeout = 1 * time.Second 180 globalConfig.InstallTimeout = 90 * time.Second 181 globalConfig.StartupTimeout = 10 * time.Second 182 183 buildRegistry := &container.BuildRegistry{} 184 185 client, err := docker.NewClientFromEnv() 186 if err != nil { 187 panic(err) 188 } 189 190 containerRouter := &container.Router{ 191 DockerBuilder: &dockercontroller.DockerVM{ 192 PlatformBuilder: &platforms.Builder{ 193 Registry: platforms.NewRegistry(&golang.Platform{}), 194 Client: client, 195 }, 196 }, 197 PackageProvider: &persistence.FallbackPackageLocator{ 198 ChaincodePackageLocator: &persistence.ChaincodePackageLocator{}, 199 LegacyCCPackageLocator: &ccprovider.CCInfoFSImpl{GetHasher: cryptoProvider}, 200 }, 201 } 202 203 lsccImpl := &lscc.SCC{ 204 BuiltinSCCs: map[string]struct{}{"lscc": {}}, 205 Support: &lscc.SupportImpl{ 206 GetMSPIDs: peerInstance.GetMSPIDs, 207 }, 208 SCCProvider: &lscc.PeerShim{Peer: peerInstance}, 209 ACLProvider: mockAclProvider, 210 GetMSPIDs: peerInstance.GetMSPIDs, 211 PolicyChecker: newPolicyChecker(peerInstance), 212 BCCSP: cryptoProvider, 213 BuildRegistry: buildRegistry, 214 ChaincodeBuilder: containerRouter, 215 } 216 217 ml := &mock.Lifecycle{} 218 ml.ChaincodeEndorsementInfoStub = func(_, name string, _ ledger.SimpleQueryExecutor) (*lifecycle.ChaincodeEndorsementInfo, error) { 219 switch name { 220 case "shimTestCC", "calledCC": 221 return &lifecycle.ChaincodeEndorsementInfo{ 222 ChaincodeID: name + ":0", 223 }, nil 224 case "lscc": 225 return &lifecycle.ChaincodeEndorsementInfo{ 226 ChaincodeID: "lscc.syscc", 227 }, nil 228 default: 229 return nil, errors.New("oh-bother-no-chaincode-info") 230 } 231 } 232 233 containerRuntime := &ContainerRuntime{ 234 BuildRegistry: buildRegistry, 235 ContainerRouter: containerRouter, 236 } 237 userRunsCC := true 238 metricsProviders := &disabled.Provider{} 239 chaincodeHandlerRegistry := NewHandlerRegistry(userRunsCC) 240 chaincodeLauncher := &RuntimeLauncher{ 241 Metrics: NewLaunchMetrics(metricsProviders), 242 Runtime: containerRuntime, 243 Registry: chaincodeHandlerRegistry, 244 StartupTimeout: globalConfig.StartupTimeout, 245 CACert: ca.CertBytes(), 246 CertGenerator: certGenerator, 247 } 248 if !globalConfig.TLSEnabled { 249 chaincodeLauncher.CertGenerator = nil 250 } 251 chaincodeSupport := &ChaincodeSupport{ 252 ACLProvider: mockAclProvider, 253 AppConfig: peerInstance, 254 DeployedCCInfoProvider: &ledgermock.DeployedChaincodeInfoProvider{}, 255 ExecuteTimeout: globalConfig.ExecuteTimeout, 256 InstallTimeout: globalConfig.InstallTimeout, 257 HandlerMetrics: NewHandlerMetrics(metricsProviders), 258 HandlerRegistry: chaincodeHandlerRegistry, 259 Keepalive: globalConfig.Keepalive, 260 Launcher: chaincodeLauncher, 261 Lifecycle: ml, 262 Peer: peerInstance, 263 Runtime: containerRuntime, 264 BuiltinSCCs: map[string]struct{}{"lscc": {}}, 265 TotalQueryLimit: globalConfig.TotalQueryLimit, 266 UserRunsCC: userRunsCC, 267 } 268 269 scc.DeploySysCC(lsccImpl, chaincodeSupport) 270 271 globalBlockNum = make(map[string]uint64, len(channelIDs)) 272 for _, id := range channelIDs { 273 capabilities := &mock.ApplicationCapabilities{} 274 config := &mock.ApplicationConfig{} 275 config.CapabilitiesReturns(capabilities) 276 resources := &mock.Resources{} 277 resources.ApplicationConfigReturns(config, true) 278 if err := peer.CreateMockChannel(peerInstance, id, resources); err != nil { 279 cleanup() 280 return nil, nil, func() {}, err 281 } 282 283 // any channel other than the default testchannelid does not have a MSP set up -> create one 284 if id != "testchannelid" { 285 mspmgmt.XXXSetMSPManager(id, mspmgmt.GetManagerForChain("testchannelid")) 286 } 287 globalBlockNum[id] = 1 288 } 289 290 return peerInstance, chaincodeSupport, cleanup, nil 291 } 292 293 func finitMockPeer(peerInstance *peer.Peer, channelIDs ...string) { 294 for _, c := range channelIDs { 295 if lgr := peerInstance.GetLedger(c); lgr != nil { 296 lgr.Close() 297 } 298 } 299 ledgerPath := config.GetPath("peer.fileSystemPath") 300 os.RemoveAll(ledgerPath) 301 os.RemoveAll(filepath.Join(os.TempDir(), "hyperledger")) 302 } 303 304 //store the stream CC mappings here 305 var mockPeerCCSupport = mock.NewMockPeerSupport() 306 307 func setupcc(name string) (*mock.MockCCComm, *mock.MockCCComm) { 308 send := make(chan *pb.ChaincodeMessage) 309 recv := make(chan *pb.ChaincodeMessage) 310 peerSide, _ := mockPeerCCSupport.AddCC(name, recv, send) 311 peerSide.SetName("peer") 312 ccSide := mockPeerCCSupport.GetCCMirror(name) 313 ccSide.SetPong(true) 314 return peerSide, ccSide 315 } 316 317 //assign this to done and failNow and keep using them 318 func setuperror() chan error { 319 return make(chan error) 320 } 321 322 func processDone(t *testing.T, done chan error, expecterr bool) { 323 var err error 324 if done != nil { 325 err = <-done 326 } 327 if expecterr != (err != nil) { 328 if err == nil { 329 t.Fatalf("Expected error but got success") 330 } else { 331 t.Fatalf("Expected success but got error %s", err) 332 } 333 } 334 } 335 336 func startTx(t *testing.T, peerInstance *peer.Peer, channelID string, cis *pb.ChaincodeInvocationSpec, txId string) (*ccprovider.TransactionParams, ledger.TxSimulator) { 337 creator := []byte([]byte("Alice")) 338 sprop, prop := protoutil.MockSignedEndorserProposalOrPanic(channelID, cis.ChaincodeSpec, creator, []byte("msg1")) 339 txsim, hqe, err := startTxSimulation(peerInstance, channelID, txId) 340 if err != nil { 341 t.Fatalf("getting txsimulator failed %s", err) 342 } 343 344 txParams := &ccprovider.TransactionParams{ 345 ChannelID: channelID, 346 TxID: txId, 347 Proposal: prop, 348 SignedProp: sprop, 349 TXSimulator: txsim, 350 HistoryQueryExecutor: hqe, 351 } 352 353 return txParams, txsim 354 } 355 356 func endTx(t *testing.T, peerInstance *peer.Peer, txParams *ccprovider.TransactionParams, txsim ledger.TxSimulator, cis *pb.ChaincodeInvocationSpec) { 357 if err := endTxSimulationCIS(peerInstance, txParams.ChannelID, cis.ChaincodeSpec.ChaincodeId, txParams.TxID, txsim, []byte("invoke"), true, cis, globalBlockNum[txParams.ChannelID]); err != nil { 358 t.Fatalf("simulation failed with error %s", err) 359 } 360 globalBlockNum[txParams.ChannelID] = globalBlockNum[txParams.ChannelID] + 1 361 } 362 363 func execCC(t *testing.T, txParams *ccprovider.TransactionParams, ccSide *mock.MockCCComm, chaincodeName string, waitForERROR bool, expectExecErr bool, done chan error, cis *pb.ChaincodeInvocationSpec, respSet *mock.MockResponseSet, chaincodeSupport *ChaincodeSupport) error { 364 ccSide.SetResponses(respSet) 365 366 resp, _, err := chaincodeSupport.Execute(txParams, chaincodeName, cis.ChaincodeSpec.Input) 367 if err == nil && resp.Status != shim.OK { 368 err = errors.New(resp.Message) 369 } 370 371 if err == nil && expectExecErr { 372 t.Fatalf("expected error but succeeded") 373 } else if err != nil && !expectExecErr { 374 t.Fatalf("exec failed with %s", err) 375 } 376 377 //wait 378 processDone(t, done, waitForERROR) 379 380 return nil 381 } 382 383 //initialize cc support env and startup the chaincode 384 func startCC(t *testing.T, channelID string, ccname string, chaincodeSupport *ChaincodeSupport) (*mock.MockCCComm, *mock.MockCCComm) { 385 peerSide, ccSide := setupcc(ccname) 386 defer mockPeerCCSupport.RemoveCC(ccname) 387 388 //register peer side with ccsupport 389 go func() { 390 chaincodeSupport.HandleChaincodeStream(peerSide) 391 }() 392 393 done := setuperror() 394 395 errorFunc := func(ind int, err error) { 396 done <- err 397 } 398 399 ccDone := make(chan struct{}) 400 defer close(ccDone) 401 402 //start the mock peer 403 go func() { 404 respSet := &mock.MockResponseSet{ 405 DoneFunc: errorFunc, 406 ErrorFunc: nil, 407 Responses: []*mock.MockResponse{ 408 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTERED}, RespMsg: nil}, 409 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_READY}, RespMsg: nil}, 410 }, 411 } 412 ccSide.SetResponses(respSet) 413 ccSide.Run(ccDone) 414 }() 415 416 ccSide.Send(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeID{Name: ccname + ":0"}), Txid: "0", ChannelId: channelID}) 417 418 //wait for init 419 processDone(t, done, false) 420 421 return peerSide, ccSide 422 } 423 424 func getTarGZ(t *testing.T, name string, contents []byte) []byte { 425 startTime := time.Now() 426 inputbuf := bytes.NewBuffer(nil) 427 gw := gzip.NewWriter(inputbuf) 428 tr := tar.NewWriter(gw) 429 size := int64(len(contents)) 430 431 tr.WriteHeader(&tar.Header{Name: name, Size: size, ModTime: startTime, AccessTime: startTime, ChangeTime: startTime}) 432 tr.Write(contents) 433 tr.Close() 434 gw.Close() 435 ioutil.WriteFile("/tmp/t.gz", inputbuf.Bytes(), 0644) 436 return inputbuf.Bytes() 437 } 438 439 // Deploy a chaincode - i.e., build and initialize. 440 func deployCC(t *testing.T, txParams *ccprovider.TransactionParams, ccContext *CCContext, spec *pb.ChaincodeSpec, chaincodeSupport *ChaincodeSupport) { 441 // First build and get the deployment spec 442 code := getTarGZ(t, "src/dummy/dummy.go", []byte("code")) 443 cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: code} 444 445 cryptoProvider, err := sw.NewDefaultSecurityLevelWithKeystore(sw.NewDummyKeyStore()) 446 assert.NoError(t, err) 447 ccinfoFSImpl := &ccprovider.CCInfoFSImpl{GetHasher: cryptoProvider} 448 _, err = ccinfoFSImpl.PutChaincode(cds) 449 assert.NoError(t, err) 450 451 b := protoutil.MarshalOrPanic(cds) 452 453 //wrap the deployment in an invocation spec to lscc... 454 lsccSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeId: &pb.ChaincodeID{Name: "lscc"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("deploy"), []byte(txParams.ChannelID), b}}}} 455 456 //write to lscc 457 if _, _, err := chaincodeSupport.Execute(txParams, "lscc", lsccSpec.ChaincodeSpec.Input); err != nil { 458 t.Fatalf("Error deploying chaincode %v (err: %s)", ccContext, err) 459 } 460 } 461 462 func initializeCC(t *testing.T, chainID, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) error { 463 done := setuperror() 464 465 errorFunc := func(ind int, err error) { 466 done <- err 467 } 468 469 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 470 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("A"), []byte("100"), []byte("B"), []byte("200")}, Decorations: nil} 471 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 472 473 txid := util.GenerateUUID() 474 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 475 476 //bad txid in response (should be "1"), should fail 477 resp := &mock.MockResponse{ 478 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, 479 RespMsg: &pb.ChaincodeMessage{ 480 Type: pb.ChaincodeMessage_COMPLETED, 481 Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("init succeeded")}), 482 Txid: "unknowntxid", 483 ChannelId: chainID, 484 }, 485 } 486 respSet := &mock.MockResponseSet{ 487 DoneFunc: errorFunc, 488 ErrorFunc: nil, 489 Responses: []*mock.MockResponse{resp}, 490 } 491 492 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 493 494 //set the right TxID in response now 495 resp = &mock.MockResponse{ 496 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, 497 RespMsg: &pb.ChaincodeMessage{ 498 Type: pb.ChaincodeMessage_COMPLETED, 499 Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("init succeeded")}), 500 Txid: txid, 501 ChannelId: chainID, 502 }, 503 } 504 respSet = &mock.MockResponseSet{ 505 DoneFunc: errorFunc, 506 ErrorFunc: nil, 507 Responses: []*mock.MockResponse{resp}, 508 } 509 510 //we are not going to reach the chaincode and so won't get a response from it. processDone will not 511 //be triggered by the chaincode stream. We just expect an error from fabric. Hence pass nil for done 512 execCC(t, txParams, ccSide, "badccname", false, true, nil, cis, respSet, chaincodeSupport) 513 514 //---------try a successful init at last------- 515 //everything lined up 516 // correct registered chaincode version 517 // matching txid 518 // txsim context 519 // full response 520 // correct block number for ending sim 521 522 respSet = &mock.MockResponseSet{ 523 DoneFunc: errorFunc, 524 ErrorFunc: nil, 525 Responses: []*mock.MockResponse{ 526 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: protoutil.MarshalOrPanic(&pb.PutState{Collection: "", Key: "A", Value: []byte("100")}), Txid: txid, ChannelId: chainID}}, 527 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: protoutil.MarshalOrPanic(&pb.PutState{Collection: "", Key: "B", Value: []byte("200")}), Txid: txid, ChannelId: chainID}}, 528 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), ChaincodeEvent: &pb.ChaincodeEvent{ChaincodeId: ccname}, Txid: txid, ChannelId: chainID}}, 529 }, 530 } 531 532 execCC(t, txParams, ccSide, ccname, false, false, done, cis, respSet, chaincodeSupport) 533 534 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 535 536 return nil 537 } 538 539 func invokeCC(t *testing.T, chainID, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) error { 540 done := setuperror() 541 542 errorFunc := func(ind int, err error) { 543 done <- err 544 } 545 546 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 547 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}, Decorations: nil} 548 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 549 txid := util.GenerateUUID() 550 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 551 552 respSet := &mock.MockResponseSet{ 553 DoneFunc: errorFunc, 554 ErrorFunc: nil, 555 Responses: []*mock.MockResponse{ 556 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: protoutil.MarshalOrPanic(&pb.GetState{Collection: "", Key: "A"}), Txid: txid, ChannelId: chainID}}, 557 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: protoutil.MarshalOrPanic(&pb.GetState{Collection: "", Key: "B"}), Txid: txid, ChannelId: chainID}}, 558 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: protoutil.MarshalOrPanic(&pb.PutState{Collection: "", Key: "A", Value: []byte("90")}), Txid: txid, ChannelId: chainID}}, 559 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: protoutil.MarshalOrPanic(&pb.PutState{Collection: "", Key: "B", Value: []byte("210")}), Txid: txid, ChannelId: chainID}}, 560 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: protoutil.MarshalOrPanic(&pb.PutState{Collection: "", Key: "TODEL", Value: []byte("-to-be-deleted-")}), Txid: txid, ChannelId: chainID}}, 561 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: txid, ChannelId: chainID}}, 562 }, 563 } 564 565 execCC(t, txParams, ccSide, ccname, false, false, done, cis, respSet, chaincodeSupport) 566 567 //delete the extra var 568 respSet = &mock.MockResponseSet{ 569 DoneFunc: errorFunc, 570 ErrorFunc: nil, 571 Responses: []*mock.MockResponse{ 572 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: protoutil.MarshalOrPanic(&pb.GetState{Collection: "", Key: "TODEL"}), Txid: "3", ChannelId: chainID}}, 573 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_DEL_STATE, Payload: protoutil.MarshalOrPanic(&pb.DelState{Collection: "", Key: "TODEL"}), Txid: "3", ChannelId: chainID}}, 574 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "3", ChannelId: chainID}}, 575 }, 576 } 577 578 txParams.TxID = "3" 579 execCC(t, txParams, ccSide, ccname, false, false, done, cis, respSet, chaincodeSupport) 580 581 //get the extra var and delete it 582 respSet = &mock.MockResponseSet{ 583 DoneFunc: errorFunc, 584 ErrorFunc: nil, 585 Responses: []*mock.MockResponse{ 586 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: protoutil.MarshalOrPanic(&pb.GetState{Collection: "", Key: "TODEL"}), Txid: "4", ChannelId: chainID}}, 587 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.ERROR, Message: "variable not found"}), Txid: "4", ChannelId: chainID}}, 588 }, 589 } 590 591 txParams.TxID = "4" 592 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 593 594 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 595 596 return nil 597 } 598 599 func getQueryStateByRange(t *testing.T, collection, chainID, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) error { 600 done := setuperror() 601 errorFunc := func(ind int, err error) { 602 done <- err 603 } 604 605 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 606 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}, Decorations: nil} 607 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 608 txid := util.GenerateUUID() 609 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 610 611 //create the response 612 queryStateNextFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 613 qr := &pb.QueryResponse{} 614 proto.Unmarshal(reqMsg.Payload, qr) 615 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: protoutil.MarshalOrPanic(&pb.QueryStateNext{Id: qr.Id}), Txid: txid, ChannelId: chainID} 616 } 617 queryStateCloseFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 618 qr := &pb.QueryResponse{} 619 proto.Unmarshal(reqMsg.Payload, qr) 620 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: protoutil.MarshalOrPanic(&pb.QueryStateClose{Id: qr.Id}), Txid: txid, ChannelId: chainID} 621 } 622 623 var mkpeer []*mock.MockResponse 624 625 mkpeer = append(mkpeer, &mock.MockResponse{ 626 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, 627 RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE_BY_RANGE, Payload: protoutil.MarshalOrPanic(&pb.GetStateByRange{Collection: collection, StartKey: "A", EndKey: "B"}), Txid: txid, ChannelId: chainID}, 628 }) 629 630 if collection == "" { 631 mkpeer = append(mkpeer, &mock.MockResponse{ 632 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, 633 RespMsg: queryStateNextFunc, 634 }) 635 mkpeer = append(mkpeer, &mock.MockResponse{ 636 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, 637 RespMsg: queryStateCloseFunc, 638 }) 639 mkpeer = append(mkpeer, &mock.MockResponse{ 640 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, 641 RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: txid, ChannelId: chainID}, 642 }) 643 } else { 644 // Range queries on private data is not yet implemented. 645 mkpeer = append(mkpeer, &mock.MockResponse{ 646 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, 647 RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.ERROR, Message: "Not Yet Supported"}), Txid: txid, ChannelId: chainID}, 648 }) 649 } 650 651 respSet := &mock.MockResponseSet{ 652 DoneFunc: errorFunc, 653 ErrorFunc: nil, 654 Responses: mkpeer, 655 } 656 657 if collection == "" { 658 execCC(t, txParams, ccSide, ccname, false, false, done, cis, respSet, chaincodeSupport) 659 } else { 660 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 661 } 662 663 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 664 665 return nil 666 } 667 668 func cc2cc(t *testing.T, chainID, chainID2, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) error { 669 calledCC := "calledCC" 670 //starts and registers the CC 671 _, calledCCSide := startCC(t, chainID2, calledCC, chaincodeSupport) 672 if calledCCSide == nil { 673 t.Fatalf("start up failed for called CC") 674 } 675 defer calledCCSide.Quit() 676 677 done := setuperror() 678 679 errorFunc := func(ind int, err error) { 680 done <- err 681 } 682 683 chaincodeID := &pb.ChaincodeID{Name: calledCC, Version: "0"} 684 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("deploycc")}, Decorations: nil} 685 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 686 txid := util.GenerateUUID() 687 //first deploy the new cc to LSCC 688 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 689 690 ccContext := &CCContext{ 691 Name: calledCC, 692 Version: "0", 693 } 694 695 deployCC(t, txParams, ccContext, cis.ChaincodeSpec, chaincodeSupport) 696 697 //commit 698 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 699 700 //now do the cc2cc 701 chaincodeID = &pb.ChaincodeID{Name: ccname, Version: "0"} 702 ci = &pb.ChaincodeInput{Args: [][]byte{[]byte("invokecc")}, Decorations: nil} 703 cis = &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 704 txid = util.GenerateUUID() 705 txParams, txsim = startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 706 707 //call a callable system CC, a regular cc, a regular but different cc on a different chain, a regular but same cc on a different chain, and an uncallable system cc and expect an error inthe last one 708 respSet := &mock.MockResponseSet{ 709 DoneFunc: errorFunc, 710 ErrorFunc: nil, 711 Responses: []*mock.MockResponse{ 712 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "lscc.syscc"}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 713 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "calledCC:0/" + chainID}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 714 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "calledCC:0/" + chainID2}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 715 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "vscc.syscc"}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 716 }, 717 } 718 719 respSet2 := &mock.MockResponseSet{ 720 DoneFunc: nil, 721 ErrorFunc: nil, 722 Responses: []*mock.MockResponse{ 723 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: txid, ChannelId: chainID}}, 724 }, 725 } 726 calledCCSide.SetResponses(respSet2) 727 728 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 729 730 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 731 732 //finally lets try a Bad ACL with CC-calling-CC 733 chaincodeID = &pb.ChaincodeID{Name: ccname, Version: "0"} 734 ci = &pb.ChaincodeInput{Args: [][]byte{[]byte("invokecc")}, Decorations: nil} 735 cis = &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 736 txid = util.GenerateUUID() 737 txParams, txsim = startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 738 739 mockAclProvider := chaincodeSupport.ACLProvider.(*mock.ACLProvider) 740 mockAclProvider.CheckACLStub = func(resource, channel string, _ interface{}) error { 741 if resource == resources.Peer_ChaincodeToChaincode && channel == chainID { 742 return errors.New("bad-acl-calling-cc") 743 } 744 return nil 745 } 746 747 //call regular cc but without ACL on called CC 748 respSet = &mock.MockResponseSet{ 749 DoneFunc: errorFunc, 750 ErrorFunc: nil, 751 Responses: []*mock.MockResponse{ 752 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "calledCC:0/" + chainID}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 753 }, 754 } 755 756 respSet2 = &mock.MockResponseSet{ 757 DoneFunc: nil, 758 ErrorFunc: nil, 759 Responses: []*mock.MockResponse{ 760 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: txid, ChannelId: chainID}}, 761 }, 762 } 763 764 calledCCSide.SetResponses(respSet2) 765 766 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 767 768 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 769 770 return nil 771 } 772 773 func getQueryResult(t *testing.T, collection, chainID, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) error { 774 done := setuperror() 775 776 errorFunc := func(ind int, err error) { 777 done <- err 778 } 779 780 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 781 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}, Decorations: nil} 782 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 783 txid := util.GenerateUUID() 784 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 785 786 kvs := make([]*plgr.KV, 1000) 787 for i := 0; i < 1000; i++ { 788 kvs[i] = &plgr.KV{Namespace: chainID, Key: fmt.Sprintf("%d", i), Value: []byte(fmt.Sprintf("%d", i))} 789 } 790 791 queryExec := &mockExecQuerySimulator{resultsIter: make(map[string]map[string]*mockResultsIterator)} 792 queryExec.resultsIter[ccname] = map[string]*mockResultsIterator{"goodquery": {kvs: kvs}} 793 794 queryExec.txsim = txParams.TXSimulator 795 796 //create the response 797 queryStateNextFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 798 qr := &pb.QueryResponse{} 799 proto.Unmarshal(reqMsg.Payload, qr) 800 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: protoutil.MarshalOrPanic(&pb.QueryStateNext{Id: qr.Id}), Txid: txid, ChannelId: chainID} 801 } 802 queryStateCloseFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 803 qr := &pb.QueryResponse{} 804 proto.Unmarshal(reqMsg.Payload, qr) 805 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: protoutil.MarshalOrPanic(&pb.QueryStateClose{Id: qr.Id}), Txid: txid, ChannelId: chainID} 806 } 807 808 var mkpeer []*mock.MockResponse 809 810 mkpeer = append(mkpeer, &mock.MockResponse{ 811 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, 812 RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_QUERY_RESULT, Payload: protoutil.MarshalOrPanic(&pb.GetQueryResult{Collection: "", Query: "goodquery"}), Txid: txid, ChannelId: chainID}, 813 }) 814 815 if collection == "" { 816 mkpeer = append(mkpeer, &mock.MockResponse{ 817 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, 818 RespMsg: queryStateNextFunc, 819 }) 820 mkpeer = append(mkpeer, &mock.MockResponse{ 821 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, 822 RespMsg: queryStateCloseFunc, 823 }) 824 mkpeer = append(mkpeer, &mock.MockResponse{ 825 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, 826 RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: txid, ChannelId: chainID}, 827 }) 828 } else { 829 // Get query results on private data is not yet implemented. 830 mkpeer = append(mkpeer, &mock.MockResponse{ 831 RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, 832 RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.ERROR, Message: "Not Yet Supported"}), Txid: txid, ChannelId: chainID}, 833 }) 834 } 835 836 respSet := &mock.MockResponseSet{ 837 DoneFunc: errorFunc, 838 ErrorFunc: nil, 839 Responses: mkpeer, 840 } 841 842 if collection == "" { 843 execCC(t, txParams, ccSide, ccname, false, false, done, cis, respSet, chaincodeSupport) 844 } else { 845 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 846 } 847 848 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 849 850 return nil 851 } 852 853 func getHistory(t *testing.T, chainID, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) error { 854 done := setuperror() 855 856 errorFunc := func(ind int, err error) { 857 done <- err 858 } 859 860 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 861 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}, Decorations: nil} 862 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 863 txid := util.GenerateUUID() 864 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 865 866 kvs := make([]*plgr.KV, 1000) 867 for i := 0; i < 1000; i++ { 868 kvs[i] = &plgr.KV{Namespace: chainID, Key: fmt.Sprintf("%d", i), Value: []byte(fmt.Sprintf("%d", i))} 869 } 870 871 queryExec := &mockExecQuerySimulator{resultsIter: make(map[string]map[string]*mockResultsIterator)} 872 queryExec.resultsIter[ccname] = map[string]*mockResultsIterator{"goodquery": {kvs: kvs}} 873 874 queryExec.txsim = txParams.TXSimulator 875 876 //create the response 877 queryStateNextFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 878 qr := &pb.QueryResponse{} 879 proto.Unmarshal(reqMsg.Payload, qr) 880 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: protoutil.MarshalOrPanic(&pb.QueryStateNext{Id: qr.Id}), Txid: txid} 881 } 882 queryStateCloseFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 883 qr := &pb.QueryResponse{} 884 proto.Unmarshal(reqMsg.Payload, qr) 885 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: protoutil.MarshalOrPanic(&pb.QueryStateClose{Id: qr.Id}), Txid: txid} 886 } 887 888 respSet := &mock.MockResponseSet{ 889 DoneFunc: errorFunc, 890 ErrorFunc: nil, 891 Responses: []*mock.MockResponse{ 892 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_HISTORY_FOR_KEY, Payload: protoutil.MarshalOrPanic(&pb.GetQueryResult{Query: "goodquery"}), Txid: txid, ChannelId: chainID}}, 893 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: queryStateNextFunc}, 894 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: queryStateNextFunc}, 895 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, RespMsg: queryStateCloseFunc}, 896 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: protoutil.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: txid, ChannelId: chainID}}, 897 }, 898 } 899 900 execCC(t, txParams, ccSide, ccname, false, false, done, cis, respSet, chaincodeSupport) 901 902 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 903 904 return nil 905 } 906 907 //success case 908 func TestStartAndWaitSuccess(t *testing.T) { 909 handlerRegistry := NewHandlerRegistry(false) 910 fakeRuntime := &mock.Runtime{} 911 fakeRuntime.StartStub = func(_ string, _ *ccintf.PeerConnection) error { 912 handlerRegistry.Ready("testcc:0") 913 return nil 914 } 915 916 launcher := &RuntimeLauncher{ 917 Runtime: fakeRuntime, 918 Registry: handlerRegistry, 919 StartupTimeout: 10 * time.Second, 920 Metrics: NewLaunchMetrics(&disabled.Provider{}), 921 } 922 923 fakeStreamHandler := &mock.ChaincodeStreamHandler{} 924 //actual test - everythings good 925 err := launcher.Launch("testcc:0", fakeStreamHandler) 926 if err != nil { 927 t.Fatalf("expected success but failed with error %s", err) 928 } 929 } 930 931 //test timeout error 932 func TestStartAndWaitTimeout(t *testing.T) { 933 fakeRuntime := &mock.Runtime{} 934 fakeRuntime.StartStub = func(_ string, _ *ccintf.PeerConnection) error { 935 time.Sleep(time.Second) 936 return nil 937 } 938 939 launcher := &RuntimeLauncher{ 940 Runtime: fakeRuntime, 941 Registry: NewHandlerRegistry(false), 942 StartupTimeout: 500 * time.Millisecond, 943 Metrics: NewLaunchMetrics(&disabled.Provider{}), 944 } 945 946 fakeStreamHandler := &mock.ChaincodeStreamHandler{} 947 //the actual test - timeout 1000 > 500 948 err := launcher.Launch("testcc:0", fakeStreamHandler) 949 if err == nil { 950 t.Fatalf("expected error but succeeded") 951 } 952 } 953 954 //test container return error 955 func TestStartAndWaitLaunchError(t *testing.T) { 956 fakeRuntime := &mock.Runtime{} 957 fakeRuntime.StartStub = func(_ string, _ *ccintf.PeerConnection) error { 958 return errors.New("Bad lunch; upset stomach") 959 } 960 961 launcher := &RuntimeLauncher{ 962 Runtime: fakeRuntime, 963 Registry: NewHandlerRegistry(false), 964 StartupTimeout: 10 * time.Second, 965 Metrics: NewLaunchMetrics(&disabled.Provider{}), 966 } 967 968 fakeStreamHandler := &mock.ChaincodeStreamHandler{} 969 //actual test - container launch gives error 970 err := launcher.Launch("testcc:0", fakeStreamHandler) 971 if err == nil { 972 t.Fatalf("expected error but succeeded") 973 } 974 assert.EqualError(t, err, "error starting container: Bad lunch; upset stomach") 975 } 976 977 func TestGetTxContextFromHandler(t *testing.T) { 978 chnl := "test" 979 peerInstance, _, cleanup, err := initMockPeer(chnl) 980 assert.NoError(t, err, "failed to initialize mock peer") 981 defer cleanup() 982 983 h := Handler{ 984 TXContexts: NewTransactionContexts(), 985 BuiltinSCCs: map[string]struct{}{"lscc": {}}, 986 } 987 988 txid := "1" 989 // test getTxContext for TEST channel, tx=1, msgType=IVNOKE_CHAINCODE and empty payload - empty payload => expect to return empty txContext 990 txContext, _ := h.getTxContextForInvoke(chnl, "1", []byte(""), "[%s]No ledger context for %s. Sending %s", 12345, "TestCC", pb.ChaincodeMessage_ERROR) 991 assert.Nil(t, txContext, "expected empty txContext for empty payload") 992 993 pldgr := peerInstance.GetLedger(chnl) 994 995 // prepare a payload and generate a TxContext in the handler to be used in the following getTxContextFroMessage with a normal UCC 996 txCtxGenerated, payload := genNewPldAndCtxFromLdgr(t, "shimTestCC", chnl, txid, pldgr, &h) 997 998 // test getTxContext for TEST channel, tx=1, msgType=IVNOKE_CHAINCODE and non empty payload => must return a non empty txContext 999 txContext, ccMsg := h.getTxContextForInvoke(chnl, txid, payload, "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_INVOKE_CHAINCODE, pb.ChaincodeMessage_ERROR) 1000 if txContext == nil || ccMsg != nil || txContext != txCtxGenerated { 1001 t.Fatalf("expected successful txContext for non empty payload and INVOKE_CHAINCODE msgType. triggerNextStateMsg: %s.", ccMsg) 1002 } 1003 1004 // test for another msgType (PUT_STATE) with the same payload ==> must return a non empty txContext 1005 txContext, ccMsg = h.getTxContextForInvoke(chnl, txid, payload, "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_PUT_STATE, pb.ChaincodeMessage_ERROR) 1006 if txContext == nil || ccMsg != nil || txContext != txCtxGenerated { 1007 t.Fatalf("expected successful txContext for non empty payload and PUT_STATE msgType. triggerNextStateMsg: %s.", ccMsg) 1008 } 1009 1010 // get a new txContext for our SCC tests 1011 txid = "2" 1012 // reset channel to "" to test getting a context for an SCC without a channel 1013 chnl = "" 1014 txCtxGenerated, payload = genNewPldAndCtxFromLdgr(t, "lscc", chnl, txid, pldgr, &h) 1015 1016 // test getting a TxContext with an SCC without a channel => expect to return a non empty txContext 1017 txContext, ccMsg = h.getTxContextForInvoke(chnl, txid, payload, 1018 "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_INVOKE_CHAINCODE, pb.ChaincodeMessage_ERROR) 1019 if txContext == nil || ccMsg != nil || txContext != txCtxGenerated { 1020 t.Fatalf("expected successful txContext for non empty payload and INVOKE_CHAINCODE msgType. triggerNextStateMsg: %s.", ccMsg) 1021 } 1022 1023 // now reset back to non empty channel and test with an SCC 1024 txid = "3" 1025 chnl = "TEST" 1026 txCtxGenerated, payload = genNewPldAndCtxFromLdgr(t, "lscc", chnl, txid, pldgr, &h) 1027 1028 // test getting a TxContext with an SCC with channel TEST => expect to return a non empty txContext 1029 txContext, ccMsg = h.getTxContextForInvoke(chnl, txid, payload, 1030 "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_INVOKE_CHAINCODE, pb.ChaincodeMessage_ERROR) 1031 if txContext == nil || ccMsg != nil || txContext != txCtxGenerated { 1032 t.Fatalf("expected successful txContext for non empty payload and INVOKE_CHAINCODE msgType. triggerNextStateMsg: %s.", ccMsg) 1033 } 1034 1035 // now test getting a context with an empty channel and a UCC instead of an SCC 1036 txid = "4" 1037 chnl = "" 1038 txCtxGenerated, payload = genNewPldAndCtxFromLdgr(t, "shimTestCC", chnl, txid, pldgr, &h) 1039 // test getting a TxContext with an SCC with channel TEST => expect to return a non empty txContext 1040 txContext, ccMsg = h.getTxContextForInvoke(chnl, txid, payload, 1041 "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_INVOKE_CHAINCODE, pb.ChaincodeMessage_ERROR) 1042 if txContext == nil || ccMsg != nil || txContext != txCtxGenerated { 1043 t.Fatalf("expected successful txContext for non empty payload and INVOKE_CHAINCODE msgType. triggerNextStateMsg: %s.", ccMsg) 1044 } 1045 1046 // new test getting a context with an empty channel without the ledger creating a new context for a UCC 1047 txid = "5" 1048 payload = genNewPld(t, "shimTestCC") 1049 // test getting a TxContext with an SCC with channel TEST => expect to return a non empty txContext 1050 txContext, ccMsg = h.getTxContextForInvoke(chnl, txid, payload, 1051 "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_INVOKE_CHAINCODE, pb.ChaincodeMessage_ERROR) 1052 if txContext != nil || ccMsg == nil { 1053 t.Fatal("expected nil txContext for non empty payload and INVOKE_CHAINCODE msgType without the ledger generating a TxContext . unexpected non nil tcContext") 1054 } 1055 1056 // test same scenario as above but for an SCC this time 1057 txid = "6" 1058 payload = genNewPld(t, "lscc") 1059 // test getting a TxContext with an SCC with channel TEST => expect to return a non empty txContext 1060 txContext, ccMsg = h.getTxContextForInvoke(chnl, txid, payload, 1061 "[%s]No ledger context for %s. Sending %s", 12345, pb.ChaincodeMessage_INVOKE_CHAINCODE, pb.ChaincodeMessage_ERROR) 1062 if txContext != nil || ccMsg == nil { 1063 t.Fatal("expected nil txContext for non empty payload and INVOKE_CHAINCODE msgType without the ledger generating a TxContext . unexpected non nil tcContext") 1064 } 1065 } 1066 1067 func genNewPldAndCtxFromLdgr(t *testing.T, ccName string, chnl string, txid string, pldgr ledger.PeerLedger, h *Handler) (*TransactionContext, []byte) { 1068 // create a new TxSimulator for the received txid 1069 txsim, err := pldgr.NewTxSimulator(txid) 1070 if err != nil { 1071 t.Fatalf("failed to create TxSimulator %s", err) 1072 } 1073 txParams := &ccprovider.TransactionParams{ 1074 TxID: txid, 1075 ChannelID: chnl, 1076 TXSimulator: txsim, 1077 NamespaceID: ccName, 1078 } 1079 newTxCtxt, err := h.TXContexts.Create(txParams) 1080 if err != nil { 1081 t.Fatalf("Error creating TxContext by the handler for cc %s and channel '%s': %s", ccName, chnl, err) 1082 } 1083 if newTxCtxt == nil { 1084 t.Fatalf("Error creating TxContext: newTxCtxt created by the handler is nil for cc %s and channel '%s'.", ccName, chnl) 1085 } 1086 // build a new cds and payload for the CC called ccName 1087 payload := genNewPld(t, ccName) 1088 return newTxCtxt, payload 1089 } 1090 1091 func genNewPld(t *testing.T, ccName string) []byte { 1092 // build a new cds and payload for the CC called ccName 1093 chaincodeID := &pb.ChaincodeID{Name: ccName, Version: "0"} 1094 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("deploycc")}, Decorations: nil} 1095 cds := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci} 1096 payload, err := proto.Marshal(cds) 1097 if err != nil { 1098 t.Fatalf("failed to marshal CDS %s", err) 1099 } 1100 return payload 1101 } 1102 1103 func cc2SameCC(t *testing.T, chainID, chainID2, ccname string, ccSide *mock.MockCCComm, chaincodeSupport *ChaincodeSupport) { 1104 //first deploy the CC on chainID2 1105 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 1106 ci := &pb.ChaincodeInput{Args: [][]byte{[]byte("deploycc")}, Decorations: nil} 1107 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 1108 1109 txid := util.GenerateUUID() 1110 txParams, txsim := startTx(t, chaincodeSupport.Peer, chainID2, cis, txid) 1111 1112 ccContext := &CCContext{ 1113 Name: ccname, 1114 Version: "0", 1115 } 1116 1117 deployCC(t, txParams, ccContext, cis.ChaincodeSpec, chaincodeSupport) 1118 1119 //commit 1120 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 1121 1122 done := setuperror() 1123 1124 errorFunc := func(ind int, err error) { 1125 done <- err 1126 } 1127 1128 //now for the test - call the same cc on a different channel(should succeed), call the same cc on the same channel(should fail) 1129 //Note the error "Another request pending for this Txid. Cannot process." in the logs under TX "cctosamecctx" 1130 ci = &pb.ChaincodeInput{Args: [][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}, Decorations: nil} 1131 cis = &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 1132 txid = util.GenerateUUID() 1133 txParams, txsim = startTx(t, chaincodeSupport.Peer, chainID, cis, txid) 1134 1135 txid = "cctosamecctx" 1136 respSet := &mock.MockResponseSet{ 1137 DoneFunc: errorFunc, 1138 ErrorFunc: nil, 1139 Responses: []*mock.MockResponse{ 1140 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: ccname + ":0/" + chainID2}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 1141 {RecvMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, RespMsg: &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: protoutil.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: ccname + ":0/" + chainID}, Input: &pb.ChaincodeInput{Args: [][]byte{{}}}}), Txid: txid, ChannelId: chainID}}, 1142 }, 1143 } 1144 1145 execCC(t, txParams, ccSide, ccname, false, true, done, cis, respSet, chaincodeSupport) 1146 1147 endTx(t, chaincodeSupport.Peer, txParams, txsim, cis) 1148 } 1149 1150 func TestCCFramework(t *testing.T) { 1151 //register 2 channels 1152 chainID := "mockchainid" 1153 chainID2 := "secondchain" 1154 peerInstance, chaincodeSupport, cleanup, err := initMockPeer(chainID, chainID2) 1155 if err != nil { 1156 t.Fatalf("%s", err) 1157 } 1158 defer cleanup() 1159 defer finitMockPeer(peerInstance, chainID, chainID2) 1160 //create a chaincode 1161 ccname := "shimTestCC" 1162 1163 //starts and registers the CC 1164 _, ccSide := startCC(t, chainID, ccname, chaincodeSupport) 1165 if ccSide == nil { 1166 t.Fatalf("start up failed") 1167 } 1168 defer ccSide.Quit() 1169 1170 //call's init and does some PUT (after doing some negative testing) 1171 initializeCC(t, chainID, ccname, ccSide, chaincodeSupport) 1172 1173 //chaincode support should not allow dups 1174 handler := &Handler{chaincodeID: ccname + ":0", BuiltinSCCs: chaincodeSupport.BuiltinSCCs} 1175 if err := chaincodeSupport.HandlerRegistry.Register(handler); err == nil { 1176 t.Fatalf("expected re-register to fail") 1177 } 1178 1179 //call's init and does some PUT (after doing some negative testing) 1180 initializeCC(t, chainID2, ccname, ccSide, chaincodeSupport) 1181 1182 //call's invoke and do some GET 1183 invokeCC(t, chainID, ccname, ccSide, chaincodeSupport) 1184 1185 //call's query state range 1186 getQueryStateByRange(t, "", chainID, ccname, ccSide, chaincodeSupport) 1187 1188 //call's cc2cc on the same chaincode only call to chainID2 should succeed 1189 cc2SameCC(t, chainID, chainID2, ccname, ccSide, chaincodeSupport) 1190 1191 //call's cc2cc (variation with syscc calls) 1192 cc2cc(t, chainID, chainID2, ccname, ccSide, chaincodeSupport) 1193 // reset mock 1194 chaincodeSupport.ACLProvider = &mock.ACLProvider{} 1195 1196 //call's query result 1197 getQueryResult(t, "", chainID, ccname, ccSide, chaincodeSupport) 1198 1199 //call's history result 1200 getHistory(t, chainID, ccname, ccSide, chaincodeSupport) 1201 1202 ccSide.Quit() 1203 } 1204 1205 func TestExecuteTimeout(t *testing.T) { 1206 _, cs, cleanup, err := initMockPeer("testchannel") 1207 assert.NoError(t, err) 1208 defer cleanup() 1209 1210 tests := []struct { 1211 executeTimeout time.Duration 1212 installTimeout time.Duration 1213 namespace string 1214 command string 1215 expectedTimeout time.Duration 1216 }{ 1217 { 1218 executeTimeout: time.Second, 1219 installTimeout: time.Minute, 1220 namespace: "lscc", 1221 command: "install", 1222 expectedTimeout: time.Minute, 1223 }, 1224 { 1225 executeTimeout: time.Minute, 1226 installTimeout: time.Second, 1227 namespace: "lscc", 1228 command: "install", 1229 expectedTimeout: time.Minute, 1230 }, 1231 { 1232 executeTimeout: time.Second, 1233 installTimeout: time.Minute, 1234 namespace: "_lifecycle", 1235 command: "InstallChaincode", 1236 expectedTimeout: time.Minute, 1237 }, 1238 { 1239 executeTimeout: time.Minute, 1240 installTimeout: time.Second, 1241 namespace: "_lifecycle", 1242 command: "InstallChaincode", 1243 expectedTimeout: time.Minute, 1244 }, 1245 { 1246 executeTimeout: time.Second, 1247 installTimeout: time.Minute, 1248 namespace: "_lifecycle", 1249 command: "anything", 1250 expectedTimeout: time.Second, 1251 }, 1252 { 1253 executeTimeout: time.Second, 1254 installTimeout: time.Minute, 1255 namespace: "lscc", 1256 command: "anything", 1257 expectedTimeout: time.Second, 1258 }, 1259 { 1260 executeTimeout: time.Second, 1261 installTimeout: time.Minute, 1262 namespace: "anything", 1263 command: "", 1264 expectedTimeout: time.Second, 1265 }, 1266 } 1267 for _, tt := range tests { 1268 t.Run(tt.namespace+"_"+tt.command, func(t *testing.T) { 1269 cs.ExecuteTimeout = tt.executeTimeout 1270 cs.InstallTimeout = tt.installTimeout 1271 input := &pb.ChaincodeInput{Args: util.ToChaincodeArgs(tt.command)} 1272 1273 result := cs.executeTimeout(tt.namespace, input) 1274 assert.Equalf(t, tt.expectedTimeout, result, "want %s, got %s", tt.expectedTimeout, result) 1275 }) 1276 } 1277 } 1278 1279 func TestMaxDuration(t *testing.T) { 1280 tests := []struct { 1281 durations []time.Duration 1282 expected time.Duration 1283 }{ 1284 { 1285 durations: []time.Duration{}, 1286 expected: time.Duration(0), 1287 }, 1288 { 1289 durations: []time.Duration{time.Second, time.Hour, time.Minute}, 1290 expected: time.Hour, 1291 }, 1292 { 1293 durations: []time.Duration{-time.Second}, 1294 expected: time.Duration(0), 1295 }, 1296 } 1297 for _, tt := range tests { 1298 result := maxDuration(tt.durations...) 1299 assert.Equalf(t, tt.expected, result, "want %s got %s", tt.expected, result) 1300 } 1301 }