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  }