github.com/kchristidis/fabric@v1.0.4-0.20171028114726-837acd08cde1/core/chaincode/chaincode_support_test.go (about) 1 /* 2 Copyright IBM Corp. 2017 All Rights Reserved. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package chaincode 18 19 import ( 20 "archive/tar" 21 "bytes" 22 "compress/gzip" 23 "fmt" 24 "io/ioutil" 25 "os" 26 "path/filepath" 27 "testing" 28 "time" 29 30 "github.com/golang/protobuf/proto" 31 "github.com/hyperledger/fabric/common/flogging" 32 commonledger "github.com/hyperledger/fabric/common/ledger" 33 mocklgr "github.com/hyperledger/fabric/common/mocks/ledger" 34 mockpeer "github.com/hyperledger/fabric/common/mocks/peer" 35 "github.com/hyperledger/fabric/common/util" 36 "github.com/hyperledger/fabric/core/chaincode/shim" 37 "github.com/hyperledger/fabric/core/common/ccprovider" 38 "github.com/hyperledger/fabric/core/config" 39 "github.com/hyperledger/fabric/core/ledger" 40 "github.com/hyperledger/fabric/core/ledger/ledgermgmt" 41 "github.com/hyperledger/fabric/core/peer" 42 "github.com/hyperledger/fabric/core/policy" 43 "github.com/hyperledger/fabric/core/scc" 44 plgr "github.com/hyperledger/fabric/protos/ledger/queryresult" 45 pb "github.com/hyperledger/fabric/protos/peer" 46 putils "github.com/hyperledger/fabric/protos/utils" 47 "golang.org/x/net/context" 48 49 mspmgmt "github.com/hyperledger/fabric/msp/mgmt" 50 ) 51 52 var globalBlockNum map[string]uint64 53 54 type mockResultsIterator struct { 55 current int 56 kvs []*plgr.KV 57 } 58 59 func (mri *mockResultsIterator) Next() (commonledger.QueryResult, error) { 60 if mri.current == len(mri.kvs) { 61 return nil, nil 62 } 63 kv := mri.kvs[mri.current] 64 mri.current = mri.current + 1 65 66 return kv, nil 67 } 68 69 func (mri *mockResultsIterator) Close() { 70 mri.current = len(mri.kvs) 71 } 72 73 type mockExecQuerySimulator struct { 74 txsim ledger.TxSimulator 75 mocklgr.MockQueryExecutor 76 resultsIter map[string]map[string]*mockResultsIterator 77 } 78 79 func (meqe *mockExecQuerySimulator) GetHistoryForKey(namespace, query string) (commonledger.ResultsIterator, error) { 80 return meqe.commonQuery(namespace, query) 81 } 82 83 func (meqe *mockExecQuerySimulator) ExecuteQuery(namespace, query string) (commonledger.ResultsIterator, error) { 84 return meqe.commonQuery(namespace, query) 85 } 86 87 func (meqe *mockExecQuerySimulator) commonQuery(namespace, query string) (commonledger.ResultsIterator, error) { 88 if meqe.resultsIter == nil { 89 return nil, fmt.Errorf("query executor not initialized") 90 } 91 nsiter := meqe.resultsIter[namespace] 92 if nsiter == nil { 93 return nil, fmt.Errorf("namespace %v not found for %s", namespace, query) 94 } 95 iter := nsiter[query] 96 if iter == nil { 97 fmt.Printf("iter not found for query %s\n", query) 98 } 99 return iter, nil 100 } 101 102 func (meqe *mockExecQuerySimulator) SetState(namespace string, key string, value []byte) error { 103 if meqe.txsim == nil { 104 return fmt.Errorf("SetState txsimulator not initialed") 105 } 106 return meqe.txsim.SetState(namespace, key, value) 107 } 108 109 func (meqe *mockExecQuerySimulator) DeleteState(namespace string, key string) error { 110 if meqe.txsim == nil { 111 return fmt.Errorf("SetState txsimulator not initialed") 112 } 113 return meqe.txsim.DeleteState(namespace, key) 114 } 115 116 func (meqe *mockExecQuerySimulator) SetStateMultipleKeys(namespace string, kvs map[string][]byte) error { 117 if meqe.txsim == nil { 118 return fmt.Errorf("SetState txsimulator not initialed") 119 } 120 return meqe.txsim.SetStateMultipleKeys(namespace, kvs) 121 } 122 123 func (meqe *mockExecQuerySimulator) ExecuteUpdate(query string) error { 124 if meqe.txsim == nil { 125 return fmt.Errorf("SetState txsimulator not initialed") 126 } 127 return meqe.txsim.ExecuteUpdate(query) 128 } 129 130 func (meqe *mockExecQuerySimulator) GetTxSimulationResults() ([]byte, error) { 131 if meqe.txsim == nil { 132 return nil, fmt.Errorf("SetState txsimulator not initialed") 133 } 134 return meqe.txsim.GetTxSimulationResults() 135 } 136 137 //initialize peer and start up. If security==enabled, login as vp 138 func initMockPeer(chainIDs ...string) error { 139 peer.MockInitialize() 140 141 mspGetter := func(cid string) []string { 142 return []string{"DEFAULT"} 143 } 144 145 peer.MockSetMSPIDGetter(mspGetter) 146 147 getPeerEndpoint := func() (*pb.PeerEndpoint, error) { 148 return &pb.PeerEndpoint{Id: &pb.PeerID{Name: "testpeer"}}, nil 149 } 150 151 ccStartupTimeout := time.Duration(2) * time.Second 152 NewChaincodeSupport(getPeerEndpoint, false, ccStartupTimeout) 153 theChaincodeSupport.executetimeout = time.Duration(1) * time.Second 154 155 // Mock policy checker 156 policy.RegisterPolicyCheckerFactory(&mockPolicyCheckerFactory{}) 157 158 scc.RegisterSysCCs() 159 160 globalBlockNum = make(map[string]uint64, len(chainIDs)) 161 for _, id := range chainIDs { 162 scc.DeDeploySysCCs(id) 163 if err := peer.MockCreateChain(id); err != nil { 164 return err 165 } 166 scc.DeploySysCCs(id) 167 // any chain other than the default testchainid does not have a MSP set up -> create one 168 if id != util.GetTestChainID() { 169 mspmgmt.XXXSetMSPManager(id, mspmgmt.GetManagerForChain(util.GetTestChainID())) 170 } 171 globalBlockNum[id] = 1 172 } 173 174 return nil 175 } 176 177 func finitMockPeer(chainIDs ...string) { 178 for _, c := range chainIDs { 179 scc.DeDeploySysCCs(c) 180 if lgr := peer.GetLedger(c); lgr != nil { 181 lgr.Close() 182 } 183 } 184 ledgermgmt.CleanupTestEnv() 185 ledgerPath := config.GetPath("peer.fileSystemPath") 186 os.RemoveAll(ledgerPath) 187 os.RemoveAll(filepath.Join(os.TempDir(), "hyperledger")) 188 } 189 190 //store the stream CC mappings here 191 var mockPeerCCSupport = mockpeer.NewMockPeerSupport() 192 193 func mockChaincodeStreamGetter(name string) (shim.PeerChaincodeStream, error) { 194 return mockPeerCCSupport.GetCC(name) 195 } 196 197 func setupcc(name string) (*mockpeer.MockCCComm, *mockpeer.MockCCComm) { 198 send := make(chan *pb.ChaincodeMessage) 199 recv := make(chan *pb.ChaincodeMessage) 200 peerSide, _ := mockPeerCCSupport.AddCC(name, recv, send) 201 peerSide.SetName("peer") 202 ccSide := mockPeerCCSupport.GetCCMirror(name) 203 ccSide.SetPong(true) 204 return peerSide, ccSide 205 } 206 207 //assign this to done and failNow and keep using them 208 func setuperror() chan error { 209 return make(chan error) 210 } 211 212 func processDone(t *testing.T, done chan error, expecterr bool) { 213 var err error 214 if done != nil { 215 err = <-done 216 } 217 if expecterr != (err != nil) { 218 if err == nil { 219 t.Fatalf("Expected error but got success") 220 } else { 221 t.Fatalf("Expected success but got error %s", err) 222 } 223 } 224 } 225 226 func startTx(t *testing.T, chainID string, cis *pb.ChaincodeInvocationSpec) (context.Context, ledger.TxSimulator, *pb.SignedProposal, *pb.Proposal) { 227 ctxt := context.Background() 228 229 creator := []byte([]byte("Alice")) 230 sprop, prop := putils.MockSignedEndorserProposalOrPanic(chainID, cis.ChaincodeSpec, creator, []byte("msg1")) 231 var txsim ledger.TxSimulator 232 var err error 233 if ctxt, txsim, err = startTxSimulation(ctxt, chainID); err != nil { 234 t.Fatalf("getting txsimulator failed %s", err) 235 } 236 return ctxt, txsim, sprop, prop 237 } 238 239 func endTx(t *testing.T, cccid *ccprovider.CCContext, txsim ledger.TxSimulator, cis *pb.ChaincodeInvocationSpec) { 240 if err := endTxSimulationCIS(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId, cccid.TxID, txsim, []byte("invoke"), true, cis, globalBlockNum[cccid.ChainID]); err != nil { 241 t.Fatalf("simulation failed with error %s", err) 242 } 243 globalBlockNum[cccid.ChainID] = globalBlockNum[cccid.ChainID] + 1 244 } 245 246 func execCC(t *testing.T, ctxt context.Context, ccSide *mockpeer.MockCCComm, cccid *ccprovider.CCContext, waitForERROR bool, expectExecErr bool, done chan error, cis *pb.ChaincodeInvocationSpec, respSet *mockpeer.MockResponseSet) error { 247 ccSide.SetResponses(respSet) 248 249 _, _, err := ExecuteWithErrorFilter(ctxt, cccid, cis) 250 251 if err == nil && expectExecErr { 252 t.Fatalf("expected error but succeeded") 253 } else if err != nil && !expectExecErr { 254 t.Fatalf("exec failed with %s", err) 255 } 256 257 //wait 258 processDone(t, done, waitForERROR) 259 260 return nil 261 } 262 263 //initialize cc support env and startup the chaincode 264 func startCC(t *testing.T, ccname string) (*mockpeer.MockCCComm, *mockpeer.MockCCComm) { 265 peerSide, ccSide := setupcc(ccname) 266 defer mockPeerCCSupport.RemoveCC(ccname) 267 theChaincodeSupport.userRunsCC = true 268 flogging.SetModuleLevel("chaincode", "debug") 269 //register peer side with ccsupport 270 go func() { 271 theChaincodeSupport.HandleChaincodeStream(context.Background(), peerSide) 272 }() 273 274 done := setuperror() 275 276 errorFunc := func(ind int, err error) { 277 done <- err 278 } 279 280 //start the mock peer 281 go func() { 282 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 283 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTERED}, nil}, 284 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_READY}, nil}}} 285 ccSide.SetResponses(respSet) 286 ccSide.Run() 287 }() 288 289 ccSide.Send(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTER, Payload: putils.MarshalOrPanic(&pb.ChaincodeID{Name: ccname + ":0"}), Txid: "0"}) 290 291 //wait for init 292 processDone(t, done, false) 293 294 return peerSide, ccSide 295 } 296 297 func getTarGZ(t *testing.T, name string, contents []byte) []byte { 298 startTime := time.Now() 299 inputbuf := bytes.NewBuffer(nil) 300 gw := gzip.NewWriter(inputbuf) 301 tr := tar.NewWriter(gw) 302 size := int64(len(contents)) 303 304 tr.WriteHeader(&tar.Header{Name: name, Size: size, ModTime: startTime, AccessTime: startTime, ChangeTime: startTime}) 305 tr.Write(contents) 306 tr.Close() 307 gw.Close() 308 ioutil.WriteFile("/tmp/t.gz", inputbuf.Bytes(), 0644) 309 return inputbuf.Bytes() 310 } 311 312 // Deploy a chaincode - i.e., build and initialize. 313 func deployCC(t *testing.T, ctx context.Context, cccid *ccprovider.CCContext, spec *pb.ChaincodeSpec) { 314 // First build and get the deployment spec 315 code := getTarGZ(t, "src/dummy/dummy.go", []byte("code")) 316 cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: code} 317 318 //ignore existence errors 319 ccprovider.PutChaincodeIntoFS(cds) 320 321 b := putils.MarshalOrPanic(cds) 322 323 sysCCVers := util.GetSysCCVersion() 324 325 //wrap the deployment in an invocation spec to lscc... 326 lsccSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeId: &pb.ChaincodeID{Name: "lscc", Version: sysCCVers}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("deploy"), []byte(cccid.ChainID), b}}}} 327 328 sprop, prop := putils.MockSignedEndorserProposal2OrPanic(cccid.ChainID, lsccSpec.ChaincodeSpec, signer) 329 lsccid := ccprovider.NewCCContext(cccid.ChainID, lsccSpec.ChaincodeSpec.ChaincodeId.Name, sysCCVers, cccid.TxID, true, sprop, prop) 330 331 //write to lscc 332 if _, _, err := ExecuteWithErrorFilter(ctx, lsccid, lsccSpec); err != nil { 333 t.Fatalf("Error deploying chaincode %v (err: %s)", cccid, err) 334 } 335 } 336 337 func initializeCC(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCComm) error { 338 done := setuperror() 339 340 errorFunc := func(ind int, err error) { 341 done <- err 342 } 343 344 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 345 ci := &pb.ChaincodeInput{[][]byte{[]byte("init"), []byte("A"), []byte("100"), []byte("B"), []byte("200")}} 346 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 347 348 ctxt, txsim, sprop, prop := startTx(t, chainID, cis) 349 350 //bad txid in response (should be "1"), should fail 351 resp := &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("init succeeded")}), Txid: "unknowntxid"}} 352 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{resp}} 353 354 cccid := ccprovider.NewCCContext(chainID, ccname, "0", "1", false, sprop, prop) 355 execCC(t, ctxt, ccSide, cccid, false, true, done, cis, respSet) 356 357 //set the right TxID in response now 358 resp.RespMsg.(*pb.ChaincodeMessage).Txid = "1" 359 360 badcccid := ccprovider.NewCCContext(chainID, ccname, "unknownver", "1", false, sprop, prop) 361 362 //we are not going to reach the chaincode and so won't get a response from it. processDone will not 363 //be triggered by the chaincode stream. We just expect an error from fabric. Hence pass nil for done 364 execCC(t, ctxt, ccSide, badcccid, false, true, nil, cis, respSet) 365 366 //---------try a successful init at last------- 367 //everything lined up 368 // correct registered chaincode version 369 // matching txid 370 // txsim context 371 // full response 372 // correct block number for ending sim 373 374 respSet = &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 375 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: putils.MarshalOrPanic(&pb.PutStateInfo{Key: "A", Value: []byte("100")}), Txid: "1"}}, 376 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: putils.MarshalOrPanic(&pb.PutStateInfo{Key: "B", Value: []byte("200")}), Txid: "1"}}, 377 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), ChaincodeEvent: &pb.ChaincodeEvent{ChaincodeId: ccname}, Txid: "1"}}}} 378 379 cccid.Version = "1" 380 execCC(t, ctxt, ccSide, cccid, false, false, done, cis, respSet) 381 382 endTx(t, cccid, txsim, cis) 383 384 return nil 385 } 386 387 func invokeCC(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCComm) error { 388 done := setuperror() 389 390 errorFunc := func(ind int, err error) { 391 done <- err 392 } 393 394 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 395 ci := &pb.ChaincodeInput{[][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}} 396 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 397 398 ctxt, txsim, sprop, prop := startTx(t, chainID, cis) 399 400 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 401 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: []byte("A"), Txid: "2"}}, 402 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: []byte("B"), Txid: "2"}}, 403 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: putils.MarshalOrPanic(&pb.PutStateInfo{Key: "A", Value: []byte("90")}), Txid: "2"}}, 404 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: putils.MarshalOrPanic(&pb.PutStateInfo{Key: "B", Value: []byte("210")}), Txid: "2"}}, 405 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_PUT_STATE, Payload: putils.MarshalOrPanic(&pb.PutStateInfo{Key: "TODEL", Value: []byte("-to-be-deleted-")}), Txid: "2"}}, 406 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "2"}}}} 407 408 cccid := ccprovider.NewCCContext(chainID, ccname, "0", "2", false, sprop, prop) 409 execCC(t, ctxt, ccSide, cccid, false, false, done, cis, respSet) 410 411 //delete the extra var 412 respSet = &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 413 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: []byte("TODEL"), Txid: "3"}}, 414 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_DEL_STATE, Payload: []byte("TODEL"), Txid: "3"}}, 415 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "3"}}}} 416 417 cccid.TxID = "3" 418 execCC(t, ctxt, ccSide, cccid, false, false, done, cis, respSet) 419 420 //get the extra var and delete it 421 //NOTE- we are calling ExecuteWithErrorFilter which returns error if chaincode returns ERROR response 422 respSet = &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 423 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE, Payload: []byte("TODEL"), Txid: "4"}}, 424 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.ERROR, Message: "variable not found"}), Txid: "4"}}}} 425 426 cccid.TxID = "4" 427 execCC(t, ctxt, ccSide, cccid, false, true, done, cis, respSet) 428 429 endTx(t, cccid, txsim, cis) 430 431 return nil 432 } 433 434 func getQueryStateByRange(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCComm) error { 435 done := setuperror() 436 437 errorFunc := func(ind int, err error) { 438 done <- err 439 } 440 441 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 442 ci := &pb.ChaincodeInput{[][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}} 443 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 444 445 ctxt, txsim, sprop, prop := startTx(t, chainID, cis) 446 447 //create the response 448 queryStateNextFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 449 qr := &pb.QueryResponse{} 450 proto.Unmarshal(reqMsg.Payload, qr) 451 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: putils.MarshalOrPanic(&pb.QueryStateNext{Id: qr.Id}), Txid: "5"} 452 } 453 queryStateCloseFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 454 qr := &pb.QueryResponse{} 455 proto.Unmarshal(reqMsg.Payload, qr) 456 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: putils.MarshalOrPanic(&pb.QueryStateClose{Id: qr.Id}), Txid: "5"} 457 } 458 459 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 460 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_STATE_BY_RANGE, Payload: putils.MarshalOrPanic(&pb.GetStateByRange{StartKey: "A", EndKey: "B"}), Txid: "5"}}, 461 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, queryStateNextFunc}, 462 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, queryStateCloseFunc}, 463 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "5"}}}} 464 465 cccid := ccprovider.NewCCContext(chainID, ccname, "0", "5", false, sprop, prop) 466 execCC(t, ctxt, ccSide, cccid, false, false, done, cis, respSet) 467 468 endTx(t, cccid, txsim, cis) 469 470 return nil 471 } 472 473 func cc2cc(t *testing.T, chainID, chainID2, ccname string, ccSide *mockpeer.MockCCComm) error { 474 calledCC := "calledCC" 475 //starts and registers the CC 476 _, calledCCSide := startCC(t, calledCC) 477 if calledCCSide == nil { 478 t.Fatalf("start up failed for called CC") 479 } 480 defer calledCCSide.Quit() 481 482 done := setuperror() 483 484 errorFunc := func(ind int, err error) { 485 done <- err 486 } 487 488 chaincodeID := &pb.ChaincodeID{Name: calledCC, Version: "0"} 489 ci := &pb.ChaincodeInput{[][]byte{[]byte("deploycc")}} 490 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 491 492 //first deploy the new cc to LSCC 493 ctxt, txsim, sprop, prop := startTx(t, chainID, cis) 494 cccid := ccprovider.NewCCContext(chainID, calledCC, "0", "6", false, sprop, prop) 495 496 deployCC(t, ctxt, cccid, cis.ChaincodeSpec) 497 498 //commit 499 endTx(t, cccid, txsim, cis) 500 501 //now do the cc2cc 502 chaincodeID = &pb.ChaincodeID{Name: ccname, Version: "0"} 503 ci = &pb.ChaincodeInput{[][]byte{[]byte("invokecc")}} 504 cis = &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 505 506 ctxt, txsim, sprop, prop = startTx(t, chainID, cis) 507 508 if _, _, err := ccprovider.GetChaincodeProvider().GetCCValidationInfoFromLSCC(ctxt, "getccdata", sprop, prop, chainID, calledCC); err != nil { 509 t.Fatalf("Could not get chaincode data from lscc for %s", calledCC) 510 } 511 512 sysCCVers := util.GetSysCCVersion() 513 //call a callable system CC, a regular cc, a regular cc on a different chain and an uncallable system cc and expect an error inthe last one 514 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 515 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: putils.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "lscc:" + sysCCVers}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte{}}}}), Txid: "7"}}, 516 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: putils.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "calledCC:0/" + chainID}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte{}}}}), Txid: "7"}}, 517 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: putils.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "calledCC:0/" + chainID2}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte{}}}}), Txid: "7"}}, 518 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_INVOKE_CHAINCODE, Payload: putils.MarshalOrPanic(&pb.ChaincodeSpec{ChaincodeId: &pb.ChaincodeID{Name: "vscc:" + sysCCVers}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte{}}}}), Txid: "7"}}}} 519 520 respSet2 := &mockpeer.MockResponseSet{nil, nil, []*mockpeer.MockResponse{ 521 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "7"}}}} 522 calledCCSide.SetResponses(respSet2) 523 524 cccid = ccprovider.NewCCContext(chainID, ccname, "0", "7", false, sprop, prop) 525 526 execCC(t, ctxt, ccSide, cccid, false, true, done, cis, respSet) 527 528 endTx(t, cccid, txsim, cis) 529 530 return nil 531 } 532 533 func getQueryResult(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCComm) error { 534 done := setuperror() 535 536 errorFunc := func(ind int, err error) { 537 done <- err 538 } 539 540 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 541 ci := &pb.ChaincodeInput{[][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}} 542 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 543 544 ctxt, txsim, sprop, prop := startTx(t, chainID, cis) 545 546 kvs := make([]*plgr.KV, 1000) 547 for i := 0; i < 1000; i++ { 548 kvs[i] = &plgr.KV{chainID, fmt.Sprintf("%d", i), []byte(fmt.Sprintf("%d", i))} 549 } 550 551 queryExec := &mockExecQuerySimulator{resultsIter: make(map[string]map[string]*mockResultsIterator)} 552 queryExec.resultsIter[ccname] = map[string]*mockResultsIterator{"goodquery": &mockResultsIterator{kvs: kvs}} 553 554 queryExec.txsim = ctxt.Value(TXSimulatorKey).(ledger.TxSimulator) 555 ctxt = context.WithValue(ctxt, TXSimulatorKey, queryExec) 556 557 //create the response 558 queryStateNextFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 559 qr := &pb.QueryResponse{} 560 proto.Unmarshal(reqMsg.Payload, qr) 561 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: putils.MarshalOrPanic(&pb.QueryStateNext{Id: qr.Id}), Txid: "8"} 562 } 563 queryStateCloseFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 564 qr := &pb.QueryResponse{} 565 proto.Unmarshal(reqMsg.Payload, qr) 566 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: putils.MarshalOrPanic(&pb.QueryStateClose{Id: qr.Id}), Txid: "8"} 567 } 568 569 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 570 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_QUERY_RESULT, Payload: putils.MarshalOrPanic(&pb.GetQueryResult{Query: "goodquery"}), Txid: "8"}}, 571 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, queryStateNextFunc}, 572 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, queryStateNextFunc}, 573 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, queryStateCloseFunc}, 574 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "8"}}}} 575 576 cccid := ccprovider.NewCCContext(chainID, ccname, "0", "8", false, sprop, prop) 577 execCC(t, ctxt, ccSide, cccid, false, false, done, cis, respSet) 578 579 endTx(t, cccid, txsim, cis) 580 581 return nil 582 } 583 584 func getHistory(t *testing.T, chainID, ccname string, ccSide *mockpeer.MockCCComm) error { 585 done := setuperror() 586 587 errorFunc := func(ind int, err error) { 588 done <- err 589 } 590 591 chaincodeID := &pb.ChaincodeID{Name: ccname, Version: "0"} 592 ci := &pb.ChaincodeInput{[][]byte{[]byte("invoke"), []byte("A"), []byte("B"), []byte("10")}} 593 cis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeId: chaincodeID, Input: ci}} 594 595 ctxt, txsim, sprop, prop := startTx(t, chainID, cis) 596 597 kvs := make([]*plgr.KV, 1000) 598 for i := 0; i < 1000; i++ { 599 kvs[i] = &plgr.KV{chainID, fmt.Sprintf("%d", i), []byte(fmt.Sprintf("%d", i))} 600 } 601 602 queryExec := &mockExecQuerySimulator{resultsIter: make(map[string]map[string]*mockResultsIterator)} 603 queryExec.resultsIter[ccname] = map[string]*mockResultsIterator{"goodquery": &mockResultsIterator{kvs: kvs}} 604 605 queryExec.txsim = ctxt.Value(TXSimulatorKey).(ledger.TxSimulator) 606 ctxt = context.WithValue(ctxt, TXSimulatorKey, queryExec) 607 608 //create the response 609 queryStateNextFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 610 qr := &pb.QueryResponse{} 611 proto.Unmarshal(reqMsg.Payload, qr) 612 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_NEXT, Payload: putils.MarshalOrPanic(&pb.QueryStateNext{Id: qr.Id}), Txid: "8"} 613 } 614 queryStateCloseFunc := func(reqMsg *pb.ChaincodeMessage) *pb.ChaincodeMessage { 615 qr := &pb.QueryResponse{} 616 proto.Unmarshal(reqMsg.Payload, qr) 617 return &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_QUERY_STATE_CLOSE, Payload: putils.MarshalOrPanic(&pb.QueryStateClose{Id: qr.Id}), Txid: "8"} 618 } 619 620 respSet := &mockpeer.MockResponseSet{errorFunc, nil, []*mockpeer.MockResponse{ 621 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_TRANSACTION}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_GET_HISTORY_FOR_KEY, Payload: putils.MarshalOrPanic(&pb.GetQueryResult{Query: "goodquery"}), Txid: "8"}}, 622 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, queryStateNextFunc}, 623 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, queryStateNextFunc}, 624 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR}, queryStateCloseFunc}, 625 &mockpeer.MockResponse{&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_RESPONSE}, &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_COMPLETED, Payload: putils.MarshalOrPanic(&pb.Response{Status: shim.OK, Payload: []byte("OK")}), Txid: "8"}}}} 626 627 cccid := ccprovider.NewCCContext(chainID, ccname, "0", "8", false, sprop, prop) 628 execCC(t, ctxt, ccSide, cccid, false, false, done, cis, respSet) 629 630 endTx(t, cccid, txsim, cis) 631 632 return nil 633 } 634 635 func TestCCFramework(t *testing.T) { 636 //register 2 channels 637 chainID := "mockchainid" 638 chainID2 := "secondchain" 639 if err := initMockPeer(chainID, chainID2); err != nil { 640 t.Fatalf("%s", err) 641 } 642 defer finitMockPeer(chainID, chainID2) 643 644 //create a chaincode 645 ccname := "shimTestCC" 646 647 //starts and registers the CC 648 _, ccSide := startCC(t, ccname) 649 if ccSide == nil { 650 t.Fatalf("start up failed") 651 } 652 653 //call's init and does some PUT (after doing some negative testing) 654 initializeCC(t, chainID, ccname, ccSide) 655 656 //chaincode support should not allow dups 657 if err := theChaincodeSupport.registerHandler(&Handler{ChaincodeID: &pb.ChaincodeID{Name: ccname + ":0"}}); err == nil { 658 t.Fatalf("expected re-register to fail") 659 } else if err, _ := err.(*DuplicateChaincodeHandlerError); err == nil { 660 t.Fatalf("expected DuplicateChaincodeHandlerError") 661 } 662 663 //call's init and does some PUT (after doing some negative testing) 664 initializeCC(t, chainID2, ccname, ccSide) 665 666 //call's invoke and do some GET 667 invokeCC(t, chainID, ccname, ccSide) 668 669 //call's query state range 670 getQueryStateByRange(t, chainID, ccname, ccSide) 671 672 //call's cc2cc (variation with syscc calls) 673 cc2cc(t, chainID, chainID2, ccname, ccSide) 674 675 //call's query result 676 getQueryResult(t, chainID, ccname, ccSide) 677 678 //call's history result 679 getHistory(t, chainID, ccname, ccSide) 680 681 ccSide.Quit() 682 }