Skip to content

Commit

Permalink
FAB-2081 allow user CC to call system CC
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-2081

Chaincode to chaincode invocation works only if the called chaincode
is a user chaincode. Add the ability to call system chaincode as well
and add a UT for it.

Change-Id: Icbe28493e32f9e98ea7e046fdae3287b16c59cb2
Signed-off-by: Srinivasan Muralidharan <[email protected]>
  • Loading branch information
Srinivasan Muralidharan committed Mar 10, 2017
1 parent 3295920 commit 3169234
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 7 deletions.
65 changes: 65 additions & 0 deletions core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
27 changes: 20 additions & 7 deletions core/chaincode/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 3169234

Please sign in to comment.