From 269379a01ad324b39fffa5905d72099eba97c96a Mon Sep 17 00:00:00 2001 From: Srinivasan Muralidharan Date: Sat, 10 Dec 2016 16:51:25 -0500 Subject: [PATCH] FAB-1318 - complete upgrade from endorser side https://jira.hyperledger.org/browse/FAB-1318 This completes the work begun with https://gerrit.hyperledger.org/r/#/c/2973 https://gerrit.hyperledger.org/r/#/c/2945/. The command peer chaincode upgrade -n mycc -p -c '{"Args":[]}' will upgrade exisisting chaincode "mycc" if one exists. There is still work left on the committer side to comb block for transactions colliding with an upgrade. Upgrade will override those colliding transactions for that . This will be in a future CR when ledger and committer support for this work is available. A chaincode is uniquely identified by (chain name, chaincode name). When upgrading a chaincode, many versions of the chaincode may be running (typically 2, the "current" and the "upgrade" but one can imagine multiple upgrades of the same chaincode in progress. Even if only one will succeed...). When upgrading, LCCC bumps up the version number for that chaincode. This version is used to dissambiguate different versions of the chaincode in a chain, just as chain id dissambiguated the chaincode among different chains. Chaincode framework will panic if version is not specified or not found. Change-Id: Ie0e11cf4ed1263f91c8399021ea65a3e877e08ba Signed-off-by: Srinivasan Muralidharan --- core/chaincode/chaincode_support.go | 31 +-- core/chaincode/chaincodeexec.go | 22 +- core/chaincode/chaincodetest.yaml | 1 + core/chaincode/exectransaction_test.go | 58 ++--- core/chaincode/handler.go | 75 ++++++- core/chaincode/importsysccs.go | 4 +- core/chaincode/lccc.go | 103 +++++---- core/chaincode/multichains_test.go | 2 +- core/chaincode/sysccapi.go | 13 +- core/chaincode/systemchaincode_test.go | 152 +++++++------ core/chaincode/upgrade_test.go | 247 ++++++++++++++++++++++ core/committer/noopssinglechain/client.go | 4 +- core/container/ccintf/ccintf.go | 10 +- core/endorser/endorser.go | 69 ++++-- core/endorser/endorser_test.go | 14 +- core/peer/msgvalidation.go | 2 +- core/util/utils.go | 12 ++ 17 files changed, 610 insertions(+), 209 deletions(-) create mode 100644 core/chaincode/upgrade_test.go diff --git a/core/chaincode/chaincode_support.go b/core/chaincode/chaincode_support.go index 0902130041e..0df51040446 100644 --- a/core/chaincode/chaincode_support.go +++ b/core/chaincode/chaincode_support.go @@ -88,32 +88,34 @@ type CCContext struct { Proposal *pb.Proposal //this is not set but computed (note that this is not exported. use GetCanonicalName) - canName string + canonicalName string } //NewCCContext just construct a new struct with whatever args func NewCCContext(cid, name, version, txid string, syscc bool, prop *pb.Proposal) *CCContext { - var canName string - if version != "" { - canName = name + ":" + version + "/" + cid - } else { - canName = name + "/" + cid + //version CANNOT be empty. The chaincode namespace has to use version and chain name. + //All system chaincodes share the same version given by utils.GetSysCCVersion. Note + //that neither Chain Name or Version are stored in a chaincodes state on the ledger + if version == "" { + panic(fmt.Sprintf("---empty version---(chain=%s,chaincode=%s,version=%s,txid=%s,syscc=%t,proposal=%p", cid, name, version, txid, syscc, prop)) } + canName := name + ":" + version + "/" + cid + cccid := &CCContext{cid, name, version, txid, syscc, prop, canName} - chaincodeLogger.Infof("NewCCCC (chain=%s,chaincode=%s,version=%s,txid=%s,syscc=%t,proposal=%p,canname=%s", cid, name, version, txid, syscc, prop, cccid.canName) + chaincodeLogger.Infof("NewCCCC (chain=%s,chaincode=%s,version=%s,txid=%s,syscc=%t,proposal=%p,canname=%s", cid, name, version, txid, syscc, prop, cccid.canonicalName) return cccid } //GetCanonicalName returns the canonical name associated with the proposal context func (cccid *CCContext) GetCanonicalName() string { - if cccid.canName == "" { + if cccid.canonicalName == "" { panic(fmt.Sprintf("cccid not constructed using NewCCContext(chain=%s,chaincode=%s,version=%s,txid=%s,syscc=%t)", cccid.ChainID, cccid.Name, cccid.Version, cccid.TxID, cccid.Syscc)) } - return cccid.canName + return cccid.canonicalName } // @@ -425,7 +427,7 @@ func (chaincodeSupport *ChaincodeSupport) launchAndWaitForRegister(ctxt context. vmtype, _ := chaincodeSupport.getVMType(cds) - sir := container.StartImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID}, Reader: targz, Args: args, Env: env} + sir := container.StartImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID, Version: cccid.Version}, Reader: targz, Args: args, Env: env} ipcCtxt := context.WithValue(ctxt, ccintf.GetCCHandlerKey(), chaincodeSupport) @@ -468,7 +470,7 @@ func (chaincodeSupport *ChaincodeSupport) Stop(context context.Context, cccid *C } //stop the chaincode - sir := container.StopImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID}, Timeout: 0} + sir := container.StopImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID, Version: cccid.Version}, Timeout: 0} vmtype, _ := chaincodeSupport.getVMType(cds) @@ -548,9 +550,6 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid chaincodeLogger.Error("You are attempting to perform an action other than Deploy on Chaincode that is not ready and you are in developer mode. Did you forget to Deploy your chaincode?") } - //PDMP - panic if not using simulator path - _ = getTxSimulator(context) - var depPayload []byte //hopefully we are restarting from existing image and the deployed transaction exists @@ -563,11 +562,13 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid } cds = &pb.ChaincodeDeploymentSpec{} + //Get lang from original deployment err = proto.Unmarshal(depPayload, cds) if err != nil { return cID, cMsg, fmt.Errorf("failed to unmarshal deployment transactions for %s - %s", canName, err) } + cLang = cds.ChaincodeSpec.Type } @@ -636,7 +637,7 @@ func (chaincodeSupport *ChaincodeSupport) Deploy(context context.Context, cccid } var targz io.Reader = bytes.NewBuffer(cds.CodePackage) - cir := &container.CreateImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID}, Args: args, Reader: targz, Env: envs} + cir := &container.CreateImageReq{CCID: ccintf.CCID{ChaincodeSpec: cds.ChaincodeSpec, NetworkID: chaincodeSupport.peerNetworkID, PeerID: chaincodeSupport.peerID, ChainID: cccid.ChainID, Version: cccid.Version}, Args: args, Reader: targz, Env: envs} vmtype, _ := chaincodeSupport.getVMType(cds) diff --git a/core/chaincode/chaincodeexec.go b/core/chaincode/chaincodeexec.go index 7ab9ac56949..e44bb8e2ad3 100644 --- a/core/chaincode/chaincodeexec.go +++ b/core/chaincode/chaincodeexec.go @@ -21,6 +21,8 @@ import ( "fmt" + "github.com/golang/protobuf/proto" + "github.com/hyperledger/fabric/core/util" pb "github.com/hyperledger/fabric/protos/peer" ) @@ -36,11 +38,29 @@ func createCIS(ccname string, args [][]byte) (*pb.ChaincodeInvocationSpec, error // GetCDSFromLCCC gets chaincode deployment spec from LCCC func GetCDSFromLCCC(ctxt context.Context, txid string, prop *pb.Proposal, chainID string, chaincodeID string) ([]byte, error) { - cccid := NewCCContext(chainID, "lccc", "", txid, true, prop) + version := util.GetSysCCVersion() + cccid := NewCCContext(chainID, "lccc", version, txid, true, prop) payload, _, err := ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getdepspec"), []byte(chainID), []byte(chaincodeID)}) return payload, err } +// GetChaincodeDataFromLCCC gets chaincode data from LCCC given name +func GetChaincodeDataFromLCCC(ctxt context.Context, txid string, prop *pb.Proposal, chainID string, chaincodeID string) (*ChaincodeData, error) { + version := util.GetSysCCVersion() + cccid := NewCCContext(chainID, "lccc", version, txid, true, prop) + payload, _, err := ExecuteChaincode(ctxt, cccid, [][]byte{[]byte("getccdata"), []byte(chainID), []byte(chaincodeID)}) + if err == nil { + cd := &ChaincodeData{} + err = proto.Unmarshal(payload, cd) + if err != nil { + return nil, err + } + return cd, nil + } + + return nil, err +} + // ExecuteChaincode executes a given chaincode given chaincode name and arguments func ExecuteChaincode(ctxt context.Context, cccid *CCContext, args [][]byte) ([]byte, *pb.ChaincodeEvent, error) { var spec *pb.ChaincodeInvocationSpec diff --git a/core/chaincode/chaincodetest.yaml b/core/chaincode/chaincodetest.yaml index fcd132d7d49..a635dcf486d 100644 --- a/core/chaincode/chaincodetest.yaml +++ b/core/chaincode/chaincodetest.yaml @@ -392,6 +392,7 @@ chaincode: # system chaincodes whitelist. To add system chaincode "myscc" to the # whitelist, add "myscc: enable" to the list system: + cscc: enable lccc: enable escc: enable vscc: enable diff --git a/core/chaincode/exectransaction_test.go b/core/chaincode/exectransaction_test.go index 21897cbca0d..2811bb7cdf7 100644 --- a/core/chaincode/exectransaction_test.go +++ b/core/chaincode/exectransaction_test.go @@ -91,6 +91,7 @@ func initPeer(chainIDs ...string) (net.Listener, error) { RegisterSysCCs() for _, id := range chainIDs { + deDeploySysCCs(id) if err = peer.MockCreateChain(id); err != nil { closeListenerAndSleep(lis) return nil, err @@ -106,7 +107,7 @@ func initPeer(chainIDs ...string) (net.Listener, error) { func finitPeer(lis net.Listener, chainIDs ...string) { if lis != nil { for _, c := range chainIDs { - deRegisterSysCCs(c) + deDeploySysCCs(c) if lgr := peer.GetLedger(c); lgr != nil { lgr.Close() } @@ -263,7 +264,8 @@ func deploy2(ctx context.Context, cccid *CCContext, chaincodeDeploymentSpec *pb. } }() - lcccid := NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeID.Name, "", uuid, true, nil) + sysCCVers := util.GetSysCCVersion() + lcccid := NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeID.Name, sysCCVers, uuid, true, nil) //write to lccc if _, _, err = Execute(ctx, lcccid, cis); err != nil { @@ -279,6 +281,11 @@ func deploy2(ctx context.Context, cccid *CCContext, chaincodeDeploymentSpec *pb. // Invoke a chaincode. func invoke(ctx context.Context, chainID string, spec *pb.ChaincodeSpec) (ccevt *pb.ChaincodeEvent, uuid string, retval []byte, err error) { + return invokeWithVersion(ctx, chainID, "0", spec) +} + +// Invoke a chaincode with version (needed for upgrade) +func invokeWithVersion(ctx context.Context, chainID string, version string, spec *pb.ChaincodeSpec) (ccevt *pb.ChaincodeEvent, uuid string, retval []byte, err error) { chaincodeInvocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: spec} // Now create the Transactions message and send to Peer. @@ -301,7 +308,7 @@ func invoke(ctx context.Context, chainID string, spec *pb.ChaincodeSpec) (ccevt } }() - cccid := NewCCContext(chainID, chaincodeInvocationSpec.ChaincodeSpec.ChaincodeID.Name, "", uuid, false, nil) + cccid := NewCCContext(chainID, chaincodeInvocationSpec.ChaincodeSpec.ChaincodeID.Name, version, uuid, false, nil) retval, ccevt, err = Execute(ctx, cccid, chaincodeInvocationSpec) if err != nil { return nil, uuid, nil, fmt.Errorf("Error invoking chaincode: %s ", err) @@ -332,7 +339,7 @@ func executeDeployTransaction(t *testing.T, chainID string, name string, url str args := util.ToChaincodeArgs(f, "a", "100", "b", "200") spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: name, Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} - cccid := NewCCContext(chainID, name, "", "", false, nil) + cccid := NewCCContext(chainID, name, "0", "", false, nil) _, err = deploy(ctxt, cccid, spec) @@ -359,7 +366,7 @@ func chaincodeQueryChaincode(chainID string, user string) error { spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} - cccid1 := NewCCContext(chainID, "example02", "", "", false, nil) + cccid1 := NewCCContext(chainID, "example02", "0", "", false, nil) _, err := deploy(ctxt, cccid1, spec1) @@ -380,7 +387,7 @@ func chaincodeQueryChaincode(chainID string, user string) error { spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} - cccid2 := NewCCContext(chainID, "example05", "", "", false, nil) + cccid2 := NewCCContext(chainID, "example05", "0", "", false, nil) _, err = deploy(ctxt, cccid2, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -479,32 +486,33 @@ func checkFinalState(cccid *CCContext) error { defer txsim.Done() - canName := cccid.GetCanonicalName() + cName := cccid.GetCanonicalName() + // Invoke ledger to get state var Aval, Bval int - resbytes, resErr := txsim.GetState(canName, "a") + resbytes, resErr := txsim.GetState(cccid.Name, "a") if resErr != nil { - return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", canName, resErr) + return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", cName, resErr) } fmt.Printf("Got string: %s\n", string(resbytes)) Aval, resErr = strconv.Atoi(string(resbytes)) if resErr != nil { - return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", canName, resErr) + return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", cName, resErr) } if Aval != 90 { - return fmt.Errorf("Incorrect result. Aval is wrong for <%s>", canName) + return fmt.Errorf("Incorrect result. Aval is wrong for <%s>", cName) } - resbytes, resErr = txsim.GetState(canName, "b") + resbytes, resErr = txsim.GetState(cccid.Name, "b") if resErr != nil { - return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", canName, resErr) + return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", cName, resErr) } Bval, resErr = strconv.Atoi(string(resbytes)) if resErr != nil { - return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", canName, resErr) + return fmt.Errorf("Error retrieving state from ledger for <%s>: %s", cName, resErr) } if Bval != 210 { - return fmt.Errorf("Incorrect result. Bval is wrong for <%s>", canName) + return fmt.Errorf("Incorrect result. Bval is wrong for <%s>", cName) } // Success @@ -576,7 +584,7 @@ func TestExecuteInvokeTransaction(t *testing.T) { var ctxt = context.Background() - cccid := NewCCContext(chainID, "example02", "", "", false, nil) + cccid := NewCCContext(chainID, "example02", "0", "", false, nil) url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" chaincodeID := &pb.ChaincodeID{Name: "example02", Path: url} @@ -642,7 +650,7 @@ func TestExecuteInvokeInvalidTransaction(t *testing.T) { url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" chaincodeID := &pb.ChaincodeID{Name: "example02", Path: url} - cccid := NewCCContext(chainID, "example02", "", "", false, nil) + cccid := NewCCContext(chainID, "example02", "0", "", false, nil) //FAIL, FAIL! args := []string{"x", "-1"} @@ -699,7 +707,7 @@ func chaincodeInvokeChaincode(t *testing.T, chainID string, user string) (err er spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} - cccid1 := NewCCContext(chainID, "example02", "", "", false, nil) + cccid1 := NewCCContext(chainID, "example02", "0", "", false, nil) _, err = deploy(ctxt, cccid1, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -723,7 +731,7 @@ func chaincodeInvokeChaincode(t *testing.T, chainID string, user string) (err er spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}, SecureContext: user} - cccid2 := NewCCContext(chainID, "example04", "", "", false, nil) + cccid2 := NewCCContext(chainID, "example04", "0", "", false, nil) _, err = deploy(ctxt, cccid2, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -798,7 +806,7 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) { spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}} - cccid1 := NewCCContext(chainID, "example02", "", "", false, nil) + cccid1 := NewCCContext(chainID, "example02", "0", "", false, nil) _, err = deploy(ctxt, cccid1, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -820,7 +828,7 @@ func TestChaincodeInvokeChaincodeErrorCase(t *testing.T) { spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} - cccid2 := NewCCContext(chainID, "pthru", "", "", false, nil) + cccid2 := NewCCContext(chainID, "pthru", "0", "", false, nil) _, err = deploy(ctxt, cccid2, spec2) chaincodeID2 := spec2.ChaincodeID.Name @@ -887,7 +895,7 @@ func TestRangeQuery(t *testing.T) { spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: args}} - cccid := NewCCContext(chainID, "tmap", "", "", false, nil) + cccid := NewCCContext(chainID, "tmap", "0", "", false, nil) _, err = deploy(ctxt, cccid, spec) chaincodeID := spec.ChaincodeID.Name @@ -933,7 +941,7 @@ func TestGetEvent(t *testing.T) { f := "init" spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID, CtorMsg: &pb.ChaincodeInput{Args: util.ToChaincodeArgs(f)}} - cccid := NewCCContext(chainID, "esender", "", "", false, nil) + cccid := NewCCContext(chainID, "esender", "0", "", false, nil) _, err = deploy(ctxt, cccid, spec) chaincodeID := spec.ChaincodeID.Name @@ -1002,7 +1010,7 @@ func TestChaincodeQueryChaincodeUsingInvoke(t *testing.T) { spec1 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID1, CtorMsg: &pb.ChaincodeInput{Args: args}} - cccid1 := NewCCContext(chainID, "example02", "", "", false, nil) + cccid1 := NewCCContext(chainID, "example02", "0", "", false, nil) _, err = deploy(ctxt, cccid1, spec1) chaincodeID1 := spec1.ChaincodeID.Name @@ -1024,7 +1032,7 @@ func TestChaincodeQueryChaincodeUsingInvoke(t *testing.T) { spec2 := &pb.ChaincodeSpec{Type: 1, ChaincodeID: cID2, CtorMsg: &pb.ChaincodeInput{Args: args}} - cccid2 := NewCCContext(chainID, "example05", "", "", false, nil) + cccid2 := NewCCContext(chainID, "example05", "0", "", false, nil) _, err = deploy(ctxt, cccid2, spec2) chaincodeID2 := spec2.ChaincodeID.Name diff --git a/core/chaincode/handler.go b/core/chaincode/handler.go index fa00be725a7..fb51b898206 100644 --- a/core/chaincode/handler.go +++ b/core/chaincode/handler.go @@ -17,6 +17,7 @@ limitations under the License. package chaincode import ( + "bytes" "fmt" "io" "sync" @@ -28,7 +29,7 @@ import ( "github.com/hyperledger/fabric/core/util" pb "github.com/hyperledger/fabric/protos/peer" "github.com/looplab/fsm" - "github.com/op/go-logging" + logging "github.com/op/go-logging" "golang.org/x/net/context" ) @@ -68,6 +69,14 @@ type nextStateInfo struct { sendToCC bool } +//chaincode registered name is of the form +// :/ +type ccParts struct { + name string //the main name of the chaincode + version string //the version param if any (used for upgrade) + suffix string //for now just the chain name +} + // Handler responsbile for management of Peer's side of chaincode stream type Handler struct { sync.RWMutex @@ -76,6 +85,7 @@ type Handler struct { ChatStream ccintf.ChaincodeStream FSM *fsm.FSM ChaincodeID *pb.ChaincodeID + ccCompParts *ccParts chaincodeSupport *ChaincodeSupport registered bool @@ -97,6 +107,44 @@ func shorttxid(txid string) string { return txid[0:8] } +//gets component parts from the canonical name of the chaincode. +//Called exactly once per chaincode when registering chaincode. +//This is needed for the "one-instance-per-chain" model when +//starting up the chaincode for each chain. It will still +//work for the "one-instance-for-all-chains" as the version +//and suffix will just be absent (also note that LCCC reserves +//"/:[]${}" as special chars mainly for such namespace uses) +func (handler *Handler) decomposeRegisteredName(cid *pb.ChaincodeID) { + handler.ccCompParts = &ccParts{} + b := []byte(cid.Name) + + //compute suffix (ie, chain name) + i := bytes.IndexByte(b, '/') + if i >= 0 { + if i < len(b)-1 { + handler.ccCompParts.suffix = string(b[i+1:]) + } + b = b[:i] + } + + //compute version + i = bytes.IndexByte(b, ':') + if i >= 0 { + if i < len(b)-1 { + handler.ccCompParts.version = string(b[i+1:]) + } + b = b[:i] + } + + handler.ccCompParts.name = string(b) + + return +} + +func (handler *Handler) getCCRootName() string { + return handler.ccCompParts.name +} + func (handler *Handler) serialSend(msg *pb.ChaincodeMessage) error { handler.serialLock.Lock() defer handler.serialLock.Unlock() @@ -424,6 +472,10 @@ func (handler *Handler) beforeRegisterEvent(e *fsm.Event, state string) { return } + //get the component parts so we can use the root chaincode + //name in keys + handler.decomposeRegisteredName(handler.ChaincodeID) + chaincodeLogger.Debugf("Got %s for chaincodeID = %s, sending back %s", e.Event, chaincodeID, pb.ChaincodeMessage_REGISTERED) if err := handler.serialSend(&pb.ChaincodeMessage{Type: pb.ChaincodeMessage_REGISTERED}); err != nil { e.Cancel(fmt.Errorf("Error sending %s: %s", pb.ChaincodeMessage_REGISTERED, err)) @@ -517,7 +569,7 @@ func (handler *Handler) handleGetState(msg *pb.ChaincodeMessage) { key := string(msg.Payload) // Invoke ledger to get state - chaincodeID := handler.ChaincodeID.Name + chaincodeID := handler.getCCRootName() var res []byte var err error @@ -603,7 +655,7 @@ func (handler *Handler) handleRangeQueryState(msg *pb.ChaincodeMessage) { if txContext == nil { return } - chaincodeID := handler.ChaincodeID.Name + chaincodeID := handler.getCCRootName() rangeIter, err := txContext.txsimulator.GetStateRangeScanIterator(chaincodeID, rangeQueryState.StartKey, rangeQueryState.EndKey) if err != nil { @@ -882,7 +934,7 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) { handler.triggerNextState(triggerNextStateMsg, true) }() - chaincodeID := handler.ChaincodeID.Name + chaincodeID := handler.getCCRootName() var err error var res []byte @@ -925,8 +977,8 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) { } // Get the chaincodeID to invoke - newChaincodeID := chaincodeSpec.ChaincodeID.Name - chaincodeLogger.Debugf("[%s] C-call-C %s", shorttxid(msg.Txid), newChaincodeID) + calledCCName := chaincodeSpec.ChaincodeID.Name + chaincodeLogger.Debugf("[%s] C-call-C %s", shorttxid(msg.Txid), calledCCName) ctxt := context.Background() ctxt = context.WithValue(ctxt, TXSimulatorKey, txContext.txsimulator) @@ -934,8 +986,15 @@ func (handler *Handler) enterBusyState(e *fsm.Event, state string) { // Create the invocation spec chaincodeInvocationSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: chaincodeSpec} - //Get the latest version of newChaincodeID - cccid := NewCCContext(txContext.chainID, newChaincodeID, "", msg.Txid, false, txContext.proposal) + //Get the latest version of calledCCName + cd, err := GetChaincodeDataFromLCCC(ctxt, msg.Txid, txContext.proposal, txContext.chainID, calledCCName) + 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 + } + cccid := NewCCContext(txContext.chainID, calledCCName, cd.Version, msg.Txid, false, txContext.proposal) // Launch the new chaincode if not already running _, chaincodeInput, launchErr := handler.chaincodeSupport.Launch(ctxt, cccid, chaincodeInvocationSpec) diff --git a/core/chaincode/importsysccs.go b/core/chaincode/importsysccs.go index 317d8831ffc..2406d23d79b 100644 --- a/core/chaincode/importsysccs.go +++ b/core/chaincode/importsysccs.go @@ -89,10 +89,10 @@ func DeployChainlessSysCCs() { //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(chainID string) { +func deDeploySysCCs(chainID string) { for _, sysCC := range systemChaincodes { if !sysCC.ChainlessCC { - deregisterSysCC(chainID, sysCC) + deDeploySysCC(chainID, sysCC) } } } diff --git a/core/chaincode/lccc.go b/core/chaincode/lccc.go index 4e60f6426b6..a4cb5390f9f 100644 --- a/core/chaincode/lccc.go +++ b/core/chaincode/lccc.go @@ -18,6 +18,7 @@ package chaincode import ( "fmt" + "strconv" "strings" "github.com/golang/protobuf/proto" @@ -30,20 +31,26 @@ import ( "golang.org/x/net/context" ) -//define the datastructure for chaincodes to be serialized by proto -type chaincodeData struct { - name string `protobuf:"bytes,1,opt,name=name"` - version int32 `protobuf:"varint,2,opt,name=version,proto3"` - depSpec []byte `protobuf:"bytes,3,opt,name=depSpec,proto3"` - escc string `protobuf:"bytes,4,opt,name=escc"` - vscc string `protobuf:"bytes,5,opt,name=vscc"` - policy []byte `protobuf:"bytes,6,opt,name=policy"` +//ChaincodeData defines the datastructure for chaincodes to be serialized by proto +type ChaincodeData struct { + Name string `protobuf:"bytes,1,opt,name=name"` + Version string `protobuf:"bytes,2,opt,name=version"` + DepSpec []byte `protobuf:"bytes,3,opt,name=depSpec,proto3"` + Escc string `protobuf:"bytes,4,opt,name=escc"` + Vscc string `protobuf:"bytes,5,opt,name=vscc"` + Policy []byte `protobuf:"bytes,6,opt,name=policy"` } //implement functions needed from proto.Message for proto's mar/unmarshal functions -func (cd *chaincodeData) Reset() { *cd = chaincodeData{} } -func (cd *chaincodeData) String() string { return proto.CompactTextString(cd) } -func (*chaincodeData) ProtoMessage() {} + +//Reset resets +func (cd *ChaincodeData) Reset() { *cd = ChaincodeData{} } + +//String convers to string +func (cd *ChaincodeData) String() string { return proto.CompactTextString(cd) } + +//ProtoMessage just exists to make proto happy +func (*ChaincodeData) ProtoMessage() {} //The life cycle system chaincode manages chaincodes deployed //on this peer. It manages chaincodes via Invoke proposals. @@ -72,11 +79,14 @@ const ( //GETDEPSPEC get ChaincodeDeploymentSpec GETDEPSPEC = "getdepspec" + //GETCCDATA get ChaincodeData + GETCCDATA = "getccdata" + //characters used in chaincodenamespace specialChars = "/:[]${}" // chaincode version when deploy - startVersion = 0 + startVersion = "0" ) //---------- the LCCC ----------------- @@ -173,18 +183,18 @@ func (m MarshallErr) Error() string { //-------------- helper functions ------------------ //create the chaincode on the given chain -func (lccc *LifeCycleSysCC) createChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, cccode []byte) (*chaincodeData, error) { +func (lccc *LifeCycleSysCC) createChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, cccode []byte) (*ChaincodeData, error) { return lccc.putChaincodeData(stub, chainname, ccname, startVersion, cccode) } //upgrade the chaincode on the given chain -func (lccc *LifeCycleSysCC) upgradeChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version int32, cccode []byte) (*chaincodeData, error) { +func (lccc *LifeCycleSysCC) upgradeChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte) (*ChaincodeData, error) { return lccc.putChaincodeData(stub, chainname, ccname, version, cccode) } //create the chaincode on the given chain -func (lccc *LifeCycleSysCC) putChaincodeData(stub shim.ChaincodeStubInterface, chainname string, ccname string, version int32, cccode []byte) (*chaincodeData, error) { - cd := &chaincodeData{name: ccname, version: version, depSpec: cccode} +func (lccc *LifeCycleSysCC) putChaincodeData(stub shim.ChaincodeStubInterface, chainname string, ccname string, version string, cccode []byte) (*ChaincodeData, error) { + cd := &ChaincodeData{Name: ccname, Version: version, DepSpec: cccode} cdbytes, err := proto.Marshal(cd) if err != nil { return nil, err @@ -200,23 +210,23 @@ func (lccc *LifeCycleSysCC) putChaincodeData(stub shim.ChaincodeStubInterface, c } //checks for existence of chaincode on the given chain -func (lccc *LifeCycleSysCC) getChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string) (*chaincodeData, error) { +func (lccc *LifeCycleSysCC) getChaincode(stub shim.ChaincodeStubInterface, chainname string, ccname string) (*ChaincodeData, []byte, error) { cdbytes, err := stub.GetState(ccname) if err != nil { - return nil, err + return nil, nil, err } if cdbytes != nil { - cd := &chaincodeData{} + cd := &ChaincodeData{} err = proto.Unmarshal(cdbytes, cd) if err != nil { - return nil, MarshallErr(ccname) + return nil, nil, MarshallErr(ccname) } - return cd, nil + return cd, cdbytes, nil } - return nil, nil + return nil, nil, NotFoundErr(ccname) } //getChaincodeDeploymentSpec returns a ChaincodeDeploymentSpec given args @@ -261,7 +271,7 @@ func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodename string) bool { } //deploy the chaincode on to the chain -func (lccc *LifeCycleSysCC) deploy(stub shim.ChaincodeStubInterface, chainname string, cds *pb.ChaincodeDeploymentSpec) error { +func (lccc *LifeCycleSysCC) deploy(stub shim.ChaincodeStubInterface, chainname string, version string, cds *pb.ChaincodeDeploymentSpec) error { //if unit testing, just return..we cannot do the actual deploy if _, ismock := stub.(*shim.MockStub); ismock { //we got this far just stop short of actual deploy for test purposes @@ -293,7 +303,7 @@ func (lccc *LifeCycleSysCC) deploy(stub shim.ChaincodeStubInterface, chainname s txid := util.GenerateUUID() //deploy does not need a version - cccid := NewCCContext(chainname, cds.ChaincodeSpec.ChaincodeID.Name, "", txid, false, nil) + cccid := NewCCContext(chainname, cds.ChaincodeSpec.ChaincodeID.Name, startVersion, txid, false, nil) _, err = theChaincodeSupport.Deploy(ctxt, cccid, cds) if err != nil { @@ -328,7 +338,7 @@ func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chai return err } - cd, err := lccc.getChaincode(stub, chainname, cds.ChaincodeSpec.ChaincodeID.Name) + cd, _, err := lccc.getChaincode(stub, chainname, cds.ChaincodeSpec.ChaincodeID.Name) if cd != nil { return ExistsErr(cds.ChaincodeSpec.ChaincodeID.Name) } @@ -336,7 +346,7 @@ func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chai /**TODO - this is done in the endorser service for now so we can * collect all state changes under one TXSim. Revisit this ... * maybe this *is* the right solution - *if err = lccc.deploy(stub, chainname, cds); err != nil { + *if err = lccc.deploy(stub, chainname, version, cds); err != nil { * return err *} **/ @@ -353,30 +363,45 @@ func (lccc *LifeCycleSysCC) executeUpgrade(stub shim.ChaincodeStubInterface, cha return nil, err } + if err = lccc.acl(stub, chainName, cds); err != nil { + return nil, err + } + chaincodeName := cds.ChaincodeSpec.ChaincodeID.Name if !lccc.isValidChaincodeName(chaincodeName) { return nil, InvalidChaincodeNameErr(chaincodeName) } // check for existence of chaincode - cd, err := lccc.getChaincode(stub, chainName, chaincodeName) + cd, _, err := lccc.getChaincode(stub, chainName, chaincodeName) if cd == nil { return nil, NotFoundErr(chainName) } - if err = lccc.acl(stub, chainName, cds); err != nil { - return nil, err + // if (ever) we allow users to specify a "deployed" version, this will have to change so + // accept that. We might then require that users provide an "upgrade" version too. In + // that case we'd replace the increment below with a uniqueness check. For now we will + // assume Version is internal and is a number. + // + // NOTE - system chaincodes use the fabric's version and hence are not numbers. + // As they cannot be "upgraded" via LCCC, that's not an issue. But they do help illustrate + // the kind of issues we will have if we allow users to specify version. + v, err := strconv.ParseInt(cd.Version, 10, 32) + + //This should never happen as long we don't expose version as version is computed internally + //so panic till we find a need to relax + if err != nil { + panic(fmt.Sprintf("invalid version %s/%s [err: %s]", chaincodeName, chainName, err)) } - // replace the ChaincodeDeploymentSpec - newVersion := cd.version + 1 + // replace the ChaincodeDeploymentSpec using the next version + newVersion := fmt.Sprintf("%d", (v + 1)) newCD, err := lccc.upgradeChaincode(stub, chainName, chaincodeName, newVersion, code) if err != nil { return nil, err } - strVer := fmt.Sprint(newCD.version) - return []byte(strVer), nil + return []byte(newCD.Version), nil } //-------------- the chaincode stub interface implementation ---------- @@ -431,7 +456,7 @@ func (lccc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) ([]byte, er code := args[2] return lccc.executeUpgrade(stub, chainname, code) - case GETCCINFO, GETDEPSPEC: + case GETCCINFO, GETDEPSPEC, GETCCDATA: if len(args) != 3 { return nil, InvalidArgsLenErr(len(args)) } @@ -440,16 +465,18 @@ func (lccc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) ([]byte, er ccname := string(args[2]) //get chaincode given - cd, _ := lccc.getChaincode(stub, chain, ccname) - if cd == nil { + cd, cdbytes, _ := lccc.getChaincode(stub, chain, ccname) + if cd == nil || cdbytes == nil { logger.Debug("ChaincodeID [%s/%s] does not exist", chain, ccname) return nil, TXNotFoundErr(ccname + "/" + chain) } if function == GETCCINFO { - return []byte(cd.name), nil + return []byte(cd.Name), nil + } else if function == GETCCDATA { + return cdbytes, nil } - return cd.depSpec, nil + return cd.DepSpec, nil } return nil, InvalidFunctionErr(function) diff --git a/core/chaincode/multichains_test.go b/core/chaincode/multichains_test.go index 48ade3d30fc..a3b3a97f301 100644 --- a/core/chaincode/multichains_test.go +++ b/core/chaincode/multichains_test.go @@ -41,7 +41,7 @@ func TestExecuteInvokeOnManyChains(t *testing.T) { args := []string{"a", "b", "10"} for _, c := range chains { - cccid := NewCCContext(c, "example02", "", "", false, nil) + cccid := NewCCContext(c, "example02", "0", "", false, nil) err = invokeExample02Transaction(ctxt, cccid, chaincodeID, args, false) if err != nil { t.Fail() diff --git a/core/chaincode/sysccapi.go b/core/chaincode/sysccapi.go index bd19b504eea..00ac8870db8 100644 --- a/core/chaincode/sysccapi.go +++ b/core/chaincode/sysccapi.go @@ -26,6 +26,7 @@ import ( "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/peer" "github.com/hyperledger/fabric/core/util" + "github.com/op/go-logging" "github.com/spf13/viper" @@ -62,7 +63,7 @@ type SystemChaincode struct { // RegisterSysCC registers the given system chaincode with the peer func RegisterSysCC(syscc *SystemChaincode) error { if !syscc.Enabled || !isWhitelisted(syscc) { - sysccLogger.Info(fmt.Sprintf("system chaincode (%s,%s) disabled", syscc.Name, syscc.Path)) + sysccLogger.Info(fmt.Sprintf("system chaincode (%s,%s,%t) disabled", syscc.Name, syscc.Path, syscc.Enabled)) return nil } @@ -121,7 +122,8 @@ func deploySysCC(chainID string, syscc *SystemChaincode) error { txid := util.GenerateUUID() - cccid := NewCCContext(chainID, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name, "", txid, true, nil) + version := util.GetSysCCVersion() + cccid := NewCCContext(chainID, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name, version, txid, true, nil) _, _, err = Execute(ctxt, cccid, chaincodeDeploymentSpec) @@ -130,8 +132,8 @@ func deploySysCC(chainID string, syscc *SystemChaincode) error { return err } -// deregisterSysCC stops the system chaincode and deregisters it from inproccontroller -func deregisterSysCC(chainID string, syscc *SystemChaincode) error { +// deDeploySysCC stops the system chaincode and deregisters it from inproccontroller +func deDeploySysCC(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}} @@ -146,7 +148,8 @@ func deregisterSysCC(chainID string, syscc *SystemChaincode) error { chaincodeSupport := GetChain() if chaincodeSupport != nil { - cccid := NewCCContext(chainID, syscc.Name, "", "", true, nil) + version := util.GetSysCCVersion() + cccid := NewCCContext(chainID, syscc.Name, version, "", true, nil) err = chaincodeSupport.Stop(ctx, cccid, chaincodeDeploymentSpec) } diff --git a/core/chaincode/systemchaincode_test.go b/core/chaincode/systemchaincode_test.go index 4b8755ac85f..37eaf0d9cb1 100644 --- a/core/chaincode/systemchaincode_test.go +++ b/core/chaincode/systemchaincode_test.go @@ -31,42 +31,17 @@ import ( "google.golang.org/grpc" ) -func deploySampleSysCC(t *testing.T, ctxt context.Context, chainID string) error { - DeploySysCCs(chainID) - - url := "github.com/hyperledger/fabric/core/system_chaincode/sample_syscc" - - cdsforStop := &pb.ChaincodeDeploymentSpec{ExecEnv: 1, ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}} - - f := "putval" - args := util.ToChaincodeArgs(f, "greeting", "hey there") - - spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} - _, _, _, err := invoke(ctxt, chainID, spec) - cccid := NewCCContext(chainID, "sample_syscc", "", "", true, nil) - if err != nil { - theChaincodeSupport.Stop(ctxt, cccid, cdsforStop) - t.Logf("Error invoking sample_syscc: %s", err) - return err - } - - f = "getval" - args = util.ToChaincodeArgs(f, "greeting") - spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} - _, _, _, err = invoke(ctxt, chainID, spec) - if err != nil { - theChaincodeSupport.Stop(ctxt, cccid, cdsforStop) - t.Logf("Error invoking sample_syscc: %s", err) - return err - } - - theChaincodeSupport.Stop(ctxt, cccid, cdsforStop) +type oldSysCCInfo struct { + origSystemCC []*SystemChaincode + origSysCCWhitelist map[string]string +} - return nil +func (osyscc *oldSysCCInfo) reset() { + systemChaincodes = osyscc.origSystemCC + viper.Set("chaincode.system", osyscc.origSysCCWhitelist) } -// Test deploy of a transaction. -func TestExecuteDeploySysChaincode(t *testing.T) { +func initSysCCTests() (*oldSysCCInfo, net.Listener, error) { var opts []grpc.ServerOption grpcServer := grpc.NewServer(opts...) viper.Set("peer.fileSystemPath", "/var/hyperledger/test/tmpdb") @@ -80,9 +55,7 @@ func TestExecuteDeploySysChaincode(t *testing.T) { peerAddress := "0.0.0.0:21726" lis, err := net.Listen("tcp", peerAddress) if err != nil { - t.Fail() - t.Logf("Error starting peer listener %s", err) - return + return nil, nil, err } getPeerEndpoint := func() (*pb.PeerEndpoint, error) { @@ -94,7 +67,7 @@ func TestExecuteDeploySysChaincode(t *testing.T) { go grpcServer.Serve(lis) - var ctxt = context.Background() + sysccinfo := &oldSysCCInfo{systemChaincodes, viper.GetStringMapString("chaincode.system")} //set systemChaincodes to sample systemChaincodes = []*SystemChaincode{ @@ -110,17 +83,71 @@ func TestExecuteDeploySysChaincode(t *testing.T) { // System chaincode has to be enabled viper.Set("chaincode.system", map[string]string{"sample_syscc": "true"}) - chainID := util.GetTestChainID() - RegisterSysCCs() /////^^^ system initialization completed ^^^ + return sysccinfo, lis, nil +} + +func deploySampleSysCC(t *testing.T, ctxt context.Context, chainID string) error { + DeploySysCCs(chainID) + + url := "github.com/hyperledger/fabric/core/system_chaincode/sample_syscc" + + cdsforStop := &pb.ChaincodeDeploymentSpec{ExecEnv: 1, ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}} + + f := "putval" + args := util.ToChaincodeArgs(f, "greeting", "hey there") + + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} + + sysCCVers := util.GetSysCCVersion() + + _, _, _, err := invokeWithVersion(ctxt, chainID, sysCCVers, spec) + + cccid := NewCCContext(chainID, "sample_syscc", sysCCVers, "", true, nil) + if err != nil { + theChaincodeSupport.Stop(ctxt, cccid, cdsforStop) + t.Logf("Error invoking sample_syscc: %s", err) + return err + } + + f = "getval" + args = util.ToChaincodeArgs(f, "greeting") + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "sample_syscc", Path: url}, CtorMsg: &pb.ChaincodeInput{Args: args}} + _, _, _, err = invokeWithVersion(ctxt, chainID, sysCCVers, spec) + if err != nil { + theChaincodeSupport.Stop(ctxt, cccid, cdsforStop) + t.Logf("Error invoking sample_syscc: %s", err) + return err + } + + theChaincodeSupport.Stop(ctxt, cccid, cdsforStop) + + return nil +} + +// Test deploy of a transaction. +func TestExecuteDeploySysChaincode(t *testing.T) { + sysccinfo, lis, err := initSysCCTests() + if err != nil { + t.Fail() + return + } + + defer func() { + sysccinfo.reset() + }() + + chainID := util.GetTestChainID() if err = peer.MockCreateChain(chainID); err != nil { closeListenerAndSleep(lis) return } + var ctxt = context.Background() + err = deploySampleSysCC(t, ctxt, chainID) if err != nil { closeListenerAndSleep(lis) @@ -133,52 +160,15 @@ func TestExecuteDeploySysChaincode(t *testing.T) { // Test multichains func TestMultichains(t *testing.T) { - var opts []grpc.ServerOption - grpcServer := grpc.NewServer(opts...) - viper.Set("peer.fileSystemPath", "/var/hyperledger/test/tmpdb") - defer os.RemoveAll("/var/hyperledger/test/tmpdb") - - peer.MockInitialize() - - //use a different address than what we usually use for "peer" - //we override the peerAddress set in chaincode_support.go - // FIXME: Use peer.GetLocalAddress() - peerAddress := "0.0.0.0:21726" - lis, err := net.Listen("tcp", peerAddress) + sysccinfo, lis, err := initSysCCTests() if err != nil { t.Fail() - t.Logf("Error starting peer listener %s", err) return } - getPeerEndpoint := func() (*pb.PeerEndpoint, error) { - return &pb.PeerEndpoint{ID: &pb.PeerID{Name: "testpeer"}, Address: peerAddress}, nil - } - - ccStartupTimeout := time.Duration(5000) * time.Millisecond - pb.RegisterChaincodeSupportServer(grpcServer, NewChaincodeSupport(getPeerEndpoint, false, ccStartupTimeout)) - - go grpcServer.Serve(lis) - - var ctxt = context.Background() - - //set systemChaincodes to sample - systemChaincodes = []*SystemChaincode{ - { - Enabled: true, - Name: "sample_syscc", - Path: "github.com/hyperledger/fabric/core/system_chaincode/samplesyscc", - InitArgs: [][]byte{}, - Chaincode: &samplesyscc.SampleSysCC{}, - }, - } - - // System chaincode has to be enabled - viper.Set("chaincode.system", map[string]string{"sample_syscc": "true"}) - - RegisterSysCCs() - - /////^^^ system initialization completed ^^^ + defer func() { + sysccinfo.reset() + }() chainID := "chain1" @@ -187,6 +177,8 @@ func TestMultichains(t *testing.T) { return } + var ctxt = context.Background() + err = deploySampleSysCC(t, ctxt, chainID) if err != nil { closeListenerAndSleep(lis) diff --git a/core/chaincode/upgrade_test.go b/core/chaincode/upgrade_test.go new file mode 100644 index 00000000000..ffba90f12c4 --- /dev/null +++ b/core/chaincode/upgrade_test.go @@ -0,0 +1,247 @@ +/* +Copyright IBM Corp. 2016 All Rights Reserved. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package chaincode + +import ( + "fmt" + "strings" + "testing" + + "github.com/hyperledger/fabric/core/util" + pb "github.com/hyperledger/fabric/protos/peer" + + "github.com/golang/protobuf/proto" + "golang.org/x/net/context" +) + +//getUpgradeLCCCSpec gets the spec for the chaincode upgrade to be sent to LCCC +func getUpgradeLCCCSpec(chainID string, cds *pb.ChaincodeDeploymentSpec) (*pb.ChaincodeInvocationSpec, error) { + b, err := proto.Marshal(cds) + if err != nil { + return nil, err + } + + //wrap the deployment in an invocation spec to lccc... + lcccSpec := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Name: "lccc"}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("upgrade"), []byte(chainID), b}}}} + + return lcccSpec, nil +} + +// upgrade a chaincode - i.e., build and initialize. +func upgrade(ctx context.Context, cccid *CCContext, spec *pb.ChaincodeSpec) (*CCContext, error) { + // First build and get the deployment spec + chaincodeDeploymentSpec, err := getDeploymentSpec(ctx, spec) + if err != nil { + return nil, err + } + + return upgrade2(ctx, cccid, chaincodeDeploymentSpec) +} + +func upgrade2(ctx context.Context, cccid *CCContext, chaincodeDeploymentSpec *pb.ChaincodeDeploymentSpec) (*CCContext, error) { + cis, err := getUpgradeLCCCSpec(cccid.ChainID, chaincodeDeploymentSpec) + if err != nil { + return nil, fmt.Errorf("Error creating lccc spec : %s\n", err) + } + + ctx, txsim, err := startTxSimulation(ctx, cccid.ChainID) + if err != nil { + return nil, fmt.Errorf("Failed to get handle to simulator: %s ", err) + } + + uuid := util.GenerateUUID() + + cccid.TxID = uuid + + defer func() { + //no error, lets try commit + if err == nil { + //capture returned error from commit + err = endTxSimulationCDS(cccid.ChainID, uuid, txsim, []byte("upgraded"), true, chaincodeDeploymentSpec) + } else { + //there was an error, just close simulation and return that + endTxSimulationCDS(cccid.ChainID, uuid, txsim, []byte("upgraded"), false, chaincodeDeploymentSpec) + } + }() + + sysCCVers := util.GetSysCCVersion() + lcccid := NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeID.Name, sysCCVers, uuid, true, nil) + + var versionBytes []byte + //write to lccc + if versionBytes, _, err = Execute(ctx, lcccid, cis); err != nil { + return nil, fmt.Errorf("Error executing LCCC for upgrade: %s", err) + } + + if versionBytes == nil { + return nil, fmt.Errorf("Expected version back from LCCC but got nil") + } + + newVersion := string(versionBytes) + if newVersion == cccid.Version { + return nil, fmt.Errorf("Expected new version from LCCC but got same %s(%s)", newVersion, cccid.Version) + } + + newcccid := NewCCContext(cccid.ChainID, chaincodeDeploymentSpec.ChaincodeSpec.ChaincodeID.Name, newVersion, uuid, false, nil) + + if _, _, err = Execute(ctx, newcccid, chaincodeDeploymentSpec); err != nil { + return nil, fmt.Errorf("Error deploying chaincode for upgrade: %s", err) + } + + return newcccid, nil +} + +//TestUpgradeCC - test basic upgrade +// deploy example01 +// do a query against 01 that'll fail +// upgrade to exampl02 +// show the upgrade worked using the same query successfully +//This test a variety of things in addition to basic upgrade +// uses next version from lccc +// re-initializtion of the same chaincode "mycc" +// upgrade when "mycc" is up and running (test version based namespace) +func TestUpgradeCC(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() + + ccName := "mycc" + url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01" + chaincodeID := &pb.ChaincodeID{Name: ccName, Path: url} + + f := "init" + args := util.ToChaincodeArgs(f, "a", "100", "b", "200") + + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: args}} + + cccid := NewCCContext(chainID, ccName, "0", "", false, nil) + _, err = deploy(ctxt, cccid, spec) + + if err != nil { + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + t.Fail() + t.Logf("Error deploying chaincode %s(%s)", chaincodeID, err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: chaincodeID}}) + return + } + + // Query example01, which should fail + qArgs := util.ToChaincodeArgs("query", "a") + + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: qArgs}} + + _, _, _, err = invoke(ctxt, chainID, spec) + if err == nil { + t.Fail() + t.Logf("querying chaincode exampl01 should fail transaction: %s", err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: chaincodeID}}) + return + } else if !strings.Contains(err.Error(), "Invalid invoke function name. Expecting \"invoke\"") { + t.Fail() + t.Logf("expected found <%s>", err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{ChaincodeID: chaincodeID}}) + return + } + + //now upgrade to example02 which takes the same args as example01 but inits state vars + //and also allows query. + url = "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + + //Note ccName hasn't changed... + chaincodeID = &pb.ChaincodeID{Name: ccName, Path: url} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: args}} + + //...and get back the ccid with the new version + cccid2, err := upgrade(ctxt, cccid, spec) + if err != nil { + t.Fail() + t.Logf("Error upgrading chaincode %s(%s)", chaincodeID, err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + if cccid2 != nil { + theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + } + return + } + + //go back and do the same query now + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: qArgs}} + + _, _, _, err = invokeWithVersion(ctxt, chainID, cccid2.Version, spec) + if err != nil { + t.Fail() + t.Logf("querying chaincode exampl02 did not succeed: %s", err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + return + } + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) +} + +//TestInvalUpgradeCC - test basic upgrade +// upgrade to exampl02 when "mycc" is not deployed +// look for "not found" failure +func TestInvalUpgradeCC(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() + + ccName := "mycc" + url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02" + chaincodeID := &pb.ChaincodeID{Name: ccName, Path: url} + + f := "init" + args := util.ToChaincodeArgs(f, "a", "100", "b", "200") + + spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: args}} + + cccid := NewCCContext(chainID, ccName, "0", "", false, nil) + + //Note ccName hasn't changed... + chaincodeID = &pb.ChaincodeID{Name: ccName, Path: url} + spec = &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: args}} + + //...and get back the ccid with the new version + cccid2, err := upgrade(ctxt, cccid, spec) + if err == nil { + t.Fail() + t.Logf("Error expected upgrading to fail but it succeeded%s(%s)", chaincodeID, err) + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + if cccid2 != nil { + theChaincodeSupport.Stop(ctxt, cccid2, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) + } + return + } + + theChaincodeSupport.Stop(ctxt, cccid, &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec}) +} diff --git a/core/committer/noopssinglechain/client.go b/core/committer/noopssinglechain/client.go index c4d9496541d..d30bc1c46d2 100644 --- a/core/committer/noopssinglechain/client.go +++ b/core/committer/noopssinglechain/client.go @@ -24,6 +24,7 @@ import ( "github.com/golang/protobuf/proto" "github.com/hyperledger/fabric/core/chaincode" "github.com/hyperledger/fabric/core/committer" + "github.com/hyperledger/fabric/core/util" "github.com/hyperledger/fabric/events/producer" "github.com/hyperledger/fabric/protos/common" "github.com/hyperledger/fabric/protos/orderer" @@ -214,7 +215,8 @@ func isTxValidForVscc(payload *common.Payload, envBytes []byte) error { defer txsim.Done() ctxt := context.WithValue(context.Background(), chaincode.TXSimulatorKey, txsim) - cccid := chaincode.NewCCContext(chainName, vscc, "", txid, true, prop) + version := util.GetSysCCVersion() + cccid := chaincode.NewCCContext(chainName, vscc, version, txid, true, prop) // invoke VSCC _, _, err = chaincode.ExecuteChaincode(ctxt, cccid, args) diff --git a/core/container/ccintf/ccintf.go b/core/container/ccintf/ccintf.go index 886eb774178..4ea221d01b0 100644 --- a/core/container/ccintf/ccintf.go +++ b/core/container/ccintf/ccintf.go @@ -51,6 +51,7 @@ type CCID struct { NetworkID string PeerID string ChainID string + Version string } //GetName returns canonical chaincode name based on chain name @@ -59,12 +60,17 @@ func (ccid *CCID) GetName() string { panic("nil chaincode spec") } + name := ccid.ChaincodeSpec.ChaincodeID.Name + if ccid.Version != "" { + name = name + "-" + ccid.Version + } + //this better be chainless system chaincode! if ccid.ChainID != "" { hash := util.ComputeCryptoHash([]byte(ccid.ChainID)) hexstr := hex.EncodeToString(hash[:]) - return ccid.ChaincodeSpec.ChaincodeID.Name + "-" + hexstr + name = name + "-" + hexstr } - return ccid.ChaincodeSpec.ChaincodeID.Name + return name } diff --git a/core/endorser/endorser.go b/core/endorser/endorser.go index b1964f4eef8..bcdc2f096fc 100644 --- a/core/endorser/endorser.go +++ b/core/endorser/endorser.go @@ -26,6 +26,7 @@ import ( "github.com/hyperledger/fabric/core/chaincode" "github.com/hyperledger/fabric/core/ledger" "github.com/hyperledger/fabric/core/peer" + "github.com/hyperledger/fabric/core/util" "github.com/hyperledger/fabric/msp" "github.com/hyperledger/fabric/protos/common" pb "github.com/hyperledger/fabric/protos/peer" @@ -87,7 +88,7 @@ func (e *Endorser) deploy(ctxt context.Context, cccid *chaincode.CCContext, cds } //call specified chaincode (system or user) -func (e *Endorser) callChaincode(ctxt context.Context, chainID string, txid string, prop *pb.Proposal, cis *pb.ChaincodeInvocationSpec, cid *pb.ChaincodeID, txsim ledger.TxSimulator) ([]byte, *pb.ChaincodeEvent, error) { +func (e *Endorser) callChaincode(ctxt context.Context, chainID string, version string, txid string, prop *pb.Proposal, cis *pb.ChaincodeInvocationSpec, cid *pb.ChaincodeID, txsim ledger.TxSimulator) ([]byte, *pb.ChaincodeEvent, error) { var err error var b []byte var ccevent *pb.ChaincodeEvent @@ -99,7 +100,7 @@ func (e *Endorser) callChaincode(ctxt context.Context, chainID string, txid stri //is this a system chaincode syscc := chaincode.IsSysCC(cid.Name) - cccid := chaincode.NewCCContext(chainID, cid.Name, "", txid, syscc, prop) + cccid := chaincode.NewCCContext(chainID, cid.Name, version, txid, syscc, prop) b, ccevent, err = chaincode.ExecuteChaincode(ctxt, cccid, cis.ChaincodeSpec.CtorMsg.Args) @@ -116,6 +117,18 @@ func (e *Endorser) callChaincode(ctxt context.Context, chainID string, txid stri //NOTE that if there's an error all simulation, including the chaincode //table changes in lccc will be thrown away if cid.Name == "lccc" && len(cis.ChaincodeSpec.CtorMsg.Args) == 3 && (string(cis.ChaincodeSpec.CtorMsg.Args[0]) == "deploy" || string(cis.ChaincodeSpec.CtorMsg.Args[0]) == "upgrade") { + var ccVersion string + switch string(cis.ChaincodeSpec.CtorMsg.Args[0]) { + case "deploy": + //NOTE - if user provides chaincode version on deploy, that'll be in the + //ChaincodeID and will be used + ccVersion = "0" + case "upgrade": + //use the new version + ccVersion = string(b) + default: + panic(fmt.Sprintf("invalid call to lccc... we shouldn't have got here (ie,passed ExecuteChaincode (%s))", cis.ChaincodeSpec.CtorMsg.Args[0])) + } var cds *pb.ChaincodeDeploymentSpec cds, err = putils.GetChaincodeDeploymentSpec(cis.ChaincodeSpec.CtorMsg.Args[2]) if err != nil { @@ -127,7 +140,7 @@ func (e *Endorser) callChaincode(ctxt context.Context, chainID string, txid stri return nil, nil, fmt.Errorf("attempting to deploy a system chaincode %s/%s", cds.ChaincodeSpec.ChaincodeID.Name, chainID) } - cccid = chaincode.NewCCContext(chainID, cds.ChaincodeSpec.ChaincodeID.Name, "", txid, false, prop) + cccid = chaincode.NewCCContext(chainID, cds.ChaincodeSpec.ChaincodeID.Name, ccVersion, txid, false, prop) err = e.deploy(ctxt, cccid, cds) if err != nil { @@ -140,64 +153,73 @@ func (e *Endorser) callChaincode(ctxt context.Context, chainID string, txid stri } //simulate the proposal by calling the chaincode -func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid string, prop *pb.Proposal, cid *pb.ChaincodeID, txsim ledger.TxSimulator) ([]byte, []byte, *pb.ChaincodeEvent, error) { +func (e *Endorser) simulateProposal(ctx context.Context, chainID string, txid string, prop *pb.Proposal, cid *pb.ChaincodeID, txsim ledger.TxSimulator) (*chaincode.ChaincodeData, []byte, []byte, *pb.ChaincodeEvent, error) { //we do expect the payload to be a ChaincodeInvocationSpec //if we are supporting other payloads in future, this be glaringly point //as something that should change cis, err := putils.GetChaincodeInvocationSpec(prop) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } //---1. check ACL if err = e.checkACL(prop); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } //---2. check ESCC and VSCC for the chaincode if err = e.checkEsccAndVscc(prop); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err + } + + var cd *chaincode.ChaincodeData + + //default it to a system CC + version := util.GetSysCCVersion() + if !chaincode.IsSysCC(cid.Name) { + cd, err = e.getCDSFromLCCC(ctx, chainID, txid, prop, cid.Name, txsim) + if err != nil { + return nil, nil, nil, nil, fmt.Errorf("failed to obtain cds for %s - %s", cid.Name, err) + } + version = cd.Version } //---3. execute the proposal and get simulation results var simResult []byte var resp []byte var ccevent *pb.ChaincodeEvent - resp, ccevent, err = e.callChaincode(ctx, chainID, txid, prop, cis, cid, txsim) + resp, ccevent, err = e.callChaincode(ctx, chainID, version, txid, prop, cis, cid, txsim) if err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } if txsim != nil { if simResult, err = txsim.GetTxSimulationResults(); err != nil { - return nil, nil, nil, err + return nil, nil, nil, nil, err } } - return resp, simResult, ccevent, nil + return cd, resp, simResult, ccevent, nil } -func (e *Endorser) getCDSFromLCCC(ctx context.Context, chainID string, txid string, prop *pb.Proposal, chaincodeID string, txsim ledger.TxSimulator) ([]byte, error) { +func (e *Endorser) getCDSFromLCCC(ctx context.Context, chainID string, txid string, prop *pb.Proposal, chaincodeID string, txsim ledger.TxSimulator) (*chaincode.ChaincodeData, error) { ctxt := ctx if txsim != nil { ctxt = context.WithValue(ctx, chaincode.TXSimulatorKey, txsim) } - return chaincode.GetCDSFromLCCC(ctxt, txid, prop, chainID, chaincodeID) + return chaincode.GetChaincodeDataFromLCCC(ctxt, txid, prop, chainID, chaincodeID) } //endorse the proposal by calling the ESCC -func (e *Endorser) endorseProposal(ctx context.Context, chainID string, txid string, proposal *pb.Proposal, simRes []byte, event *pb.ChaincodeEvent, visibility []byte, ccid *pb.ChaincodeID, txsim ledger.TxSimulator) (*pb.ProposalResponse, error) { +func (e *Endorser) endorseProposal(ctx context.Context, chainID string, txid string, proposal *pb.Proposal, simRes []byte, event *pb.ChaincodeEvent, visibility []byte, ccid *pb.ChaincodeID, txsim ledger.TxSimulator, cd *chaincode.ChaincodeData) (*pb.ProposalResponse, error) { endorserLogger.Infof("endorseProposal starts for chainID %s, ccid %s", chainID, ccid) // 1) extract the chaincodeDeploymentSpec for the chaincode we are invoking; we need it to get the escc var escc string - if !chaincode.IsSysCC(ccid.Name) { - depPayload, err := e.getCDSFromLCCC(ctx, chainID, txid, proposal, ccid.Name, txsim) - if err != nil { - return nil, fmt.Errorf("failed to obtain cds for %s - %s", ccid, err) - } - _, err = putils.GetChaincodeDeploymentSpec(depPayload) + //ie, not "lccc" or system chaincodes + if cd != nil { + _, err := putils.GetChaincodeDeploymentSpec(cd.DepSpec) if err != nil { return nil, fmt.Errorf("failed to unmarshal cds for %s - %s", ccid, err) } @@ -230,8 +252,9 @@ func (e *Endorser) endorseProposal(ctx context.Context, chainID string, txid str // args[4] - serialized events // args[5] - payloadVisibility args := [][]byte{[]byte(""), proposal.Header, proposal.Payload, simRes, eventBytes, visibility} + version := util.GetSysCCVersion() ecccis := &pb.ChaincodeInvocationSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: pb.ChaincodeSpec_GOLANG, ChaincodeID: &pb.ChaincodeID{Name: escc}, CtorMsg: &pb.ChaincodeInput{Args: args}}} - prBytes, _, err := e.callChaincode(ctx, chainID, txid, proposal, ecccis, &pb.ChaincodeID{Name: escc}, txsim) + prBytes, _, err := e.callChaincode(ctx, chainID, version, txid, proposal, ecccis, &pb.ChaincodeID{Name: escc}, txsim) if err != nil { return nil, err } @@ -309,7 +332,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro //1 -- simulate //TODO what do we do with response ? We need it for Invoke responses for sure //Which field in PayloadResponse will carry return value ? - result, simulationResult, ccevent, err := e.simulateProposal(ctx, chainID, txid, prop, hdrExt.ChaincodeID, txsim) + cd, result, simulationResult, ccevent, err := e.simulateProposal(ctx, chainID, txid, prop, hdrExt.ChaincodeID, txsim) if err != nil { return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err } @@ -322,7 +345,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro if ischainless { pResp = &pb.ProposalResponse{Response: &pb.Response{}} } else { - pResp, err = e.endorseProposal(ctx, chainID, txid, prop, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeID, txsim) + pResp, err = e.endorseProposal(ctx, chainID, txid, prop, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeID, txsim, cd) if err != nil { return &pb.ProposalResponse{Response: &pb.Response{Status: 500, Message: err.Error()}}, err } diff --git a/core/endorser/endorser_test.go b/core/endorser/endorser_test.go index a36c4a5beb3..74db16f40b6 100644 --- a/core/endorser/endorser_test.go +++ b/core/endorser/endorser_test.go @@ -264,7 +264,7 @@ func TestDeploy(t *testing.T) { chainID := util.GetTestChainID() spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "ex01", Path: "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01"}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}}} - cccid := chaincode.NewCCContext(chainID, "ex01", "", "", false, nil) + cccid := chaincode.NewCCContext(chainID, "ex01", "0", "", false, nil) _, _, err := deploy(endorserServer, chainID, spec, nil) if err != nil { @@ -282,7 +282,7 @@ func TestDeployBadArgs(t *testing.T) { //invalid arguments spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "ex02", Path: "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b")}}} - cccid := chaincode.NewCCContext(chainID, "ex02", "", "", false, nil) + cccid := chaincode.NewCCContext(chainID, "ex02", "0", "", false, nil) _, _, err := deploy(endorserServer, chainID, spec, nil) if err == nil { @@ -300,7 +300,7 @@ func TestDeployBadPayload(t *testing.T) { //invalid arguments spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "ex02", Path: "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}}} - cccid := chaincode.NewCCContext(chainID, "ex02", "", "", false, nil) + cccid := chaincode.NewCCContext(chainID, "ex02", "0", "", false, nil) f := func(cds *pb.ChaincodeDeploymentSpec) { cds.CodePackage = nil @@ -322,7 +322,7 @@ func TestRedeploy(t *testing.T) { //invalid arguments spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: &pb.ChaincodeID{Name: "ex02", Path: "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02"}, CtorMsg: &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}}} - cccid := chaincode.NewCCContext(chainID, "ex02", "", "", false, nil) + cccid := chaincode.NewCCContext(chainID, "ex02", "0", "", false, nil) _, _, err := deploy(endorserServer, chainID, spec, nil) if err != nil { @@ -357,7 +357,7 @@ func TestDeployAndInvoke(t *testing.T) { argsDeploy := util.ToChaincodeArgs(f, "a", "100", "b", "200") spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID, CtorMsg: &pb.ChaincodeInput{Args: argsDeploy}} - cccid := chaincode.NewCCContext(chainID, "ex01", "", "", false, nil) + cccid := chaincode.NewCCContext(chainID, "ex01", "0", "", false, nil) resp, prop, err := deploy(endorserServer, chainID, spec, nil) chaincodeID1 := spec.ChaincodeID.Name @@ -407,8 +407,8 @@ func TestDeployAndUpgrade(t *testing.T) { argsDeploy := util.ToChaincodeArgs(f, "a", "100", "b", "200") spec := &pb.ChaincodeSpec{Type: 1, ChaincodeID: chaincodeID1, CtorMsg: &pb.ChaincodeInput{Args: argsDeploy}} - cccid1 := chaincode.NewCCContext(chainID, "upgradeex01", "", "", false, nil) - cccid2 := chaincode.NewCCContext(chainID, "upgradeex02", "", "", false, nil) + cccid1 := chaincode.NewCCContext(chainID, "upgradeex01", "0", "", false, nil) + cccid2 := chaincode.NewCCContext(chainID, "upgradeex01", "1", "", false, nil) resp, prop, err := deploy(endorserServer, chainID, spec, nil) diff --git a/core/peer/msgvalidation.go b/core/peer/msgvalidation.go index 1fb409593a3..be255ed0ce0 100644 --- a/core/peer/msgvalidation.go +++ b/core/peer/msgvalidation.go @@ -21,7 +21,7 @@ import ( "bytes" - "github.com/hyperledger/fabric/core/peer/msp" + mspmgmt "github.com/hyperledger/fabric/core/peer/msp" "github.com/hyperledger/fabric/protos/common" pb "github.com/hyperledger/fabric/protos/peer" "github.com/hyperledger/fabric/protos/utils" diff --git a/core/util/utils.go b/core/util/utils.go index f0553c295ad..056263ad49b 100644 --- a/core/util/utils.go +++ b/core/util/utils.go @@ -25,6 +25,8 @@ import ( "strings" "time" + "github.com/hyperledger/fabric/metadata" + "github.com/golang/protobuf/ptypes/timestamp" "golang.org/x/crypto/sha3" ) @@ -125,6 +127,7 @@ all: return } +// ToChaincodeArgs converts string args to []byte args func ToChaincodeArgs(args ...string) [][]byte { bargs := make([][]byte, len(args)) for i, arg := range args { @@ -133,6 +136,7 @@ func ToChaincodeArgs(args ...string) [][]byte { return bargs } +// ArrayToChaincodeArgs converts array of string args to array of []byte args func ArrayToChaincodeArgs(args []string) [][]byte { bargs := make([][]byte, len(args)) for i, arg := range args { @@ -147,3 +151,11 @@ const testchainid = "**TEST_CHAINID**" func GetTestChainID() string { return testchainid } + +//GetSysCCVersion returns the version of all system chaincodes +//This needs to be revisited on policies around system chaincode +//"upgrades" from user and relationship with "fabric" upgrade. For +//now keep it simple and use the fabric's version stamp +func GetSysCCVersion() string { + return metadata.Version +}