1 Star 0 Fork 0

妥協/fabric

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
文件
克隆/下载
persistence.go 7.08 KB
一键复制 编辑 原始数据 按行查看 历史
Will Lahti 提交于 2018-10-29 12:07 . Replace / in logger names with dots
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package persistence
import (
"encoding/hex"
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/hyperledger/fabric/common/chaincode"
"github.com/hyperledger/fabric/common/flogging"
"github.com/hyperledger/fabric/common/util"
"github.com/pkg/errors"
)
var logger = flogging.MustGetLogger("chaincode.persistence")
// IOReadWriter defines the interface needed for reading, writing, removing, and
// checking for existence of a specified file
type IOReadWriter interface {
ReadDir(string) ([]os.FileInfo, error)
ReadFile(string) ([]byte, error)
Remove(name string) error
Stat(string) (os.FileInfo, error)
WriteFile(string, []byte, os.FileMode) error
}
// FilesystemIO is the production implementation of the IOWriter interface
type FilesystemIO struct {
}
// WriteFile writes a file to the filesystem
func (f *FilesystemIO) WriteFile(filename string, data []byte, perm os.FileMode) error {
return ioutil.WriteFile(filename, data, perm)
}
// Stat checks for existence of the file on the filesystem
func (f *FilesystemIO) Stat(name string) (os.FileInfo, error) {
return os.Stat(name)
}
// Remove removes a file from the filesystem - used for rolling back an in-flight
// Save operation upon a failure
func (f *FilesystemIO) Remove(name string) error {
return os.Remove(name)
}
// ReadFile reads a file from the filesystem
func (f *FilesystemIO) ReadFile(filename string) ([]byte, error) {
return ioutil.ReadFile(filename)
}
// ReadDir reads a directory from the filesystem
func (f *FilesystemIO) ReadDir(dirname string) ([]os.FileInfo, error) {
return ioutil.ReadDir(dirname)
}
// Store holds the information needed for persisting a chaincode install package
type Store struct {
Path string
ReadWriter IOReadWriter
}
// Save persists chaincode install package bytes with the given name
// and version
func (s *Store) Save(name, version string, ccInstallPkg []byte) ([]byte, error) {
metadataJSON, err := toJSON(name, version)
if err != nil {
return nil, err
}
hash := util.ComputeSHA256(ccInstallPkg)
hashString := hex.EncodeToString(hash)
metadataPath := filepath.Join(s.Path, hashString+".json")
if _, err := s.ReadWriter.Stat(metadataPath); err == nil {
return nil, errors.Errorf("chaincode metadata already exists at %s", metadataPath)
}
ccInstallPkgPath := filepath.Join(s.Path, hashString+".bin")
if _, err := s.ReadWriter.Stat(ccInstallPkgPath); err == nil {
return nil, errors.Errorf("ChaincodeInstallPackage already exists at %s", ccInstallPkgPath)
}
if err := s.ReadWriter.WriteFile(metadataPath, metadataJSON, 0600); err != nil {
return nil, errors.Wrapf(err, "error writing metadata file to %s", metadataPath)
}
if err := s.ReadWriter.WriteFile(ccInstallPkgPath, ccInstallPkg, 0600); err != nil {
err = errors.Wrapf(err, "error writing chaincode install package to %s", ccInstallPkgPath)
logger.Error(err.Error())
// need to roll back metadata write above on error
if err2 := s.ReadWriter.Remove(metadataPath); err2 != nil {
logger.Errorf("error removing metadata file at %s: %s", metadataPath, err2)
}
return nil, err
}
return hash, nil
}
// Load loads a persisted chaincode install package bytes with the given hash
// and also returns the name and version
func (s *Store) Load(hash []byte) (ccInstallPkg []byte, name, version string, err error) {
hashString := hex.EncodeToString(hash)
ccInstallPkgPath := filepath.Join(s.Path, hashString+".bin")
ccInstallPkg, err = s.ReadWriter.ReadFile(ccInstallPkgPath)
if err != nil {
err = errors.Wrapf(err, "error reading chaincode install package at %s", ccInstallPkgPath)
return nil, "", "", err
}
metadataPath := filepath.Join(s.Path, hashString+".json")
name, version, err = s.LoadMetadata(metadataPath)
if err != nil {
return nil, "", "", err
}
return ccInstallPkg, name, version, nil
}
// LoadMetadata loads the chaincode metadata stored at the specified path
func (s *Store) LoadMetadata(path string) (name, version string, err error) {
metadataBytes, err := s.ReadWriter.ReadFile(path)
if err != nil {
err = errors.Wrapf(err, "error reading metadata at %s", path)
return "", "", err
}
ccMetadata := &ChaincodeMetadata{}
err = json.Unmarshal(metadataBytes, ccMetadata)
if err != nil {
err = errors.Wrapf(err, "error unmarshaling metadata at %s", path)
return "", "", err
}
return ccMetadata.Name, ccMetadata.Version, nil
}
// CodePackageNotFoundErr is the error returned when a code package cannot
// be found in the persistence store
type CodePackageNotFoundErr struct {
Name string
Version string
}
func (e *CodePackageNotFoundErr) Error() string {
return fmt.Sprintf("chaincode install package not found with name '%s', version '%s'", e.Name, e.Version)
}
// RetrieveHash retrieves the hash of a chaincode install package given the
// name and version of the chaincode
func (s *Store) RetrieveHash(name string, version string) ([]byte, error) {
installedChaincodes, err := s.ListInstalledChaincodes()
if err != nil {
return nil, errors.WithMessage(err, "error getting installed chaincodes")
}
for _, installedChaincode := range installedChaincodes {
if installedChaincode.Name == name && installedChaincode.Version == version {
return installedChaincode.Id, nil
}
}
err = &CodePackageNotFoundErr{
Name: name,
Version: version,
}
return nil, err
}
// ListInstalledChaincodes returns an array with information about the
// chaincodes installed in the persistence store
func (s *Store) ListInstalledChaincodes() ([]chaincode.InstalledChaincode, error) {
files, err := s.ReadWriter.ReadDir(s.Path)
if err != nil {
return nil, errors.Wrapf(err, "error reading chaincode directory at %s", s.Path)
}
installedChaincodes := []chaincode.InstalledChaincode{}
for _, file := range files {
if strings.HasSuffix(file.Name(), ".json") {
metadataPath := filepath.Join(s.Path, file.Name())
ccName, ccVersion, err := s.LoadMetadata(metadataPath)
if err != nil {
logger.Warning(err.Error())
continue
}
// split the file name and get just the hash
hashString := strings.Split(file.Name(), ".")[0]
hash, err := hex.DecodeString(hashString)
if err != nil {
return nil, errors.Wrapf(err, "error decoding hash from hex string: %s", hashString)
}
installedChaincode := chaincode.InstalledChaincode{
Name: ccName,
Version: ccVersion,
Id: hash,
}
installedChaincodes = append(installedChaincodes, installedChaincode)
}
}
return installedChaincodes, nil
}
// GetChaincodeInstallPath returns the path where chaincodes
// are installed
func (s *Store) GetChaincodeInstallPath() string {
return s.Path
}
// ChaincodeMetadata holds the name and version of a chaincode
type ChaincodeMetadata struct {
Name string `json:"Name"`
Version string `json:"Version"`
}
func toJSON(name, version string) ([]byte, error) {
metadata := &ChaincodeMetadata{
Name: name,
Version: version,
}
metadataBytes, err := json.Marshal(metadata)
if err != nil {
return nil, errors.Wrap(err, "error marshaling name and version into JSON")
}
return metadataBytes, nil
}
马建仓 AI 助手
尝试更多
代码解读
代码找茬
代码优化
1
https://gitee.com/liurenhao/fabric.git
git@gitee.com:liurenhao/fabric.git
liurenhao
fabric
fabric
v1.4.9

搜索帮助