Skip to content

Commit

Permalink
fab-2177 add install command to lccc
Browse files Browse the repository at this point in the history
With the new deploy model where the installation is on the file system,
the "on peer" install is not quite satisfactory for developers who have
to log on to a peer to install before they do anything.

This implements a new "install" Invoke command on the LCCC whose only
purpose is to put the code on the file system.

CLI usage
---------
peer chaincode install -n <name> -v <version> -p <path>

where the command will install to CORE_PEER_ADDRESS.

Change-Id: Ieadd7b9495ddf57ab7099cb788d8b99f4553cdf6
Signed-off-by: Srinivasan Muralidharan <[email protected]>
  • Loading branch information
Srinivasan Muralidharan committed Feb 13, 2017
1 parent ffe4c91 commit edf7d7c
Show file tree
Hide file tree
Showing 10 changed files with 238 additions and 98 deletions.
5 changes: 2 additions & 3 deletions core/chaincode/exectransaction_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -283,9 +283,8 @@ func deploy2(ctx context.Context, cccid *ccprovider.CCContext, chaincodeDeployme
}
}()

if err = ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec); err != nil {
return nil, err
}
//ignore existence errors
ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec)

sysCCVers := util.GetSysCCVersion()
lcccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, nil)
Expand Down
7 changes: 6 additions & 1 deletion core/common/ccprovider/ccprovider.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,12 +89,17 @@ func PutChaincodeIntoFS(depSpec *pb.ChaincodeDeploymentSpec) error {
ccname := depSpec.ChaincodeSpec.ChaincodeId.Name
ccversion := depSpec.ChaincodeSpec.ChaincodeId.Version

//return error if chaincode exists
path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)
if _, err := os.Stat(path); err == nil {
return fmt.Errorf("chaincode %s exits", path)
}

b, err := proto.Marshal(depSpec)
if err != nil {
return fmt.Errorf("failed to marshal fs deployment spec for %s, %s", ccname, ccversion)
}

path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)
if err = ioutil.WriteFile(path, b, 0644); err != nil {
return err
}
Expand Down
2 changes: 1 addition & 1 deletion core/endorser/endorser.go
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ func (e *Endorser) ProcessProposal(ctx context.Context, signedProp *pb.SignedPro
//TODO till we implement global ESCC, CSCC for system chaincodes
//chainless proposals (such as CSCC) don't have to be endorsed
if ischainless {
pResp = &pb.ProposalResponse{Response: &pb.Response{}}
pResp = &pb.ProposalResponse{Response: res}
} else {
pResp, err = e.endorseProposal(ctx, chainID, txid, prop, res, simulationResult, ccevent, hdrExt.PayloadVisibility, hdrExt.ChaincodeId, txsim, cd)
if err != nil {
Expand Down
11 changes: 11 additions & 0 deletions core/endorser/endorser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,8 @@ 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", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}}}

defer os.RemoveAll("/tmp/hyperledger/production/chaincodes/ex01.0")

cccid := ccprovider.NewCCContext(chainID, "ex01", "0", "", false, nil)

_, _, err := deploy(endorserServer, chainID, spec, nil)
Expand All @@ -283,6 +285,8 @@ 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", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}}}

defer os.RemoveAll("/tmp/hyperledger/production/chaincodes/ex02.0")

cccid := ccprovider.NewCCContext(chainID, "ex02", "0", "", false, nil)

_, _, err := deploy(endorserServer, chainID, spec, nil)
Expand All @@ -293,6 +297,8 @@ func TestRedeploy(t *testing.T) {
return
}

os.RemoveAll("/tmp/hyperledger/production/chaincodes/ex02.0")

//second time should not fail as we are just simulating
_, _, err = deploy(endorserServer, chainID, spec, nil)
if err != nil {
Expand All @@ -312,6 +318,8 @@ func TestDeployAndInvoke(t *testing.T) {
url := "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01"
chaincodeID := &pb.ChaincodeID{Path: url, Name: "ex01", Version: "0"}

defer os.RemoveAll("/tmp/hyperledger/production/chaincodes/ex01.0")

args := []string{"10"}

f := "init"
Expand Down Expand Up @@ -364,6 +372,9 @@ func TestDeployAndUpgrade(t *testing.T) {
chaincodeID1 := &pb.ChaincodeID{Path: url1, Name: "upgradeex01", Version: "0"}
chaincodeID2 := &pb.ChaincodeID{Path: url2, Name: "upgradeex01", Version: "1"}

defer os.RemoveAll("/tmp/hyperledger/production/chaincodes/upgradeex01.0")
defer os.RemoveAll("/tmp/hyperledger/production/chaincodes/upgradeex01.1")

f := "init"
argsDeploy := util.ToChaincodeArgs(f, "a", "100", "b", "200")
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: chaincodeID1, Input: &pb.ChaincodeInput{Args: argsDeploy}}
Expand Down
38 changes: 38 additions & 0 deletions core/scc/lccc/lccc.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@ const (

//chaincode lifecyle commands

//INSTALL install command
INSTALL = "install"

//DEPLOY deploy command
DEPLOY = "deploy"

Expand Down Expand Up @@ -284,6 +287,29 @@ func (lccc *LifeCycleSysCC) isValidChaincodeName(chaincodename string) bool {
return true
}

//this implements "install" Invoke transaction
func (lccc *LifeCycleSysCC) executeInstall(stub shim.ChaincodeStubInterface, depSpec []byte) error {
cds, err := lccc.getChaincodeDeploymentSpec(depSpec)

if err != nil {
return err
}

if !lccc.isValidChaincodeName(cds.ChaincodeSpec.ChaincodeId.Name) {
return InvalidChaincodeNameErr(cds.ChaincodeSpec.ChaincodeId.Name)
}

if cds.ChaincodeSpec.ChaincodeId.Version == "" {
return EmptyVersionErr(cds.ChaincodeSpec.ChaincodeId.Name)
}

if err = ccprovider.PutChaincodeIntoFS(cds); err != nil {
return fmt.Errorf("Error installing chaincode code %s:%s(%s)", cds.ChaincodeSpec.ChaincodeId.Name, cds.ChaincodeSpec.ChaincodeId.Version, err)
}

return err
}

//this implements "deploy" Invoke transaction
func (lccc *LifeCycleSysCC) executeDeploy(stub shim.ChaincodeStubInterface, chainname string, depSpec []byte, policy []byte, escc []byte, vscc []byte) error {
cds, err := lccc.getChaincodeDeploymentSpec(depSpec)
Expand Down Expand Up @@ -395,6 +421,18 @@ func (lccc *LifeCycleSysCC) Invoke(stub shim.ChaincodeStubInterface) pb.Response
function := string(args[0])

switch function {
case INSTALL:
if len(args) < 2 {
return shim.Error(InvalidArgsLenErr(len(args)).Error())
}

depSpec := args[1]

err := lccc.executeInstall(stub, depSpec)
if err != nil {
return shim.Error(err.Error())
}
return shim.Success([]byte("OK"))
case DEPLOY:
if len(args) < 3 || len(args) > 6 {
return shim.Error(InvalidArgsLenErr(len(args)).Error())
Expand Down
115 changes: 86 additions & 29 deletions core/scc/lccc/lccc_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,16 +53,18 @@ func register(stub *shim.MockStub, ccname string) error {
return nil
}

func constructDeploymentSpec(name string, path string, version string, initArgs [][]byte) (*pb.ChaincodeDeploymentSpec, error) {
func constructDeploymentSpec(name string, path string, version string, initArgs [][]byte, createFS bool) (*pb.ChaincodeDeploymentSpec, error) {
spec := &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: name, Path: path, Version: version}, Input: &pb.ChaincodeInput{Args: initArgs}}

codePackageBytes := []byte(name + path + version)

chaincodeDeploymentSpec := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: spec, CodePackage: codePackageBytes}

err := ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec)
if err != nil {
return nil, err
if createFS {
err := ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec)
if err != nil {
return nil, err
}
}

return chaincodeDeploymentSpec, nil
Expand All @@ -78,8 +80,8 @@ func TestDeploy(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand All @@ -91,6 +93,55 @@ func TestDeploy(t *testing.T) {
}
}

//TestInstall tests the install function
func TestInstall(t *testing.T) {
scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)

if res := stub.MockInit("1", nil); res.Status != shim.OK {
fmt.Println("Init failed", string(res.Message))
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, false)
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
}

//constructDeploymentSpec puts the depspec on the FS. This should fail
args := [][]byte{[]byte(INSTALL), b}
defer os.Remove(lccctestpath + "/example02.0")
if res := stub.MockInvoke("1", args); res.Status != shim.OK {
t.FailNow()
}
}

//TestReinstall tests the install function
func TestReinstall(t *testing.T) {
scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)

if res := stub.MockInit("1", nil); res.Status != shim.OK {
fmt.Println("Init failed", string(res.Message))
t.FailNow()
}

//note that this puts the code on the filesyste....
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
}

//constructDeploymentSpec puts the depspec on the FS. This should fail
args := [][]byte{[]byte(INSTALL), b}
if res := stub.MockInvoke("1", args); res.Status == shim.OK {
t.FailNow()
}
}

//TestInvalidCodeDeploy tests the deploy function with invalid code package
func TestInvalidCodeDeploy(t *testing.T) {
scc := new(LifeCycleSysCC)
Expand Down Expand Up @@ -121,8 +172,11 @@ func TestInvalidChaincodeName(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
if err != nil {
t.FailNow()
}

//change name to empty
cds.ChaincodeSpec.ChaincodeId.Name = ""
Expand Down Expand Up @@ -150,8 +204,11 @@ func TestEmptyChaincodeVersion(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
if err != nil {
t.FailNow()
}

//change version to empty
cds.ChaincodeSpec.ChaincodeId.Version = ""
Expand Down Expand Up @@ -179,8 +236,8 @@ func TestRedeploy(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand Down Expand Up @@ -209,8 +266,8 @@ func TestCheckCC(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")

var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
Expand All @@ -228,7 +285,7 @@ func TestCheckCC(t *testing.T) {
}
}

//TestMultipleDeploy tests deploying multiple chaincodes
//TestMultipleDeploy tests deploying multiple chaincodeschaincodes
func TestMultipleDeploy(t *testing.T) {
scc := new(LifeCycleSysCC)
stub := shim.NewMockStub("lccc", scc)
Expand All @@ -239,8 +296,8 @@ func TestMultipleDeploy(t *testing.T) {
}

//deploy 02
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand All @@ -257,8 +314,8 @@ func TestMultipleDeploy(t *testing.T) {
}

//deploy 01
cds, err = constructDeploymentSpec("example01", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example01.0")
cds, err = constructDeploymentSpec("example01", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example01", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example01.0")
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
}
Expand All @@ -285,8 +342,8 @@ func TestRetryFailedDeploy(t *testing.T) {
}

//deploy 02
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.FailNow()
Expand Down Expand Up @@ -328,8 +385,8 @@ func TestUpgrade(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.Fatalf("Marshal DeploymentSpec failed")
Expand All @@ -340,8 +397,8 @@ func TestUpgrade(t *testing.T) {
t.Fatalf("Deploy chaincode error: %v", err)
}

newCds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "1", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.1")
newCds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "1", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.1")
var newb []byte
if newb, err = proto.Marshal(newCds); err != nil || newb == nil {
t.Fatalf("Marshal DeploymentSpec failed")
Expand Down Expand Up @@ -370,8 +427,8 @@ func TestUpgradeNonExistChaincode(t *testing.T) {
t.FailNow()
}

cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example02.0")
cds, err := constructDeploymentSpec("example02", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "0", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example02.0")
var b []byte
if b, err = proto.Marshal(cds); err != nil || b == nil {
t.Fatalf("Marshal DeploymentSpec failed")
Expand All @@ -382,8 +439,8 @@ func TestUpgradeNonExistChaincode(t *testing.T) {
t.Fatalf("Deploy chaincode error: %s", res.Message)
}

newCds, err := constructDeploymentSpec("example03", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "1", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")})
defer os.Remove(lccctestpath + "/chaincodes/example03.1")
newCds, err := constructDeploymentSpec("example03", "github.com/hyperledger/fabric/examples/chaincode/go/chaincode_example02", "1", [][]byte{[]byte("init"), []byte("a"), []byte("100"), []byte("b"), []byte("200")}, true)
defer os.Remove(lccctestpath + "/example03.1")
var newb []byte
if newb, err = proto.Marshal(newCds); err != nil || newb == nil {
t.Fatalf("Marshal DeploymentSpec failed")
Expand Down
7 changes: 1 addition & 6 deletions core/scc/sysccapi.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,17 +84,12 @@ func deploySysCC(chainID string, syscc *SystemChaincode) error {
return nil
}

chainless := false
if chainID == "" {
chainless = true
}

var err error

ccprov := ccprovider.GetChaincodeProvider()

ctxt := context.Background()
if !chainless {
if chainID != "" {
lgr := peer.GetLedger(chainID)
if lgr == nil {
panic(fmt.Sprintf("syschain %s start up failure - unexpected nil ledger for channel %s", syscc.Name, chainID))
Expand Down
Loading

0 comments on commit edf7d7c

Please sign in to comment.