Skip to content

Commit d360f22

Browse files
author
Jason Yellick
committed
FAB-11520 Add implementation for ChaincodeInstall
This CR provides a basic implementation of a new ChaincodeInstall to be utilized by the new lifecycle SCC in a future CR. Makes #Done FAB-11520 Change-Id: Ie8efa507fd94c075bf1f1ae0f0b214f5936538a6 Signed-off-by: Jason Yellick <jyellick@us.ibm.com>
1 parent 0294774 commit d360f22

File tree

5 files changed

+351
-0
lines changed

5 files changed

+351
-0
lines changed

core/chaincode/lifecycle/lifecycle.go

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package lifecycle
8+
9+
import (
10+
"github.com/hyperledger/fabric/core/chaincode/persistence"
11+
12+
"github.com/pkg/errors"
13+
)
14+
15+
// ChaincodeStore provides a way to persist chaincodes
16+
type ChaincodeStore interface {
17+
Save(name, version string, ccInstallPkg []byte) (hash []byte, err error)
18+
}
19+
20+
type PackageParser interface {
21+
Parse(data []byte) (*persistence.ChaincodePackage, error)
22+
}
23+
24+
// Lifecycle implements the lifecycle operations which are invoked
25+
// by the SCC as well as internally
26+
type Lifecycle struct {
27+
ChaincodeStore ChaincodeStore
28+
PackageParser PackageParser
29+
}
30+
31+
// InstallChaincode installs a given chaincode to the peer's chaincode store.
32+
// It returns the hash to reference the chaincode by or an error on failure.
33+
func (l *Lifecycle) InstallChaincode(name, version string, chaincodeInstallPackage []byte) ([]byte, error) {
34+
// Let's validate that the chaincodeInstallPackage is at least well formed before writing it
35+
_, err := l.PackageParser.Parse(chaincodeInstallPackage)
36+
if err != nil {
37+
return nil, errors.WithMessage(err, "could not parse as a chaincode install package")
38+
}
39+
40+
hash, err := l.ChaincodeStore.Save(name, version, chaincodeInstallPackage)
41+
if err != nil {
42+
return nil, errors.WithMessage(err, "could not save cc install package")
43+
}
44+
45+
return hash, nil
46+
}

core/chaincode/lifecycle/lifecycle_suite_test.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
. "github.com/onsi/ginkgo"
1313
. "github.com/onsi/gomega"
1414

15+
"github.com/hyperledger/fabric/core/chaincode/lifecycle"
1516
"github.com/hyperledger/fabric/core/chaincode/shim"
1617
)
1718

@@ -20,6 +21,16 @@ type chaincodeStub interface {
2021
shim.ChaincodeStubInterface
2122
}
2223

24+
//go:generate counterfeiter -o mock/chaincode_store.go --fake-name ChaincodeStore . chaincodeStore
25+
type chaincodeStore interface {
26+
lifecycle.ChaincodeStore
27+
}
28+
29+
//go:generate counterfeiter -o mock/package_parser.go --fake-name PackageParser . packageParser
30+
type packageParser interface {
31+
lifecycle.PackageParser
32+
}
33+
2334
func TestLifecycle(t *testing.T) {
2435
RegisterFailHandler(Fail)
2536
RunSpecs(t, "Lifecycle Suite")
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package lifecycle_test
8+
9+
import (
10+
"fmt"
11+
12+
. "github.com/onsi/ginkgo"
13+
. "github.com/onsi/gomega"
14+
15+
"github.com/hyperledger/fabric/core/chaincode/lifecycle"
16+
"github.com/hyperledger/fabric/core/chaincode/lifecycle/mock"
17+
)
18+
19+
var _ = Describe("Lifecycle", func() {
20+
var (
21+
l *lifecycle.Lifecycle
22+
fakeCCStore *mock.ChaincodeStore
23+
fakeParser *mock.PackageParser
24+
)
25+
26+
BeforeEach(func() {
27+
fakeCCStore = &mock.ChaincodeStore{}
28+
fakeParser = &mock.PackageParser{}
29+
30+
l = &lifecycle.Lifecycle{
31+
PackageParser: fakeParser,
32+
ChaincodeStore: fakeCCStore,
33+
}
34+
})
35+
36+
Describe("InstallChaincode", func() {
37+
BeforeEach(func() {
38+
fakeCCStore.SaveReturns([]byte("fake-hash"), nil)
39+
})
40+
41+
It("saves the chaincode", func() {
42+
hash, err := l.InstallChaincode("name", "version", []byte("cc-package"))
43+
Expect(err).NotTo(HaveOccurred())
44+
Expect(hash).To(Equal([]byte("fake-hash")))
45+
46+
Expect(fakeParser.ParseCallCount()).To(Equal(1))
47+
Expect(fakeParser.ParseArgsForCall(0)).To(Equal([]byte("cc-package")))
48+
49+
Expect(fakeCCStore.SaveCallCount()).To(Equal(1))
50+
name, version, msg := fakeCCStore.SaveArgsForCall(0)
51+
Expect(name).To(Equal("name"))
52+
Expect(version).To(Equal("version"))
53+
Expect(msg).To(Equal([]byte("cc-package")))
54+
})
55+
56+
Context("when saving the chaincode fails", func() {
57+
BeforeEach(func() {
58+
fakeCCStore.SaveReturns(nil, fmt.Errorf("fake-error"))
59+
})
60+
61+
It("wraps and returns the error", func() {
62+
hash, err := l.InstallChaincode("name", "version", []byte("cc-package"))
63+
Expect(hash).To(BeNil())
64+
Expect(err).To(MatchError("could not save cc install package: fake-error"))
65+
})
66+
})
67+
68+
Context("when parsing the chaincode package fails", func() {
69+
BeforeEach(func() {
70+
fakeParser.ParseReturns(nil, fmt.Errorf("parse-error"))
71+
})
72+
73+
It("wraps and returns the error", func() {
74+
hash, err := l.InstallChaincode("name", "version", []byte("fake-package"))
75+
Expect(hash).To(BeNil())
76+
Expect(err).To(MatchError("could not parse as a chaincode install package: parse-error"))
77+
})
78+
})
79+
})
80+
})

core/chaincode/lifecycle/mock/chaincode_store.go

Lines changed: 108 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/chaincode/lifecycle/mock/package_parser.go

Lines changed: 106 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)