Skip to content

Commit c810332

Browse files
author
Srinivasan Muralidharan
committed
FAB-3030 intf. to deal with different package types
https://jira.hyperledger.org/browse/FAB-3030 We have now two ways to install a chaincode on the FS raw ChaincodeDeploymentSpec (current model) SignedChaincodeDeploymentSpec (under implementation) This checking prepares higher level components such as LCCC use fabric to use either package types seamlessly. This paves the way for install to use either types of packages. Change-Id: I24c68db5e58d1b64956806bec9919128788c7730 Signed-off-by: Srinivasan Muralidharan <[email protected]>
1 parent a443a59 commit c810332

File tree

7 files changed

+627
-41
lines changed

7 files changed

+627
-41
lines changed

core/common/ccpackage/ccpackage.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ import (
2828
"github.com/hyperledger/fabric/protos/utils"
2929
)
3030

31-
// extractSignedCCDepSpec extracts the messages from the envelope
32-
func extractSignedCCDepSpec(env *common.Envelope) (*common.ChannelHeader, *peer.SignedChaincodeDeploymentSpec, error) {
31+
// ExtractSignedCCDepSpec extracts the messages from the envelope
32+
func ExtractSignedCCDepSpec(env *common.Envelope) (*common.ChannelHeader, *peer.SignedChaincodeDeploymentSpec, error) {
3333
p := &common.Payload{}
3434
err := proto.Unmarshal(env.Payload, p)
3535
if err != nil {
@@ -214,7 +214,7 @@ func SignExistingPackage(env *common.Envelope, owner msp.SigningIdentity) (*comm
214214
return nil, fmt.Errorf("owner not provided")
215215
}
216216

217-
ch, sdepspec, err := extractSignedCCDepSpec(env)
217+
ch, sdepspec, err := ExtractSignedCCDepSpec(env)
218218
if err != nil {
219219
return nil, err
220220
}

core/common/ccprovider/ccprovider.go

+47-34
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,30 @@ var ccproviderLogger = logging.MustGetLogger("ccprovider")
3535

3636
var chaincodeInstallPath string
3737

38+
//CCPackage encapsulates a chaincode package which can be
39+
// raw ChaincodeDeploymentSpec
40+
// SignedChaincodeDeploymentSpec
41+
// Attempt to keep the interface at a level with minimal
42+
// interface for possible generalization.
43+
type CCPackage interface {
44+
//InitFromBuffer initialize the package from bytes
45+
InitFromBuffer(buf []byte) (*ChaincodeData, error)
46+
47+
// InitFromFS gets the chaincode from the filesystem (includes the raw bytes too)
48+
InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error)
49+
50+
// GetDepSpec gets the ChaincodeDeploymentSpec from the package
51+
GetDepSpec() *pb.ChaincodeDeploymentSpec
52+
53+
// PutChaincodeToFS writes the chaincode to the filesystem
54+
PutChaincodeToFS() error
55+
56+
// ValidateCC validates and returns the chaincode deployment spec corresponding to
57+
// ChaincodeData. The validation is based on the metadata from ChaincodeData
58+
// One use of this method is to validate the chaincode before launching
59+
ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error)
60+
}
61+
3862
//SetChaincodesPath sets the chaincode path for this peer
3963
func SetChaincodesPath(path string) {
4064
if s, err := os.Stat(path); err != nil {
@@ -63,49 +87,38 @@ func GetChaincodePackage(ccname string, ccversion string) ([]byte, error) {
6387
return ccbytes, nil
6488
}
6589

66-
//GetChaincodeFromFS returns the chaincode and its package from the file system
90+
// GetChaincodeFromFS this is a wrapper for hiding package implementation.
6791
func GetChaincodeFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
68-
//NOTE- this is the only place from where we get code from file system
69-
//this API needs to be modified to take other params for security.
70-
//this implementation needs to be enhanced to do those security checks
71-
ccbytes, err := GetChaincodePackage(ccname, ccversion)
72-
if err != nil {
73-
return nil, nil, err
74-
}
75-
76-
cdsfs := &pb.ChaincodeDeploymentSpec{}
77-
err = proto.Unmarshal(ccbytes, cdsfs)
78-
if err != nil {
79-
return nil, nil, fmt.Errorf("failed to unmarshal fs deployment spec for %s, %s", ccname, ccversion)
80-
}
81-
82-
return ccbytes, cdsfs, nil
92+
cccdspack := &CDSPackage{}
93+
return cccdspack.InitFromFS(ccname, ccversion)
8394
}
8495

85-
//PutChaincodeIntoFS - serializes chaincode to a package on the file system
96+
// PutChaincodeIntoFS is a wrapper for putting raw ChaincodeDeploymentSpec
97+
//using CDSPackage. This is only used in UTs
8698
func PutChaincodeIntoFS(depSpec *pb.ChaincodeDeploymentSpec) error {
87-
//NOTE- this is only place from where we put code into file system
88-
//this API needs to be modified to take other params for security.
89-
//this implementation needs to be enhanced to do those security checks
90-
ccname := depSpec.ChaincodeSpec.ChaincodeId.Name
91-
ccversion := depSpec.ChaincodeSpec.ChaincodeId.Version
92-
93-
//return error if chaincode exists
94-
path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)
95-
if _, err := os.Stat(path); err == nil {
96-
return fmt.Errorf("chaincode %s exists", path)
97-
}
98-
99-
b, err := proto.Marshal(depSpec)
99+
buf, err := proto.Marshal(depSpec)
100100
if err != nil {
101-
return fmt.Errorf("failed to marshal fs deployment spec for %s, %s", ccname, ccversion)
101+
return err
102102
}
103-
104-
if err = ioutil.WriteFile(path, b, 0644); err != nil {
103+
cccdspack := &CDSPackage{}
104+
if _, err := cccdspack.InitFromBuffer(buf); err != nil {
105105
return err
106106
}
107+
return cccdspack.PutChaincodeToFS()
108+
}
107109

108-
return nil
110+
// GetCCPackage tries each known package implementation one by one
111+
// till the right package is found
112+
func GetCCPackage(buf []byte) (CCPackage, error) {
113+
cccdspack := &CDSPackage{}
114+
if _, err := cccdspack.InitFromBuffer(buf); err != nil {
115+
ccscdspack := &SignedCDSPackage{}
116+
if _, err := ccscdspack.InitFromBuffer(buf); err != nil {
117+
return nil, err
118+
}
119+
return ccscdspack, nil
120+
}
121+
return cccdspack, nil
109122
}
110123

111124
// GetInstalledChaincodes returns a map whose key is the chaincode id and

core/common/ccprovider/cdspackage.go

+116
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ccprovider
18+
19+
import (
20+
"fmt"
21+
"io/ioutil"
22+
"os"
23+
24+
"github.com/golang/protobuf/proto"
25+
26+
pb "github.com/hyperledger/fabric/protos/peer"
27+
)
28+
29+
//CDSPackage encapsulates ChaincodeDeploymentSpec.
30+
type CDSPackage struct {
31+
buf []byte
32+
depSpec *pb.ChaincodeDeploymentSpec
33+
}
34+
35+
// GetDepSpec gets the ChaincodeDeploymentSpec from the package
36+
func (ccpack *CDSPackage) GetDepSpec() *pb.ChaincodeDeploymentSpec {
37+
return ccpack.depSpec
38+
}
39+
40+
// ValidateCC returns error if the chaincode is not found or if its not a
41+
// ChaincodeDeploymentSpec
42+
func (ccpack *CDSPackage) ValidateCC(ccdata *ChaincodeData) (*pb.ChaincodeDeploymentSpec, error) {
43+
if ccpack.depSpec == nil {
44+
return nil, fmt.Errorf("uninitialized package")
45+
}
46+
if ccdata.Name != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name || ccdata.Version != ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version {
47+
return nil, fmt.Errorf("invalid chaincode data %v (%v)", ccdata, ccpack.depSpec.ChaincodeSpec.ChaincodeId)
48+
}
49+
//for now just return chaincode. When we introduce Hash we will do more checks
50+
return ccpack.depSpec, nil
51+
}
52+
53+
//InitFromBuffer sets the buffer if valid and returns ChaincodeData
54+
func (ccpack *CDSPackage) InitFromBuffer(buf []byte) (*ChaincodeData, error) {
55+
//incase ccpack is reused
56+
ccpack.buf = nil
57+
ccpack.depSpec = nil
58+
59+
depSpec := &pb.ChaincodeDeploymentSpec{}
60+
err := proto.Unmarshal(buf, depSpec)
61+
if err != nil {
62+
return nil, fmt.Errorf("failed to unmarshal fs deployment spec from bytes")
63+
}
64+
ccpack.buf = buf
65+
ccpack.depSpec = depSpec
66+
return &ChaincodeData{Name: depSpec.ChaincodeSpec.ChaincodeId.Name, Version: depSpec.ChaincodeSpec.ChaincodeId.Version}, nil
67+
}
68+
69+
//InitFromFS returns the chaincode and its package from the file system
70+
func (ccpack *CDSPackage) InitFromFS(ccname string, ccversion string) ([]byte, *pb.ChaincodeDeploymentSpec, error) {
71+
//incase ccpack is reused
72+
ccpack.buf = nil
73+
ccpack.depSpec = nil
74+
75+
buf, err := GetChaincodePackage(ccname, ccversion)
76+
if err != nil {
77+
return nil, nil, err
78+
}
79+
80+
depSpec := &pb.ChaincodeDeploymentSpec{}
81+
err = proto.Unmarshal(buf, depSpec)
82+
if err != nil {
83+
return nil, nil, fmt.Errorf("failed to unmarshal fs deployment spec for %s, %s", ccname, ccversion)
84+
}
85+
86+
ccpack.buf = buf
87+
ccpack.depSpec = depSpec
88+
89+
return buf, depSpec, nil
90+
}
91+
92+
//PutChaincodeToFS - serializes chaincode to a package on the file system
93+
func (ccpack *CDSPackage) PutChaincodeToFS() error {
94+
if ccpack.buf == nil {
95+
return fmt.Errorf("uninitialized package")
96+
}
97+
98+
if ccpack.depSpec == nil {
99+
return fmt.Errorf("depspec cannot be nil if buf is not nil")
100+
}
101+
102+
ccname := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Name
103+
ccversion := ccpack.depSpec.ChaincodeSpec.ChaincodeId.Version
104+
105+
//return error if chaincode exists
106+
path := fmt.Sprintf("%s/%s.%s", chaincodeInstallPath, ccname, ccversion)
107+
if _, err := os.Stat(path); err == nil {
108+
return fmt.Errorf("chaincode %s exists", path)
109+
}
110+
111+
if err := ioutil.WriteFile(path, ccpack.buf, 0644); err != nil {
112+
return err
113+
}
114+
115+
return nil
116+
}
+137
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/*
2+
Copyright IBM Corp. 2017 All Rights Reserved.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package ccprovider
18+
19+
import (
20+
"io/ioutil"
21+
"os"
22+
"testing"
23+
24+
pb "github.com/hyperledger/fabric/protos/peer"
25+
"github.com/hyperledger/fabric/protos/utils"
26+
)
27+
28+
func setupccdir() string {
29+
tempDir, err := ioutil.TempDir("/tmp", "ccprovidertest")
30+
if err != nil {
31+
panic(err)
32+
}
33+
SetChaincodesPath(tempDir)
34+
return tempDir
35+
}
36+
37+
func TestPutCDSCC(t *testing.T) {
38+
ccdir := setupccdir()
39+
defer os.RemoveAll(ccdir)
40+
41+
cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "testcc", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}, CodePackage: []byte("code")}
42+
43+
b := utils.MarshalOrPanic(cds)
44+
45+
ccpack := &CDSPackage{}
46+
_, err := ccpack.InitFromBuffer(b)
47+
if err != nil {
48+
t.Fatalf("error owner creating package %s", err)
49+
return
50+
}
51+
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 {
58+
t.Fatalf("error validating package %s", err)
59+
return
60+
}
61+
}
62+
63+
func TestPutCDSErrorPaths(t *testing.T) {
64+
ccdir := setupccdir()
65+
defer os.RemoveAll(ccdir)
66+
67+
cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "testcc", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}, CodePackage: []byte("code")}
68+
69+
b := utils.MarshalOrPanic(cds)
70+
71+
ccpack := &CDSPackage{}
72+
_, err := ccpack.InitFromBuffer(b)
73+
if err != nil {
74+
t.Fatalf("error owner creating package %s", err)
75+
return
76+
}
77+
78+
//validate with invalid name
79+
if _, err = ccpack.ValidateCC(&ChaincodeData{Name: "invalname", Version: "0"}); err == nil {
80+
t.Fatalf("expected error validating package")
81+
return
82+
}
83+
//remove the buffer
84+
ccpack.buf = nil
85+
if err = ccpack.PutChaincodeToFS(); err == nil {
86+
t.Fatalf("expected error putting package on the FS")
87+
return
88+
}
89+
90+
//put back the buffer but remove the depspec
91+
ccpack.buf = b
92+
savDepSpec := ccpack.depSpec
93+
ccpack.depSpec = nil
94+
if err = ccpack.PutChaincodeToFS(); err == nil {
95+
t.Fatalf("expected error putting package on the FS")
96+
return
97+
}
98+
99+
//put back dep spec
100+
ccpack.depSpec = savDepSpec
101+
102+
//...but remove the chaincode directory
103+
os.RemoveAll(ccdir)
104+
if err = ccpack.PutChaincodeToFS(); err == nil {
105+
t.Fatalf("expected error putting package on the FS")
106+
return
107+
}
108+
}
109+
110+
func TestCDSGetCCPackage(t *testing.T) {
111+
cds := &pb.ChaincodeDeploymentSpec{ChaincodeSpec: &pb.ChaincodeSpec{Type: 1, ChaincodeId: &pb.ChaincodeID{Name: "testcc", Version: "0"}, Input: &pb.ChaincodeInput{Args: [][]byte{[]byte("")}}}, CodePackage: []byte("code")}
112+
113+
b := utils.MarshalOrPanic(cds)
114+
115+
ccpack, err := GetCCPackage(b)
116+
if err != nil {
117+
t.Fatalf("failed to get CDS CCPackage %s", err)
118+
return
119+
}
120+
121+
cccdspack, ok := ccpack.(*CDSPackage)
122+
if !ok || cccdspack == nil {
123+
t.Fatalf("failed to get CDS CCPackage")
124+
return
125+
}
126+
127+
cds2 := cccdspack.GetDepSpec()
128+
if cds2 == nil {
129+
t.Fatalf("nil dep spec in CDS CCPackage")
130+
return
131+
}
132+
133+
if cds2.ChaincodeSpec.ChaincodeId.Name != cds.ChaincodeSpec.ChaincodeId.Name || cds2.ChaincodeSpec.ChaincodeId.Version != cds.ChaincodeSpec.ChaincodeId.Version {
134+
t.Fatalf("dep spec in CDS CCPackage does not match %v != %v", cds, cds2)
135+
return
136+
}
137+
}

0 commit comments

Comments
 (0)