Skip to content

Commit 1616277

Browse files
author
Srinivasan Muralidharan
committed
[FAB-2928] link installation to instantiation [part-2]
This adds package specific signature to LCCC on instantiations. It also prevents launching of chaincodes if the installed chaincode does not match the signature of the instanitated chaincode. In particular, it ensures future installs that don't comply with the corresponding instantiation will be useless (cannot invoke them).. Also refactored getChaincode function per Binh's suggestion in Part-1. Change-Id: I107c91a80002a336e42aff95d4aed7efe4141ead Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent 207588e commit 1616277

9 files changed

+421
-140
lines changed

core/chaincode/chaincode_support.go

+13-9
Original file line numberDiff line numberDiff line change
@@ -537,6 +537,7 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
537537
var depPayload []byte
538538

539539
//hopefully we are restarting from existing image and the deployed transaction exists
540+
//this will also validate the ID from the LCCC
540541
depPayload, err = GetCDSFromLCCC(context, cccid.TxID, cccid.SignedProposal, cccid.Proposal, cccid.ChainID, cID.Name)
541542
if err != nil {
542543
return cID, cMsg, fmt.Errorf("Could not get deployment transaction from LCCC for %s - %s", canName, err)
@@ -558,21 +559,24 @@ func (chaincodeSupport *ChaincodeSupport) Launch(context context.Context, cccid
558559

559560
//launch container if it is a System container or not in dev mode
560561
if (!chaincodeSupport.userRunsCC || cds.ExecEnv == pb.ChaincodeDeploymentSpec_SYSTEM) && (chrte == nil || chrte.handler == nil) {
561-
//whether we deploying, upgrading or launching a chaincode we now have a
562-
//deployment package. If lauching, we got it from LCCC and has gone through
563-
//ccprovider.GetChaincodeFromFS
562+
//NOTE-We need to streamline code a bit so the data from LCCC gets passed to this thus
563+
//avoiding the need to go to the FS. In particular, we should use cdsfs completely. It is
564+
//just a vestige of old protocol that we continue to use ChaincodeDeploymentSpec for
565+
//anything other than Install. In particular, instantiate, invoke, upgrade should be using
566+
//just some form of ChaincodeInvocationSpec.
567+
//
568+
//But for now, if we are invoking we have gone through the LCCC path above. If instantiating
569+
//or upgrading currently we send a CDS with nil CodePackage. In this case the codepath
570+
//in the endorser has gone through LCCC validation. Just get the code from the FS.
564571
if cds.CodePackage == nil {
565572
//no code bytes for these situations
566573
if !(chaincodeSupport.userRunsCC || cds.ExecEnv == pb.ChaincodeDeploymentSpec_SYSTEM) {
567-
_, cdsfs, err := ccprovider.GetChaincodeFromFS(cID.Name, cID.Version)
574+
ccpack, err := ccprovider.GetChaincodeFromFS(cID.Name, cID.Version)
568575
if err != nil {
569576
return cID, cMsg, err
570577
}
571-
//we should use cdsfs completely. It is just a vestige of old protocol that we
572-
//continue to use ChaincodeDeploymentSpec for anything other than Install. In
573-
//particular, instantiate, invoke, upgrade should be using just some form of
574-
//ChaincodeInvocationSpec.
575-
cds = cdsfs
578+
579+
cds = ccpack.GetDepSpec()
576580
chaincodeLogger.Debugf("launchAndWaitForRegister fetched %d from file system", len(cds.CodePackage), err)
577581
}
578582
}

core/chaincode/upgrade_test.go

+3
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ func upgrade2(ctx context.Context, cccid *ccprovider.CCContext,
8080
}
8181
}()
8282

83+
//ignore existence errors
84+
ccprovider.PutChaincodeIntoFS(chaincodeDeploymentSpec)
85+
8386
sysCCVers := util.GetSysCCVersion()
8487
lcccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, nil, nil)
8588

core/common/ccprovider/ccprovider.go

+26-9
Original file line numberDiff line numberDiff line change
@@ -47,19 +47,28 @@ type CCPackage interface {
4747
// InitFromFS gets the chaincode from the filesystem (includes the raw bytes too)
4848
InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error)
4949

50+
// PutChaincodeToFS writes the chaincode to the filesystem
51+
PutChaincodeToFS() error
52+
5053
// GetDepSpec gets the ChaincodeDeploymentSpec from the package
5154
GetDepSpec() *pb.ChaincodeDeploymentSpec
5255

53-
// PutChaincodeToFS writes the chaincode to the filesystem
54-
PutChaincodeToFS() error
56+
// GetDepSpecBytes gets the serialized ChaincodeDeploymentSpec from the package
57+
GetDepSpecBytes() []byte
5558

5659
// ValidateCC validates and returns the chaincode deployment spec corresponding to
5760
// ChaincodeData. The validation is based on the metadata from ChaincodeData
5861
// One use of this method is to validate the chaincode before launching
59-
ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error)
62+
ValidateCC(ccdata *ChaincodeData) error
6063

6164
// GetPackageObject gets the object as a proto.Message
6265
GetPackageObject() proto.Message
66+
67+
// GetChaincodeData gets the ChaincodeData
68+
GetChaincodeData() *ChaincodeData
69+
70+
// GetId gets the fingerprint of the chaincode based on package computation
71+
GetId() []byte
6372
}
6473

6574
//SetChaincodesPath sets the chaincode path for this peer
@@ -91,19 +100,20 @@ func GetChaincodePackage(ccname string, ccversion string) ([]byte, error) {
91100
}
92101

93102
// GetChaincodeFromFS this is a wrapper for hiding package implementation.
94-
func GetChaincodeFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
103+
func GetChaincodeFromFS(ccname string, ccversion string) (CCPackage, error) {
95104
//try raw CDS
96105
cccdspack := &CDSPackage{}
97-
b, depSpec, err := cccdspack.InitFromFS(ccname, ccversion)
106+
_, _, err := cccdspack.InitFromFS(ccname, ccversion)
98107
if err != nil {
99108
//try signed CDS
100109
ccscdspack := &SignedCDSPackage{}
101-
b, depSpec, err = ccscdspack.InitFromFS(ccname, ccversion)
110+
_, _, err = ccscdspack.InitFromFS(ccname, ccversion)
102111
if err != nil {
103-
return nil, nil, err
112+
return nil, err
104113
}
114+
return ccscdspack, nil
105115
}
106-
return b, depSpec, nil
116+
return cccdspack, nil
107117
}
108118

109119
// PutChaincodeIntoFS is a wrapper for putting raw ChaincodeDeploymentSpec
@@ -158,14 +168,16 @@ func GetInstalledChaincodes() (*pb.ChaincodeQueryResponse, error) {
158168
if len(fileNameArray) == 2 {
159169
ccname := fileNameArray[0]
160170
ccversion := fileNameArray[1]
161-
_, cdsfs, err := GetChaincodeFromFS(ccname, ccversion)
171+
ccpack, err := GetChaincodeFromFS(ccname, ccversion)
162172
if err != nil {
163173
// either chaincode on filesystem has been tampered with or
164174
// a non-chaincode file has been found in the chaincodes directory
165175
ccproviderLogger.Errorf("Unreadable chaincode file found on filesystem: %s", file.Name())
166176
continue
167177
}
168178

179+
cdsfs := ccpack.GetDepSpec()
180+
169181
name := cdsfs.GetChaincodeSpec().GetChaincodeId().Name
170182
version := cdsfs.GetChaincodeSpec().GetChaincodeId().Version
171183
if name != ccname || version != ccversion {
@@ -273,6 +285,11 @@ type ChaincodeData struct {
273285

274286
//Data data specific to the package
275287
Data []byte `protobuf:"bytes,6,opt,name=data,proto3"`
288+
289+
//Id of the chaincode that's the unique fingerprint for the CC
290+
//This is not currently used anywhere but serves as a good
291+
//eyecatcher
292+
Id []byte `protobuf:"bytes,7,opt,name=id,proto3"`
276293
}
277294

278295
//implement functions needed from proto.Message for proto's mar/unmarshal functions

core/common/ccprovider/cdspackage.go

+79-34
Original file line numberDiff line numberDiff line change
@@ -66,19 +66,61 @@ type CDSPackage struct {
6666
buf []byte
6767
depSpec *pb.ChaincodeDeploymentSpec
6868
data *CDSData
69+
datab []byte
70+
id []byte
71+
}
72+
73+
// resets data
74+
func (ccpack *CDSPackage) reset() {
75+
*ccpack = CDSPackage{}
76+
}
77+
78+
// GetId gets the fingerprint of the chaincode based on package computation
79+
func (ccpack *CDSPackage) GetId() []byte {
80+
//this has to be after creating a package and initializing it
81+
//If those steps fail, GetId() should never be called
82+
if ccpack.id == nil {
83+
panic("GetId called on uninitialized package")
84+
}
85+
return ccpack.id
6986
}
7087

7188
// GetDepSpec gets the ChaincodeDeploymentSpec from the package
7289
func (ccpack *CDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec {
90+
//this has to be after creating a package and initializing it
91+
//If those steps fail, GetDepSpec() should never be called
92+
if ccpack.depSpec == nil {
93+
panic("GetDepSpec called on uninitialized package")
94+
}
7395
return ccpack.depSpec
7496
}
7597

98+
// GetDepSpecBytes gets the serialized ChaincodeDeploymentSpec from the package
99+
func (ccpack *CDSPackage) GetDepSpecBytes() []byte {
100+
//this has to be after creating a package and initializing it
101+
//If those steps fail, GetDepSpecBytes() should never be called
102+
if ccpack.buf == nil {
103+
panic("GetDepSpecBytes called on uninitialized package")
104+
}
105+
return ccpack.buf
106+
}
107+
76108
// GetPackageObject gets the ChaincodeDeploymentSpec as proto.Message
77109
func (ccpack *CDSPackage) GetPackageObject() proto.Message {
78110
return ccpack.depSpec
79111
}
80112

81-
func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, *CDSData, error) {
113+
// GetChaincodeData gets the ChaincodeData
114+
func (ccpack *CDSPackage) GetChaincodeData() *ChaincodeData {
115+
//this has to be after creating a package and initializing it
116+
//If those steps fail, GetChaincodeData() should never be called
117+
if ccpack.depSpec == nil || ccpack.datab == nil || ccpack.id == nil {
118+
panic("GetChaincodeData called on uninitialized package")
119+
}
120+
return &ChaincodeData{Name: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name, Version: ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version, Data: ccpack.datab, Id: ccpack.id}
121+
}
122+
123+
func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, []byte, *CDSData, error) {
82124
// check for nil argument. It is an assertion that getCDSData
83125
// is never called on a package that did not go through/succeed
84126
// package initialization.
@@ -88,17 +130,17 @@ func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, *
88130

89131
b, err := proto.Marshal(cds)
90132
if err != nil {
91-
return nil, nil, err
133+
return nil, nil, nil, err
92134
}
93135

94136
if err = factory.InitFactories(nil); err != nil {
95-
return nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err)
137+
return nil, nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err)
96138
}
97139

98140
//compute hashes now
99141
hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{})
100142
if err != nil {
101-
return nil, nil, err
143+
return nil, nil, nil, err
102144
}
103145

104146
cdsdata := &CDSData{}
@@ -116,93 +158,88 @@ func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, *
116158

117159
b, err = proto.Marshal(cdsdata)
118160
if err != nil {
119-
return nil, nil, err
161+
return nil, nil, nil, err
120162
}
121163

122-
return b, cdsdata, nil
164+
hash.Reset()
165+
166+
//compute the id
167+
hash.Write(cdsdata.CodeHash)
168+
hash.Write(cdsdata.MetaDataHash)
169+
170+
id := hash.Sum(nil)
171+
172+
return b, id, cdsdata, nil
123173
}
124174

125175
// ValidateCC returns error if the chaincode is not found or if its not a
126176
// ChaincodeDeploymentSpec
127-
func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error) {
177+
func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) error {
128178
if ccpack.depSpec == nil {
129-
return nil, fmt.Errorf("uninitialized package")
179+
return fmt.Errorf("uninitialized package")
130180
}
131181

132182
if ccpack.data == nil {
133-
return nil, fmt.Errorf("nil data")
183+
return fmt.Errorf("nil data")
134184
}
135185

136186
if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version {
137-
return nil, fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)
187+
return fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)
138188
}
139189

140190
otherdata := &CDSData{}
141191
err := proto.Unmarshal(ccdata.Data, otherdata)
142192
if err != nil {
143-
return nil, err
193+
return err
144194
}
145195

146196
if !ccpack.data.Equals(otherdata) {
147-
return nil, fmt.Errorf("data mismatch")
197+
return fmt.Errorf("data mismatch")
148198
}
149199

150-
return ccpack.depSpec, nil
200+
return nil
151201
}
152202

153203
//InitFromBuffer sets the buffer if valid and returns ChaincodeData
154204
func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) {
155205
//incase ccpack is reused
156-
ccpack.buf = nil
157-
ccpack.depSpec = nil
158-
ccpack.data = nil
206+
ccpack.reset()
159207

160208
depSpec := &pb.ChaincodeDeploymentSpec{}
161209
err := proto.Unmarshal(buf, depSpec)
162210
if err != nil {
163211
return nil, fmt.Errorf("failed to unmarshal deployment spec from bytes")
164212
}
165213

166-
databytes, data, err := ccpack.getCDSData(depSpec)
214+
databytes, id, data, err := ccpack.getCDSData(depSpec)
167215
if err != nil {
168216
return nil, err
169217
}
170218

171219
ccpack.buf = buf
172220
ccpack.depSpec = depSpec
173221
ccpack.data = data
222+
ccpack.datab = databytes
223+
ccpack.id = id
174224

175-
return &ChaincodeData{Name: depSpec.ChaincodeSpec.ChaincodeId.Name, Version: depSpec.ChaincodeSpec.ChaincodeId.Version, Data: databytes}, nil
225+
return ccpack.GetChaincodeData(), nil
176226
}
177227

178228
//InitFromFS returns the chaincode and its package from the file system
179229
func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
180230
//incase ccpack is reused
181-
ccpack.buf = nil
182-
ccpack.depSpec = nil
183-
ccpack.data = nil
231+
ccpack.reset()
184232

185233
buf, err := GetChaincodePackage(ccname, ccversion)
186234
if err != nil {
187235
return nil, nil, err
188236
}
189237

190-
depSpec := &pb.ChaincodeDeploymentSpec{}
191-
err = proto.Unmarshal(buf, depSpec)
192-
if err != nil {
193-
return nil, nil, fmt.Errorf("failed to unmarshal fs deployment spec for %s, %s", ccname, ccversion)
194-
}
195-
196-
_, data, err := ccpack.getCDSData(depSpec)
197-
if err != nil {
238+
if _, err = ccpack.InitFromBuffer(buf); err != nil {
198239
return nil, nil, err
199240
}
200241

201-
ccpack.buf = buf
202-
ccpack.depSpec = depSpec
203-
ccpack.data = data
204-
205-
return buf, depSpec, nil
242+
return ccpack.buf, ccpack.depSpec, nil
206243
}
207244

208245
//PutChaincodeToFS - serializes chaincode to a package on the file system
@@ -211,6 +248,10 @@ func (ccpack *CDSPackage) PutChaincodeToFS() error {
211248
return fmt.Errorf("uninitialized package")
212249
}
213250

251+
if ccpack.id == nil {
252+
return fmt.Errorf("id cannot be nil if buf is not nil")
253+
}
254+
214255
if ccpack.depSpec == nil {
215256
return fmt.Errorf("depspec cannot be nil if buf is not nil")
216257
}
@@ -219,6 +260,10 @@ func (ccpack *CDSPackage) PutChaincodeToFS() error {
219260
return fmt.Errorf("nil data")
220261
}
221262

263+
if ccpack.datab == nil {
264+
return fmt.Errorf("nil data bytes")
265+
}
266+
222267
ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name
223268
ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version
224269

core/common/ccprovider/cdspackage_test.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ func TestPutCDSCC(t *testing.T) {
6565
return
6666
}
6767

68-
if _, err = ccpack.ValidateCC(cd); err != nil {
68+
if err = ccpack.ValidateCC(cd); err != nil {
6969
t.Fatalf("error validating package %s", err)
7070
return
7171
}
@@ -84,7 +84,7 @@ func TestPutCDSErrorPaths(t *testing.T) {
8484
}
8585

8686
//validate with invalid name
87-
if _, err = ccpack.ValidateCC(&ChaincodeData{Name: "invalname", Version: "0"}); err == nil {
87+
if err = ccpack.ValidateCC(&ChaincodeData{Name: "invalname", Version: "0"}); err == nil {
8888
t.Fatalf("expected error validating package")
8989
return
9090
}
@@ -169,7 +169,7 @@ func TestCDSSwitchChaincodes(t *testing.T) {
169169
return
170170
}
171171

172-
if _, err = badccpack.ValidateCC(goodcd); err == nil {
172+
if err = badccpack.ValidateCC(goodcd); err == nil {
173173
t.Fatalf("expected goodcd to fail against bad package but succeeded!")
174174
return
175175
}

0 commit comments

Comments
 (0)