Skip to content

Commit d91c5c3

Browse files
author
Srinivasan Muralidharan
committed
[FAB-2927] install chaincode package
The CLI install command is enhanced to install a package previously generated with the "package" or "signpackage" commands. The cc-packaging-and-signing.rst describes the command. With this change chaincode can deployed in one of these methods . using SDK or older "install" commands . create a (signed) package first as described in cc-packaging-and-signing.rst fabric will first test for the older "ChaincodeDeploymentSpec" based install before attempting to use the package. Security fixes and linking the install to the instantiation record will be submitted in future CRs. Change-Id: I90c736d5f933dcd619b4de5944e7b69b50b45893 Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent c810332 commit d91c5c3

File tree

7 files changed

+236
-33
lines changed

7 files changed

+236
-33
lines changed

core/common/ccprovider/ccprovider.go

+16-1
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ type CCPackage interface {
5757
// ChaincodeData. The validation is based on the metadata from ChaincodeData
5858
// One use of this method is to validate the chaincode before launching
5959
ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error)
60+
61+
// GetPackageObject gets the object as a proto.Message
62+
GetPackageObject() proto.Message
6063
}
6164

6265
//SetChaincodesPath sets the chaincode path for this peer
@@ -89,8 +92,18 @@ func GetChaincodePackage(ccname string, ccversion string) ([]byte, error) {
8992

9093
// GetChaincodeFromFS this is a wrapper for hiding package implementation.
9194
func GetChaincodeFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
95+
//try raw CDS
9296
cccdspack := &CDSPackage{}
93-
return cccdspack.InitFromFS(ccname, ccversion)
97+
b, depSpec, err := cccdspack.InitFromFS(ccname, ccversion)
98+
if err != nil {
99+
//try signed CDS
100+
ccscdspack := &SignedCDSPackage{}
101+
b, depSpec, err = ccscdspack.InitFromFS(ccname, ccversion)
102+
if err != nil {
103+
return nil, nil, err
104+
}
105+
}
106+
return b, depSpec, nil
94107
}
95108

96109
// PutChaincodeIntoFS is a wrapper for putting raw ChaincodeDeploymentSpec
@@ -110,8 +123,10 @@ func PutChaincodeIntoFS(depSpec *pb.ChaincodeDeploymentSpec) error {
110123
// GetCCPackage tries each known package implementation one by one
111124
// till the right package is found
112125
func GetCCPackage(buf []byte) (CCPackage, error) {
126+
//try raw CDS
113127
cccdspack := &CDSPackage{}
114128
if _, err := cccdspack.InitFromBuffer(buf); err != nil {
129+
//try signed CDS
115130
ccscdspack := &SignedCDSPackage{}
116131
if _, err := ccscdspack.InitFromBuffer(buf); err != nil {
117132
return nil, err

core/common/ccprovider/cdspackage.go

+6-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,11 @@ func (ccpack *CDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec {
3737
return ccpack.depSpec
3838
}
3939

40+
// GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message
41+
func (ccpack *CDSPackage) GetPackageObject() proto.Message {
42+
return ccpack.depSpec
43+
}
44+
4045
// ValidateCC returns error if the chaincode is not found or if its not a
4146
// ChaincodeDeploymentSpec
4247
func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error) {
@@ -59,7 +64,7 @@ func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) {
5964
depSpec := &pb.ChaincodeDeploymentSpec{}
6065
err := proto.Unmarshal(buf, depSpec)
6166
if err != nil {
62-
return nil, fmt.Errorf("failed to unmarshal fs deployment spec from bytes")
67+
return nil, fmt.Errorf("failed to unmarshal deployment spec from bytes")
6368
}
6469
ccpack.buf = buf
6570
ccpack.depSpec = depSpec

core/common/ccprovider/sigcdspackage.go

+13
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,19 @@ type SignedCDSPackage struct {
3333
buf []byte
3434
depSpec *pb.ChaincodeDeploymentSpec
3535
sDepSpec *pb.SignedChaincodeDeploymentSpec
36+
env *common.Envelope
3637
}
3738

3839
// GetDepSpec gets the ChaincodeDeploymentSpec from the package
3940
func (ccpack *SignedCDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec {
4041
return ccpack.depSpec
4142
}
4243

44+
// GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message
45+
func (ccpack *SignedCDSPackage) GetPackageObject() proto.Message {
46+
return ccpack.env
47+
}
48+
4349
// ValidateCC returns error if the chaincode is not found or if its not a
4450
// ChaincodeDeploymentSpec
4551
func (ccpack *SignedCDSPackage) ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error) {
@@ -69,6 +75,7 @@ func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, erro
6975
ccpack.buf = nil
7076
ccpack.sDepSpec = nil
7177
ccpack.depSpec = nil
78+
ccpack.env = nil
7279

7380
env := &common.Envelope{}
7481
err := proto.Unmarshal(buf, env)
@@ -92,6 +99,7 @@ func (ccpack *SignedCDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, erro
9299
ccpack.buf = buf
93100
ccpack.sDepSpec = sDepSpec
94101
ccpack.depSpec = depSpec
102+
ccpack.env = env
95103

96104
return &ChaincodeData{Name: depSpec.ChaincodeSpec.ChaincodeId.Name, Version: depSpec.ChaincodeSpec.ChaincodeId.Version}, nil
97105
}
@@ -102,6 +110,7 @@ func (ccpack *SignedCDSPackage) InitFromFS(ccname string, ccversion string) ([]b
102110
ccpack.buf = nil
103111
ccpack.sDepSpec = nil
104112
ccpack.depSpec = nil
113+
ccpack.env = nil
105114

106115
buf, err := GetChaincodePackage(ccname, ccversion)
107116
if err != nil {
@@ -125,6 +134,10 @@ func (ccpack *SignedCDSPackage) PutChaincodeToFS() error {
125134
return fmt.Errorf("depspec cannot be nil if buf is not nil")
126135
}
127136

137+
if ccpack.env == nil {
138+
return fmt.Errorf("env cannot be nil if buf and depspec are not nil")
139+
}
140+
128141
ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name
129142
ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version
130143

docs/source/cc-packaging-and-signing.rst

+13-2
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ installation simply as a file with name
1010
called a chaincode package.
1111

1212
This document describes how a chaincode package can be created and
13-
signed from CLI. The package is used for install using the usual install
14-
procedures and not covered in this document.
13+
signed from CLI. It also describes how the ``install`` command can
14+
be used to install the chaincode package.
1515

1616
What’s in the package ?
1717
-----------------------
@@ -64,6 +64,17 @@ where ``ccpack.out`` and ``signedccpack.out`` are input and output
6464
packages respectively. ``signedccpack.out`` contains an additional
6565
signature over the package signed using the Local MSP.
6666

67+
Installing the package
68+
----------------------
69+
The package can be installed using the ``install`` command as follows
70+
71+
::
72+
73+
peer chaincode install ccpack.out
74+
75+
where ``ccpack.out`` is a package filecreated using the ``package``
76+
or ``signedpackage`` commands.
77+
6778
Conclusion
6879
----------
6980

peer/chaincode/install.go

+107-19
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,15 @@ package chaincode
1818

1919
import (
2020
"fmt"
21+
"io/ioutil"
2122

23+
"github.com/golang/protobuf/proto"
2224
"golang.org/x/net/context"
2325

26+
"github.com/hyperledger/fabric/core/common/ccpackage"
2427
"github.com/hyperledger/fabric/core/common/ccprovider"
2528
"github.com/hyperledger/fabric/peer/common"
29+
pcommon "github.com/hyperledger/fabric/protos/common"
2630
pb "github.com/hyperledger/fabric/protos/peer"
2731
"github.com/hyperledger/fabric/protos/utils"
2832

@@ -43,21 +47,25 @@ func installCmd(cf *ChaincodeCmdFactory) *cobra.Command {
4347
Long: fmt.Sprintf(install_desc),
4448
ValidArgs: []string{"1"},
4549
RunE: func(cmd *cobra.Command, args []string) error {
46-
return chaincodeInstall(cmd, args, cf)
50+
var ccpackfile string
51+
if len(args) > 0 {
52+
ccpackfile = args[0]
53+
}
54+
return chaincodeInstall(cmd, ccpackfile, cf)
4755
},
4856
}
4957

5058
return chaincodeInstallCmd
5159
}
5260

5361
//install the depspec to "peer.address"
54-
func install(chaincodeName string, chaincodeVersion string, cds *pb.ChaincodeDeploymentSpec, cf *ChaincodeCmdFactory) error {
62+
func install(msg proto.Message, cf *ChaincodeCmdFactory) error {
5563
creator, err := cf.Signer.Serialize()
5664
if err != nil {
5765
return fmt.Errorf("Error serializing identity for %s: %s", cf.Signer.GetIdentifier(), err)
5866
}
5967

60-
prop, _, err := utils.CreateInstallProposalFromCDS(cds, creator)
68+
prop, _, err := utils.CreateInstallProposalFromCDS(msg, creator)
6169
if err != nil {
6270
return fmt.Errorf("Error creating proposal %s: %s", chainFuncName, err)
6371
}
@@ -80,12 +88,72 @@ func install(chaincodeName string, chaincodeVersion string, cds *pb.ChaincodeDep
8088
return nil
8189
}
8290

83-
// chaincodeInstall installs the chaincode. If remoteinstall, does it via a lccc call
84-
func chaincodeInstall(cmd *cobra.Command, args []string, cf *ChaincodeCmdFactory) error {
85-
if chaincodePath == common.UndefinedParamValue || chaincodeVersion == common.UndefinedParamValue {
86-
return fmt.Errorf("Must supply value for %s path and version parameters.", chainFuncName)
91+
//generateChaincode creates ChaincodeDeploymentSpec as the package to install
92+
func generateChaincode(cmd *cobra.Command, chaincodeName, chaincodeVersion string) (*pb.ChaincodeDeploymentSpec, error) {
93+
tmppkg, _ := ccprovider.GetChaincodePackage(chaincodeName, chaincodeVersion)
94+
if tmppkg != nil {
95+
return nil, fmt.Errorf("chaincode %s:%s exists", chaincodeName, chaincodeVersion)
96+
}
97+
98+
spec, err := getChaincodeSpecification(cmd)
99+
if err != nil {
100+
return nil, err
87101
}
88102

103+
cds, err := getChaincodeBytes(spec, true)
104+
if err != nil {
105+
return nil, fmt.Errorf("Error getting chaincode code %s: %s", chainFuncName, err)
106+
}
107+
108+
return cds, nil
109+
}
110+
111+
//getPackageFromFile get the chaincode package from file and the extracted ChaincodeDeploymentSpec
112+
func getPackageFromFile(ccpackfile string) (proto.Message, *pb.ChaincodeDeploymentSpec, error) {
113+
b, err := ioutil.ReadFile(ccpackfile)
114+
if err != nil {
115+
return nil, nil, err
116+
}
117+
118+
//the bytes should be a valid package (CDS or SigedCDS)
119+
ccpack, err := ccprovider.GetCCPackage(b)
120+
if err != nil {
121+
return nil, nil, err
122+
}
123+
124+
//either CDS or Envelope
125+
o, err := ccpack.GetPackageObject(), nil
126+
if err != nil {
127+
return nil, nil, err
128+
}
129+
130+
//try CDS first
131+
cds, ok := o.(*pb.ChaincodeDeploymentSpec)
132+
if !ok || cds == nil {
133+
//try Envelope next
134+
env, ok := o.(*pcommon.Envelope)
135+
if !ok || env == nil {
136+
return nil, nil, fmt.Errorf("error extracting valid chaincode package")
137+
}
138+
139+
//this will check for a valid package Envelope
140+
_, sCDS, err := ccpackage.ExtractSignedCCDepSpec(env)
141+
if err != nil {
142+
return nil, nil, fmt.Errorf("error extracting valid signed chaincode package(%s)", err)
143+
}
144+
145+
//...and get the CDS at last
146+
cds, err = utils.GetChaincodeDeploymentSpec(sCDS.ChaincodeDeploymentSpec)
147+
if err != nil {
148+
return nil, nil, fmt.Errorf("error extracting chaincode deployment spec(%s)", err)
149+
}
150+
}
151+
152+
return o, cds, nil
153+
}
154+
155+
// chaincodeInstall installs the chaincode. If remoteinstall, does it via a lccc call
156+
func chaincodeInstall(cmd *cobra.Command, ccpackfile string, cf *ChaincodeCmdFactory) error {
89157
var err error
90158
if cf == nil {
91159
cf, err = InitCmdFactory(true, false)
@@ -94,22 +162,42 @@ func chaincodeInstall(cmd *cobra.Command, args []string, cf *ChaincodeCmdFactory
94162
}
95163
}
96164

97-
tmppkg, _ := ccprovider.GetChaincodePackage(chaincodeName, chaincodeVersion)
98-
if tmppkg != nil {
99-
return fmt.Errorf("chaincode %s:%s exists", chaincodeName, chaincodeVersion)
100-
}
165+
var ccpackmsg proto.Message
166+
if ccpackfile == "" {
167+
if chaincodePath == common.UndefinedParamValue || chaincodeVersion == common.UndefinedParamValue {
168+
return fmt.Errorf("Must supply value for %s path and version parameters.", chainFuncName)
169+
}
170+
//generate a raw ChaincodeDeploymentSpec
171+
ccpackmsg, err = generateChaincode(cmd, chaincodeName, chaincodeVersion)
172+
if err != nil {
173+
return err
174+
}
175+
} else {
176+
//read in a package generated by the "package" sub-command (and perhaps signed
177+
//by multiple owners with the "signpackage" sub-command)
178+
var cds *pb.ChaincodeDeploymentSpec
179+
ccpackmsg, cds, err = getPackageFromFile(ccpackfile)
101180

102-
spec, err := getChaincodeSpecification(cmd)
103-
if err != nil {
104-
return err
105-
}
181+
if err != nil {
182+
return err
183+
}
106184

107-
cds, err := getChaincodeBytes(spec, true)
108-
if err != nil {
109-
return fmt.Errorf("Error getting chaincode code %s: %s", chainFuncName, err)
185+
//get the chaincode details from cds
186+
cName := cds.ChaincodeSpec.ChaincodeId.Name
187+
cVersion := cds.ChaincodeSpec.ChaincodeId.Version
188+
189+
//if user provided chaincodeName, use it for validation
190+
if chaincodeName != "" && chaincodeName != cName {
191+
return fmt.Errorf("chaincode name %s does not match name %s in package", chaincodeName, cName)
192+
}
193+
194+
//if user provided chaincodeVersion, use it for validation
195+
if chaincodeVersion != "" && chaincodeVersion != cVersion {
196+
return fmt.Errorf("chaincode version %s does not match version %s in packages", chaincodeVersion, cVersion)
197+
}
110198
}
111199

112-
err = install(chaincodeName, chaincodeVersion, cds, cf)
200+
err = install(ccpackmsg, cf)
113201

114202
return err
115203
}

0 commit comments

Comments
 (0)