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