Skip to content

Commit

Permalink
FAB-1318 - complete upgrade from endorser side
Browse files Browse the repository at this point in the history
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 <upgrade chaincode path> -c '{"Args":[<args to upgrade chaincode>]}'

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 <chain, chaincode>. 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 <muralisr@us.ibm.com>
  • Loading branch information
Srinivasan Muralidharan committed Dec 21, 2016
1 parent 784d260 commit 269379a
Show file tree
Hide file tree
Showing 17 changed files with 610 additions and 209 deletions.
31 changes: 16 additions & 15 deletions core/chaincode/chaincode_support.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

//
Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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)

Expand Down Expand Up @@ -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
Expand All @@ -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
}

Expand Down Expand Up @@ -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)

Expand Down
22 changes: 21 additions & 1 deletion core/chaincode/chaincodeexec.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ import (

"fmt"

"github.com/golang/protobuf/proto"
"github.com/hyperledger/fabric/core/util"
pb "github.com/hyperledger/fabric/protos/peer"
)

Expand All @@ -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
Expand Down
1 change: 1 addition & 0 deletions core/chaincode/chaincodetest.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
58 changes: 33 additions & 25 deletions core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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()
}
Expand Down Expand Up @@ -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 {
Expand All @@ -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.
Expand All @@ -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)
Expand Down Expand Up @@ -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)

Expand All @@ -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)

Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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}

Expand Down Expand Up @@ -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"}
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down

0 comments on commit 269379a

Please sign in to comment.