diff --git a/core/chaincode/exectransaction_test.go b/core/chaincode/exectransaction_test.go index 8d7699e70eb..fb639187695 100644 --- a/core/chaincode/exectransaction_test.go +++ b/core/chaincode/exectransaction_test.go @@ -1386,6 +1386,71 @@ func TestChaincodeQueryChaincodeUsingInvoke(t *testing.T) { theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec2}) } +// Test the execution of a chaincode that invokes system chaincode +// uses the "pthru" chaincode to query "lccc" for the "pthru" chaincode +func TestChaincodeInvokesSystemChaincode(t *testing.T) { + chainID := util.GetTestChainID() + + lis, err := initPeer(chainID) + if err != nil { + t.Fail() + t.Logf("Error creating peer: %s", err) + } + + defer finitPeer(lis, chainID) + + var ctxt = context.Background() + + var nextBlockNumber uint64 + + // Deploy second chaincode + url := "github.com/hyperledger/fabric/examples/chaincode/go/passthru" + + cID := &pb.ChaincodeID{Name: "pthru", Path: url, Version: "0"} + f := "init" + args := util.ToChaincodeArgs(f) + + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} + + cccid := ccprovider.NewCCContext(chainID, "pthru", "0", "", false, nil, nil) + + _, err = deploy(ctxt, cccid, spec, nextBlockNumber) + nextBlockNumber++ + ccID := spec.ChaincodeId.Name + if err != nil { + t.Fail() + t.Logf("Error initializing chaincode %s(%s)", ccID, err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + return + } + + time.Sleep(time.Second) + + //send an invoke to pass thru to query "lccc" system chaincode on chainID to get + //information about "pthru" + args = util.ToChaincodeArgs("lccc/"+chainID, "getid", chainID, "pthru") + + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeId: cID, Input: &pb.ChaincodeInput{Args: args}} + // Invoke chaincode + _, _, retval, err := invoke(ctxt, chainID, spec, nextBlockNumber) + + if err != nil { + t.Fail() + t.Logf("Error invoking <%s>: %s", ccID, err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + return + } + + if string(retval) != "pthru" { + t.Fail() + t.Logf("Expected to get back \"pthru\" from lccc but got back %s", string(retval)) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + return + } + + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) +} + var signer msp.SigningIdentity func TestMain(m *testing.M) { diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index 22b9644f707..6591e06d883 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -27,6 +27,7 @@ import ( commonledger "github.com/hyperledger/fabric/common/ledger" "github.com/hyperledger/fabric/common/util" "github.com/hyperledger/fabric/core/common/ccprovider" + "github.com/hyperledger/fabric/core/common/sysccprovider" ccintf "github.com/hyperledger/fabric/core/container/ccintf" "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/ledger/ledgerconfig" @@ -1314,15 +1315,27 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) { } //Call LCCC to get the called chaincode artifacts + + //is the chaincode a system chaincode ? + isscc := sysccprovider.GetSystemChaincodeProvider().IsSysCC(calledCcParts.name) + var cd *ccprovider.ChaincodeData - cd, err = GetChaincodeDataFromLCCC(ctxt, msg.Txid, txContext.signedProp, txContext.proposal, calledCcParts.suffix, calledCcParts.name) - if err != nil { - payload := []byte(err.Error()) - chaincodeLogger.Debugf("[%s]Failed to get chaincoed data (%s) for invoked chaincode. Sending %s", - shorttxid(msg.Txid), err, pb.ChaincodeMessage_ERROR) - triggerNextStateMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid} - return + if !isscc { + //if its a user chaincode, get the details from LCCC + //Call LCCC to get the called chaincode artifacts + cd, err = GetChaincodeDataFromLCCC(ctxt, msg.Txid, txContext.signedProp, txContext.proposal, calledCcParts.suffix, calledCcParts.name) + if err != nil { + payload := []byte(err.Error()) + chaincodeLogger.Debugf("[%s]Failed to get chaincoed data (%s) for invoked chaincode. Sending %s", + shorttxid(msg.Txid), err, pb.ChaincodeMessage_ERROR) + triggerNextStateMsg = &pb.ChaincodeMessage{Type: pb.ChaincodeMessage_ERROR, Payload: payload, Txid: msg.Txid} + return + } + } else { + //this is a system cc, just call it directly + cd = &ccprovider.ChaincodeData{Name: calledCcParts.name, Version: util.GetSysCCVersion()} } + cccid := ccprovider.NewCCContext(calledCcParts.suffix, calledCcParts.name, cd.Version, msg.Txid, false, txContext.signedProp, txContext.proposal) // Launch the new chaincode if not already running