Skip to content

Commit 36a4a8f

Browse files
wlahtimastersingh24
authored andcommitted
FAB-10720 Persistence for new cc install package
This CR adds a way to persist a ChaincodeInstallPackage on the filesystem. Change-Id: I59c066ba7b7577904cc78ba34722c3851d51b97d Signed-off-by: Will Lahti <wtlahti@us.ibm.com>
1 parent 528dff0 commit 36a4a8f

File tree

4 files changed

+534
-0
lines changed

4 files changed

+534
-0
lines changed

core/chaincode/persistence/mock/iowriter.go

Lines changed: 231 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package persistence
8+
9+
import (
10+
"encoding/hex"
11+
"encoding/json"
12+
"io/ioutil"
13+
"os"
14+
"path/filepath"
15+
16+
"github.com/hyperledger/fabric/common/flogging"
17+
"github.com/hyperledger/fabric/common/util"
18+
"github.com/pkg/errors"
19+
)
20+
21+
var logger = flogging.MustGetLogger("chaincode/persistence")
22+
23+
// IOWriter defines the interface needed for adding/removing/checking for existence
24+
// of a specified file
25+
type IOWriter interface {
26+
WriteFile(string, []byte, os.FileMode) error
27+
Stat(string) (os.FileInfo, error)
28+
Remove(name string) error
29+
}
30+
31+
// FilesystemWriter is the production implementation of the IOWriter interface
32+
type FilesystemWriter struct {
33+
}
34+
35+
// WriteFile writes a file to the filesystem
36+
func (f *FilesystemWriter) WriteFile(filename string, data []byte, perm os.FileMode) error {
37+
return ioutil.WriteFile(filename, data, perm)
38+
}
39+
40+
// Stat checks for existence of the file on the filesystem
41+
func (f *FilesystemWriter) Stat(name string) (os.FileInfo, error) {
42+
return os.Stat(name)
43+
}
44+
45+
// Remove removes a file from the filesystem - used for rolling back an in-flight
46+
// Save operation upon a failure
47+
func (f *FilesystemWriter) Remove(name string) error {
48+
return os.Remove(name)
49+
}
50+
51+
// Store holds the information needed for persisting a chaincode install package
52+
type Store struct {
53+
Path string
54+
Writer IOWriter
55+
}
56+
57+
// Save persists chaincode install package bytes with the given name
58+
// and version
59+
func (s *Store) Save(name, version string, ccInstallPkg []byte) error {
60+
metadataJSON, err := toJSON(name, version)
61+
if err != nil {
62+
return err
63+
}
64+
65+
hashString := hex.EncodeToString(util.ComputeSHA256(ccInstallPkg))
66+
metadataPath := filepath.Join(s.Path, hashString+".json")
67+
if _, err := s.Writer.Stat(metadataPath); err == nil {
68+
return errors.Errorf("chaincode metadata already exists at %s", metadataPath)
69+
}
70+
71+
ccInstallPkgPath := filepath.Join(s.Path, hashString+".bin")
72+
if _, err := s.Writer.Stat(ccInstallPkgPath); err == nil {
73+
return errors.Errorf("ChaincodeInstallPackage already exists at %s", ccInstallPkgPath)
74+
}
75+
76+
if err := s.Writer.WriteFile(metadataPath, metadataJSON, 0600); err != nil {
77+
return errors.Wrapf(err, "error writing metadata file to %s", metadataPath)
78+
}
79+
80+
if err := s.Writer.WriteFile(ccInstallPkgPath, ccInstallPkg, 0600); err != nil {
81+
err = errors.Wrapf(err, "error writing chaincode install package to %s", ccInstallPkgPath)
82+
logger.Error(err.Error())
83+
84+
// need to roll back metadata write above on error
85+
if err2 := s.Writer.Remove(metadataPath); err2 != nil {
86+
logger.Errorf("error removing metadata file at %s: %s", metadataPath, err2)
87+
}
88+
return err
89+
}
90+
91+
return nil
92+
}
93+
94+
// ChaincodeMetadata holds the name and version of a chaincode
95+
type ChaincodeMetadata struct {
96+
Name string `json:"Name"`
97+
Version string `json:"Version"`
98+
}
99+
100+
func toJSON(name, version string) ([]byte, error) {
101+
metadata := &ChaincodeMetadata{
102+
Name: name,
103+
Version: version,
104+
}
105+
106+
metadataBytes, err := json.Marshal(metadata)
107+
if err != nil {
108+
return nil, errors.Wrap(err, "failed to marshal name and version into JSON")
109+
}
110+
111+
return metadataBytes, nil
112+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package persistence_test
8+
9+
import (
10+
"testing"
11+
12+
"github.com/hyperledger/fabric/core/chaincode/persistence"
13+
. "github.com/onsi/ginkgo"
14+
. "github.com/onsi/gomega"
15+
)
16+
17+
//go:generate counterfeiter -o mock/iowriter.go -fake-name IOWriter . ioWriter
18+
type ioWriter interface {
19+
persistence.IOWriter
20+
}
21+
22+
func TestPersistence(t *testing.T) {
23+
RegisterFailHandler(Fail)
24+
RunSpecs(t, "Persistence Suite")
25+
}

0 commit comments

Comments
 (0)