Skip to content

Commit 207588e

Browse files
author
Srinivasan Muralidharan
committed
[FAB-2928] link pkg with instantiation on lccc (part-1)
This Part-1 of the task to link the instantiation with the package which sets up the structures (especially ChaincodeData) to do the actuall linking in Part-2. Specifically * adds data to ChaincodeData specific to the package This data is essentially the hashes used for the linking * removes the ChaincodeDeploymentSpec that was still hanging around in the ChaincodeData (ie on the lccc table on the ledger) Change-Id: Ic14f3bdde661efe82791e4d7db7eb96f1de169ca Signed-off-by: Srinivasan Muralidharan <muralisr@us.ibm.com>
1 parent c9ecf9e commit 207588e

File tree

8 files changed

+437
-96
lines changed

8 files changed

+437
-96
lines changed

core/chaincode/upgrade_test.go

+10-5
Original file line numberDiff line numberDiff line change
@@ -83,17 +83,22 @@ func upgrade2(ctx context.Context, cccid *ccprovider.CCContext,
8383
sysCCVers := util.GetSysCCVersion()
8484
lcccid := ccprovider.NewCCContext(cccid.ChainID, cis.ChaincodeSpec.ChaincodeId.Name, sysCCVers, uuid, true, nil, nil)
8585

86-
var versionBytes []byte
86+
var cdbytes []byte
8787
//write to lccc
88-
if versionBytes, _, err = ExecuteWithErrorFilter(ctx, lcccid, cis); err != nil {
88+
if cdbytes, _, err = ExecuteWithErrorFilter(ctx, lcccid, cis); err != nil {
8989
return nil, fmt.Errorf("Error executing LCCC for upgrade: %s", err)
9090
}
9191

92-
if versionBytes == nil {
93-
return nil, fmt.Errorf("Expected version back from LCCC but got nil")
92+
if cdbytes == nil {
93+
return nil, fmt.Errorf("Expected ChaincodeData back from LCCC but got nil")
9494
}
9595

96-
newVersion := string(versionBytes)
96+
cd := &ccprovider.ChaincodeData{}
97+
if err = proto.Unmarshal(cdbytes, cd); err != nil {
98+
return nil, fmt.Errorf("getting ChaincodeData failed")
99+
}
100+
101+
newVersion := string(cd.Version)
97102
if newVersion == cccid.Version {
98103
return nil, fmt.Errorf("Expected new version from LCCC but got same %s(%s)", newVersion, cccid.Version)
99104
}

core/common/ccprovider/ccprovider.go

+20-5
Original file line numberDiff line numberDiff line change
@@ -250,14 +250,29 @@ func (cccid *CCContext) GetCanonicalName() string {
250250
return cccid.canonicalName
251251
}
252252

253+
//-------- ChaincodeData is stored on the LCCC -------
254+
253255
//ChaincodeData defines the datastructure for chaincodes to be serialized by proto
256+
//Type provides an additional check by directing to use a specific package after instantiation
257+
//Data is Type specifc (see CDSPackage and SignedCDSPackage)
254258
type ChaincodeData struct {
255-
Name string `protobuf:"bytes,1,opt,name=name"`
259+
//Name of the chaincode
260+
Name string `protobuf:"bytes,1,opt,name=name"`
261+
262+
//Version of the chaincode
256263
Version string `protobuf:"bytes,2,opt,name=version"`
257-
DepSpec []byte `protobuf:"bytes,3,opt,name=depSpec,proto3"`
258-
Escc string `protobuf:"bytes,4,opt,name=escc"`
259-
Vscc string `protobuf:"bytes,5,opt,name=vscc"`
260-
Policy []byte `protobuf:"bytes,6,opt,name=policy"`
264+
265+
//Escc for the chaincode instance
266+
Escc string `protobuf:"bytes,3,opt,name=escc"`
267+
268+
//Vscc for the chaincode instance
269+
Vscc string `protobuf:"bytes,4,opt,name=vscc"`
270+
271+
//Policy endorsement policy for the chaincode instance
272+
Policy []byte `protobuf:"bytes,5,opt,name=policy,proto3"`
273+
274+
//Data data specific to the package
275+
Data []byte `protobuf:"bytes,6,opt,name=data,proto3"`
261276
}
262277

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

core/common/ccprovider/cdspackage.go

+117-2
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,49 @@ import (
2323

2424
"github.com/golang/protobuf/proto"
2525

26+
"bytes"
27+
28+
"github.com/hyperledger/fabric/bccsp"
29+
"github.com/hyperledger/fabric/bccsp/factory"
2630
pb "github.com/hyperledger/fabric/protos/peer"
2731
)
2832

33+
//----- CDSData ------
34+
35+
//CDSData is data stored in the LCCC on instantiation of a CC
36+
//for CDSPackage. This needs to be serialized for ChaincodeData
37+
//hence the protobuf format
38+
type CDSData struct {
39+
//CodeHash hash of CodePackage from ChaincodeDeploymentSpec
40+
CodeHash []byte `protobuf:"bytes,1,opt,name=codehash,proto3"`
41+
42+
//MetaDataHash hash of Name and Version from ChaincodeDeploymentSpec
43+
MetaDataHash []byte `protobuf:"bytes,2,opt,name=metadatahash,proto3"`
44+
}
45+
46+
//----implement functions needed from proto.Message for proto's mar/unmarshal functions
47+
48+
//Reset resets
49+
func (data *CDSData) Reset() { *data = CDSData{} }
50+
51+
//String convers to string
52+
func (data *CDSData) String() string { return proto.CompactTextString(data) }
53+
54+
//ProtoMessage just exists to make proto happy
55+
func (*CDSData) ProtoMessage() {}
56+
57+
//Equals data equals other
58+
func (data *CDSData) Equals(other *CDSData) bool {
59+
return other != nil && bytes.Equal(data.CodeHash, other.CodeHash) && bytes.Equal(data.MetaDataHash, other.MetaDataHash)
60+
}
61+
62+
//--------- CDSPackage ------------
63+
2964
//CDSPackage encapsulates ChaincodeDeploymentSpec.
3065
type CDSPackage struct {
3166
buf []byte
3267
depSpec *pb.ChaincodeDeploymentSpec
68+
data *CDSData
3369
}
3470

3571
// GetDepSpec gets the ChaincodeDeploymentSpec from the package
@@ -42,16 +78,75 @@ func (ccpack *CDSPackage) GetPackageObject() proto.Message {
4278
return ccpack.depSpec
4379
}
4480

81+
func (ccpack *CDSPackage) getCDSData(cds *pb.ChaincodeDeploymentSpec) ([]byte, *CDSData, error) {
82+
// check for nil argument. It is an assertion that getCDSData
83+
// is never called on a package that did not go through/succeed
84+
// package initialization.
85+
if cds == nil {
86+
panic("nil cds")
87+
}
88+
89+
b, err := proto.Marshal(cds)
90+
if err != nil {
91+
return nil, nil, err
92+
}
93+
94+
if err = factory.InitFactories(nil); err != nil {
95+
return nil, nil, fmt.Errorf("Internal error, BCCSP could not be initialized : %s", err)
96+
}
97+
98+
//compute hashes now
99+
hash, err := factory.GetDefault().GetHash(&bccsp.SHAOpts{})
100+
if err != nil {
101+
return nil, nil, err
102+
}
103+
104+
cdsdata := &CDSData{}
105+
106+
//code hash
107+
cdsdata.CodeHash = hash.Sum(cds.CodePackage)
108+
109+
hash.Reset()
110+
111+
//metadata hash
112+
hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Name))
113+
hash.Write([]byte(cds.ChaincodeSpec.ChaincodeId.Version))
114+
115+
cdsdata.MetaDataHash = hash.Sum(nil)
116+
117+
b, err = proto.Marshal(cdsdata)
118+
if err != nil {
119+
return nil, nil, err
120+
}
121+
122+
return b, cdsdata, nil
123+
}
124+
45125
// ValidateCC returns error if the chaincode is not found or if its not a
46126
// ChaincodeDeploymentSpec
47127
func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error) {
48128
if ccpack.depSpec == nil {
49129
return nil, fmt.Errorf("uninitialized package")
50130
}
131+
132+
if ccpack.data == nil {
133+
return nil, fmt.Errorf("nil data")
134+
}
135+
51136
if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version {
52137
return nil, fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)
53138
}
54-
//for now just return chaincode. When we introduce Hash we will do more checks
139+
140+
otherdata := &CDSData{}
141+
err := proto.Unmarshal(ccdata.Data, otherdata)
142+
if err != nil {
143+
return nil, err
144+
}
145+
146+
if !ccpack.data.Equals(otherdata) {
147+
return nil, fmt.Errorf("data mismatch")
148+
}
149+
55150
return ccpack.depSpec, nil
56151
}
57152

@@ -60,22 +155,32 @@ func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) {
60155
//incase ccpack is reused
61156
ccpack.buf = nil
62157
ccpack.depSpec = nil
158+
ccpack.data = nil
63159

64160
depSpec := &pb.ChaincodeDeploymentSpec{}
65161
err := proto.Unmarshal(buf, depSpec)
66162
if err != nil {
67163
return nil, fmt.Errorf("failed to unmarshal deployment spec from bytes")
68164
}
165+
166+
databytes, data, err := ccpack.getCDSData(depSpec)
167+
if err != nil {
168+
return nil, err
169+
}
170+
69171
ccpack.buf = buf
70172
ccpack.depSpec = depSpec
71-
return &ChaincodeData{Name: depSpec.ChaincodeSpec.ChaincodeId.Name, Version: depSpec.ChaincodeSpec.ChaincodeId.Version}, nil
173+
ccpack.data = data
174+
175+
return &ChaincodeData{Name: depSpec.ChaincodeSpec.ChaincodeId.Name, Version: depSpec.ChaincodeSpec.ChaincodeId.Version, Data: databytes}, nil
72176
}
73177

74178
//InitFromFS returns the chaincode and its package from the file system
75179
func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
76180
//incase ccpack is reused
77181
ccpack.buf = nil
78182
ccpack.depSpec = nil
183+
ccpack.data = nil
79184

80185
buf, err := GetChaincodePackage(ccname, ccversion)
81186
if err != nil {
@@ -88,8 +193,14 @@ func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *
88193
return nil, nil, fmt.Errorf("failed to unmarshal fs deployment spec for %s, %s", ccname, ccversion)
89194
}
90195

196+
_, data, err := ccpack.getCDSData(depSpec)
197+
if err != nil {
198+
return nil, nil, err
199+
}
200+
91201
ccpack.buf = buf
92202
ccpack.depSpec = depSpec
203+
ccpack.data = data
93204

94205
return buf, depSpec, nil
95206
}
@@ -104,6 +215,10 @@ func (ccpack *CDSPackage) PutChaincodeToFS() error {
104215
return fmt.Errorf("depspec cannot be nil if buf is not nil")
105216
}
106217

218+
if ccpack.data == nil {
219+
return fmt.Errorf("nil data")
220+
}
221+
107222
ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name
108223
ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version
109224

core/common/ccprovider/cdspackage_test.go

+55-16
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ limitations under the License.
1717
package ccprovider
1818

1919
import (
20+
"fmt"
2021
"io/ioutil"
2122
"os"
2223
"testing"
@@ -34,27 +35,37 @@ func setupccdir() string {
3435
return tempDir
3536
}
3637

38+
func processCDS(cds *pb.ChaincodeDeploymentSpec, tofs bool) (*CDSPackage, []byte, *ChaincodeData, error) {
39+
b := utils.MarshalOrPanic(cds)
40+
41+
ccpack := &CDSPackage{}
42+
cd, err := ccpack.InitFromBuffer(b)
43+
if err != nil {
44+
return nil, nil, nil, fmt.Errorf("error owner creating package %s", err)
45+
}
46+
47+
if tofs {
48+
if err = ccpack.PutChaincodeToFS(); err != nil {
49+
return nil, nil, nil, fmt.Errorf("error putting package on the FS %s", err)
50+
}
51+
}
52+
53+
return ccpack, b, cd, nil
54+
}
55+
3756
func TestPutCDSCC(t *testing.T) {
3857
ccdir := setupccdir()
3958
defer os.RemoveAll(ccdir)
4059

4160
cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "testcc", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}, CodePackage: []byte("code")}
4261

43-
b := utils.MarshalOrPanic(cds)
44-
45-
ccpack := &CDSPackage{}
46-
_, err := ccpack.InitFromBuffer(b)
62+
ccpack, _, cd, err := processCDS(cds, true)
4763
if err != nil {
48-
t.Fatalf("error owner creating package %s", err)
64+
t.Fatalf("error putting CDS to FS %s", err)
4965
return
5066
}
5167

52-
if err = ccpack.PutChaincodeToFS(); err != nil {
53-
t.Fatalf("error putting package on the FS %s", err)
54-
return
55-
}
56-
57-
if _, err = ccpack.ValidateCC(&ChaincodeData{Name: "testcc", Version: "0"}); err != nil {
68+
if _, err = ccpack.ValidateCC(cd); err != nil {
5869
t.Fatalf("error validating package %s", err)
5970
return
6071
}
@@ -66,12 +77,9 @@ func TestPutCDSErrorPaths(t *testing.T) {
6677

6778
cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "testcc", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}, CodePackage: []byte("code")}
6879

69-
b := utils.MarshalOrPanic(cds)
70-
71-
ccpack := &CDSPackage{}
72-
_, err := ccpack.InitFromBuffer(b)
80+
ccpack, b, _, err := processCDS(cds, true)
7381
if err != nil {
74-
t.Fatalf("error owner creating package %s", err)
82+
t.Fatalf("error putting CDS to FS %s", err)
7583
return
7684
}
7785

@@ -135,3 +143,34 @@ func TestCDSGetCCPackage(t *testing.T) {
135143
return
136144
}
137145
}
146+
147+
//switch the chaincodes on the FS and validate
148+
func TestCDSSwitchChaincodes(t *testing.T) {
149+
ccdir := setupccdir()
150+
defer os.RemoveAll(ccdir)
151+
152+
//someone modified the code on the FS with "badcode"
153+
cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "testcc", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}, CodePackage: []byte("badcode")}
154+
155+
//write the bad code to the fs
156+
badccpack, _, _, err := processCDS(cds, true)
157+
if err != nil {
158+
t.Fatalf("error putting CDS to FS %s", err)
159+
return
160+
}
161+
162+
//mimic the good code ChaincodeData from the instantiate...
163+
cds.CodePackage = []byte("goodcode")
164+
165+
//...and generate the CD for it (don't overwrite the bad code)
166+
_, _, goodcd, err := processCDS(cds, false)
167+
if err != nil {
168+
t.Fatalf("error putting CDS to FS %s", err)
169+
return
170+
}
171+
172+
if _, err = badccpack.ValidateCC(goodcd); err == nil {
173+
t.Fatalf("expected goodcd to fail against bad package but succeeded!")
174+
return
175+
}
176+
}

0 commit comments

Comments
 (0)