Skip to content

Commit

Permalink
FAB-1295 - multichannel use chain in chain namespace
Browse files Browse the repository at this point in the history
https://jira.hyperledger.org/browse/FAB-1295

This changeset uses the passed chainID (previous change set
prepared the way by removing DefaultChain and passing
chain ID top down) as as part of the namespace when registering
and launching chaincodes. With that single stroke, the chaincode
framework is ready for multichain.

This change applies to both user and system chaincodes. The endorser
provides the ledger simulation context for the proposal, outside of
chaincodes, so the chaincodes naturally execute on the chain for the
proposal. Given the chaincode execution uses the the ledger context
supplied to it, all is needed a different container for a chaincode
   . to avoid name collision between chaincodes
   . more secure with no fear of leakage

This changeset deliberately does not excercise multichain capabilities.
The intent is to make sure the changes do not break current code.

The next changeset will provide just test cases for executing chaincodes
on multiple chains.

Change-Id: Icab52e015e8d6373ef4056905695e28d8d58b3e5
Signed-off-by: Srinivasan Muralidharan <muralisr@us.ibm.com>
  • Loading branch information
Srinivasan Muralidharan committed Dec 7, 2016
1 parent 71805c9 commit 9dab228
Show file tree
Hide file tree
Showing 12 changed files with 187 additions and 152 deletions.
103 changes: 55 additions & 48 deletions core/chaincode/chaincode_support.go

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion core/chaincode/exectransaction.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func Execute(ctxt context.Context, chainID string, txid string, prop *pb.Proposa
}

if cds != nil {
_, err := theChaincodeSupport.Deploy(ctxt, cds)
_, err := theChaincodeSupport.Deploy(ctxt, chainID, cds)
if err != nil {
return nil, nil, fmt.Errorf("Failed to deploy chaincode spec(%s)", err)
}
Expand Down
131 changes: 66 additions & 65 deletions core/chaincode/exectransaction_test.go

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions core/chaincode/importsysccs.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ func RegisterSysCCs(chainID string) {
//this is used in unit tests to stop and remove the system chaincodes before
//restarting them in the same process. This allows clean start of the system
//in the same process
func deRegisterSysCCs() {
func deRegisterSysCCs(chainID string) {
for _, sysCC := range systemChaincodes {
deregisterSysCC(sysCC)
deregisterSysCC(chainID, sysCC)
}
}
6 changes: 3 additions & 3 deletions core/chaincode/lccc.go
Original file line number Diff line number Diff line change
Expand Up @@ -265,7 +265,7 @@ func (lccc *LifeCycleSysCC) deploy(stub shim.ChaincodeStubInterface, chainname s

ctxt = context.WithValue(ctxt, TXSimulatorKey, dummytxsim)

_, err = theChaincodeSupport.Deploy(ctxt, cds)
_, err = theChaincodeSupport.Deploy(ctxt, chainname, cds)
if err != nil {
return fmt.Errorf("Failed to deploy chaincode spec(%s)", err)
}
Expand All @@ -280,7 +280,7 @@ func (lccc *LifeCycleSysCC) deploy(stub shim.ChaincodeStubInterface, chainname s
}

//stop now that we are done
theChaincodeSupport.Stop(ctxt, cds)
theChaincodeSupport.Stop(ctxt, chainname, cds)

return nil
}
Expand Down Expand Up @@ -371,7 +371,7 @@ func (lccc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) ([]byte, er
cd, _ := lccc.getChaincode(stub, chain, ccname)
if cd == nil {
logger.Debug("ChaincodeID [%s/%s] does not exist", chain, ccname)
return nil, TXNotFoundErr(chain + "/" + ccname)
return nil, TXNotFoundErr(ccname + "/" + chain)
}

if function == GETCCINFO {
Expand Down
4 changes: 2 additions & 2 deletions core/chaincode/sysccapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ func RegisterSysCC(chainID string, syscc *SystemChaincode) error {
}

// deregisterSysCC stops the system chaincode and deregisters it from inproccontroller
func deregisterSysCC(syscc *SystemChaincode) error {
func deregisterSysCC(chainID string, syscc *SystemChaincode) error {
chaincodeID := &pb.ChaincodeID{Path: syscc.Path, Name: syscc.Name}
spec := &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_Type(pb.ChaincodeSpec_Type_value["GOLANG"]), ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: syscc.InitArgs}}

Expand All @@ -109,7 +109,7 @@ func deregisterSysCC(syscc *SystemChaincode) error {

chaincodeSupport := GetChain()
if chaincodeSupport != nil {
err = chaincodeSupport.Stop(ctx, chaincodeDeploymentSpec)
err = chaincodeSupport.Stop(ctx, chainID, chaincodeDeploymentSpec)
}

return err
Expand Down
2 changes: 1 addition & 1 deletion core/chaincode/systemchaincode_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ func TestExecuteDeploySysChaincode(t *testing.T) {

cds := &pb.ChaincodeDeploymentSpec{ExecEnv: 1, ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}}}

theChaincodeSupport.Stop(ctxt, cds)
theChaincodeSupport.Stop(ctxt, chainID, cds)

closeListenerAndSleep(lis)
}
20 changes: 20 additions & 0 deletions core/container/ccintf/ccintf.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ package ccintf
//Currently inproccontroller uses it. dockercontroller does not.

import (
"encoding/hex"

"github.com/hyperledger/fabric/core/util"
pb "github.com/hyperledger/fabric/protos/peer"
"golang.org/x/net/context"
)
Expand All @@ -47,4 +50,21 @@ type CCID struct {
ChaincodeSpec *pb.ChaincodeSpec
NetworkID string
PeerID string
ChainID string
}

//GetName returns canonical chaincode name based on chain name
func (ccid *CCID) GetName() string {
if ccid.ChaincodeSpec == nil {
panic("nil chaincode spec")
}
if ccid.ChainID == "" {
panic("chain id not specified")
}

hash := util.ComputeCryptoHash([]byte(ccid.ChainID))

hexstr := hex.EncodeToString(hash[:])

return ccid.ChaincodeSpec.ChaincodeID.Name + "-" + hexstr
}
8 changes: 5 additions & 3 deletions core/container/dockercontroller/dockercontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -267,11 +267,13 @@ func (vm *DockerVM) Destroy(ctxt context.Context, ccid ccintf.CCID, force bool,
//GetVMName generates the docker image from peer information given the hashcode. This is needed to
//keep image name's unique in a single host, multi-peer environment (such as a development environment)
func (vm *DockerVM) GetVMName(ccid ccintf.CCID) (string, error) {
name := ccid.GetName()

if ccid.NetworkID != "" {
return fmt.Sprintf("%s-%s-%s", ccid.NetworkID, ccid.PeerID, ccid.ChaincodeSpec.ChaincodeID.Name), nil
return fmt.Sprintf("%s-%s-%s", ccid.NetworkID, ccid.PeerID, name), nil
} else if ccid.PeerID != "" {
return fmt.Sprintf("%s-%s", ccid.PeerID, ccid.ChaincodeSpec.ChaincodeID.Name), nil
return fmt.Sprintf("%s-%s", ccid.PeerID, name), nil
} else {
return ccid.ChaincodeSpec.ChaincodeID.Name, nil
return name, nil
}
}
35 changes: 20 additions & 15 deletions core/container/inproccontroller/inproccontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,15 @@ type InprocVM struct {
id string
}

func (vm *InprocVM) getInstance(ctxt context.Context, ipctemplate *inprocContainer, ccid ccintf.CCID, args []string, env []string) (*inprocContainer, error) {
ipc := instRegistry[ccid.ChaincodeSpec.ChaincodeID.Name]
func (vm *InprocVM) getInstance(ctxt context.Context, ipctemplate *inprocContainer, instName string, args []string, env []string) (*inprocContainer, error) {
ipc := instRegistry[instName]
if ipc != nil {
inprocLogger.Warningf("chaincode instance exists for %s", ccid.ChaincodeSpec.ChaincodeID.Name)
inprocLogger.Warningf("chaincode instance exists for %s", instName)
return ipc, nil
}
ipc = &inprocContainer{args: args, env: env, chaincode: ipctemplate.chaincode, stopChan: make(chan struct{})}
instRegistry[ccid.ChaincodeSpec.ChaincodeID.Name] = ipc
inprocLogger.Debugf("chaincode instance created for %s", ccid.ChaincodeSpec.ChaincodeID.Name)
instRegistry[instName] = ipc
inprocLogger.Debugf("chaincode instance created for %s", instName)
return ipc, nil
}

Expand All @@ -92,7 +92,8 @@ func (vm *InprocVM) Deploy(ctxt context.Context, ccid ccintf.CCID, args []string
return fmt.Errorf(fmt.Sprintf("%s system chaincode does not contain chaincode instance", path))
}

_, err := vm.getInstance(ctxt, ipctemplate, ccid, args, env)
instName, _ := vm.GetVMName(ccid)
_, err := vm.getInstance(ctxt, ipctemplate, instName, args, env)

//FUTURE ... here is where we might check code for safety
inprocLogger.Debugf("registered : %s", path)
Expand Down Expand Up @@ -161,10 +162,12 @@ func (vm *InprocVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
return fmt.Errorf(fmt.Sprintf("%s not registered", path))
}

ipc, err := vm.getInstance(ctxt, ipctemplate, ccid, args, env)
instName, _ := vm.GetVMName(ccid)

ipc, err := vm.getInstance(ctxt, ipctemplate, instName, args, env)

if err != nil {
return fmt.Errorf(fmt.Sprintf("could not create instance for %s", ccid.ChaincodeSpec.ChaincodeID.Name))
return fmt.Errorf(fmt.Sprintf("could not create instance for %s", instName))
}

if ipc.running {
Expand All @@ -183,10 +186,10 @@ func (vm *InprocVM) Start(ctxt context.Context, ccid ccintf.CCID, args []string,
go func() {
defer func() {
if r := recover(); r != nil {
inprocLogger.Criticalf("caught panic from chaincode %s", ccid.ChaincodeSpec.ChaincodeID.Name)
inprocLogger.Criticalf("caught panic from chaincode %s", instName)
}
}()
ipc.launchInProc(ctxt, ccid.ChaincodeSpec.ChaincodeID.Name, args, env, ccSupport)
ipc.launchInProc(ctxt, instName, args, env, ccSupport)
}()

return nil
Expand All @@ -201,19 +204,21 @@ func (vm *InprocVM) Stop(ctxt context.Context, ccid ccintf.CCID, timeout uint, d
return fmt.Errorf("%s not registered", path)
}

ipc := instRegistry[ccid.ChaincodeSpec.ChaincodeID.Name]
instName, _ := vm.GetVMName(ccid)

ipc := instRegistry[instName]

if ipc == nil {
return fmt.Errorf("%s not found", ccid.ChaincodeSpec.ChaincodeID.Name)
return fmt.Errorf("%s not found", instName)
}

if !ipc.running {
return fmt.Errorf("%s not running", ccid.ChaincodeSpec.ChaincodeID.Name)
return fmt.Errorf("%s not running", instName)
}

ipc.stopChan <- struct{}{}

delete(instRegistry, ccid.ChaincodeSpec.ChaincodeID.Name)
delete(instRegistry, instName)
//TODO stop
return nil
}
Expand All @@ -226,5 +231,5 @@ func (vm *InprocVM) Destroy(ctxt context.Context, ccid ccintf.CCID, force bool,

//GetVMName ignores the peer and network name as it just needs to be unique in process
func (vm *InprocVM) GetVMName(ccid ccintf.CCID) (string, error) {
return ccid.ChaincodeSpec.ChaincodeID.Name, nil
return ccid.GetName(), nil
}
4 changes: 2 additions & 2 deletions core/endorser/endorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func (*Endorser) getTxSimulator(ledgername string) (ledger.TxSimulator, error) {
func (e *Endorser) deploy(ctxt context.Context, txid string, proposal *pb.Proposal, chainname string, cds *pb.ChaincodeDeploymentSpec, cid *pb.ChaincodeID) error {
chaincodeSupport := chaincode.GetChain()

_, err := chaincodeSupport.Deploy(ctxt, cds)
_, err := chaincodeSupport.Deploy(ctxt, chainname, cds)
if err != nil {
return fmt.Errorf("Failed to deploy chaincode spec(%s)", err)
}
Expand All @@ -79,7 +79,7 @@ func (e *Endorser) deploy(ctxt context.Context, txid string, proposal *pb.Propos
}

//stop now that we are done
chaincodeSupport.Stop(ctxt, cds)
chaincodeSupport.Stop(ctxt, chainname, cds)

return nil
}
Expand Down
20 changes: 10 additions & 10 deletions core/endorser/endorser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,10 @@ func TestDeploy(t *testing.T) {
if err != nil {
t.Fail()
t.Logf("Deploy-error in deploy %s", err)
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
return
}
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
}

//TestDeployBadArgs sets bad args on deploy. It should fail, and example02 should not be deployed
Expand All @@ -257,10 +257,10 @@ func TestDeployBadArgs(t *testing.T) {
if err == nil {
t.Fail()
t.Log("DeployBadArgs-expected error in deploy but succeeded")
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
return
}
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
}

//TestDeployBadPayload set payload to nil and do a deploy. It should fail and example02 should not be deployed
Expand All @@ -276,10 +276,10 @@ func TestDeployBadPayload(t *testing.T) {
if err == nil {
t.Fail()
t.Log("DeployBadPayload-expected error in deploy but succeeded")
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
return
}
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
}

//TestRedeploy - deploy two times, second time should fail but example02 should remain deployed
Expand All @@ -293,7 +293,7 @@ func TestRedeploy(t *testing.T) {
if err != nil {
t.Fail()
t.Logf("error in endorserServer.ProcessProposal %s", err)
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
return
}

Expand All @@ -302,10 +302,10 @@ func TestRedeploy(t *testing.T) {
if err != nil {
t.Fail()
t.Logf("error in endorserServer.ProcessProposal %s", err)
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
return
}
chaincode.GetChain().Stop(context.Background(), &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
chaincode.GetChain().Stop(context.Background(), chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec})
}

// TestDeployAndInvoke deploys and invokes chaincode_example01
Expand Down Expand Up @@ -349,7 +349,7 @@ func TestDeployAndInvoke(t *testing.T) {
fmt.Printf("Invoke test passed\n")
t.Logf("Invoke test passed")

chaincode.GetChain().Stop(ctxt, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: chaincodeID}})
chaincode.GetChain().Stop(ctxt, chainID, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: chaincodeID}})
}

func TestMain(m *testing.M) {
Expand Down

0 comments on commit 9dab228

Please sign in to comment.